package c_test
import (
"encoding/json"
"errors"
"html/template"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"git.sr.ht/~evanj/cms/internal/c"
mock_c "git.sr.ht/~evanj/cms/internal/c/mock"
userT "git.sr.ht/~evanj/cms/internal/m/user"
"github.com/bmizerany/assert"
"github.com/golang/mock/gomock"
"github.com/google/uuid"
)
var (
tmpl = template.Must(template.New("c_test").Parse("sup earth"))
)
type server struct{ *c.Controller }
func (s server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.HTML(w, r, tmpl, map[string]interface{}{})
}
func TestJSON(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
s = server{c.New(l, db, true, "test")}
ts = httptest.NewServer(s)
)
res, _ := http.Get(ts.URL)
assert.Equal(t, res.StatusCode, http.StatusOK)
assert.Equal(t, res.Header.Get("Content-Type"), "application/json")
}
func TestHTML(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
s = server{c.New(l, db, true, "test")}
ts = httptest.NewServer(s)
)
req, _ := http.NewRequest("GET", ts.URL, nil)
req.Header.Set("Accept", "text/html")
res, _ := http.DefaultClient.Do(req)
assert.Equal(t, res.StatusCode, http.StatusOK)
assert.Equal(t, res.Header.Get("Content-Type"), "text/html")
}
type server2 struct {
*c.Controller
it func(string)
}
func (s server2) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.it(s.Method(r))
w.WriteHeader(http.StatusOK)
}
func TestMethodHack(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
)
type spec struct {
method string
withInput bool
inputVal string
expect string
}
tests := []spec{
spec{"GET", false, "", "GET"},
spec{"POST", false, "", "POST"},
spec{"PUT", false, "", "PUT"},
spec{"PATCH", false, "", "PATCH"},
spec{"DELETE", false, "", "DELETE"},
spec{"POST", true, "GET", "GET"},
spec{"POST", true, "POST", "POST"},
spec{"POST", true, "PUT", "PUT"},
spec{"POST", true, "PATCH", "PATCH"},
spec{"POST", true, "DELETE", "DELETE"},
}
for _, test := range tests {
var (
s = server2{
c.New(l, db, true, "test"),
func(method string) {
assert.Equal(t, method, test.expect)
},
}
ts = httptest.NewServer(s)
)
form := url.Values{}
if test.withInput {
form.Add("method", test.inputVal)
}
req, _ := http.NewRequest(test.method, ts.URL,
strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
assert.Equal(t, res.StatusCode, http.StatusOK)
}
}
type server3 struct {
*c.Controller
to string
}
func (s server3) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.Redirect(w, r, s.to)
}
func TestRedirect(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
)
tests := []string{
"/space/2",
"/contenttype/2/3",
"/content/2/3/4/",
"/hook/2/3",
"/space?space=2",
"/contenttype?space=2&contenttype=3",
"/content?space=2&contenttype=3&content=4",
"/hook/?space=2&hook=3",
}
for _, test := range tests {
var (
s = server3{c.New(l, db, true, "test"), test}
ts = httptest.NewServer(s)
)
req, _ := http.NewRequest("GET", ts.URL+test, nil)
req.Header.Set("Accept", "text/html")
res, _ := http.DefaultClient.Do(req)
assert.Equal(t, res.StatusCode, http.StatusFound)
assert.Equal(t, test, res.Header.Get("Location"))
}
for _, test := range tests {
var (
s = server3{c.New(l, db, true, "test"), test}
ts = httptest.NewServer(s)
)
buf, _ := json.Marshal(test)
res, _ := http.Get(ts.URL + test)
bod, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, res.StatusCode, http.StatusOK)
assert.Equal(t, string(buf), string(bod))
}
}
type server4 struct {
*c.Controller
}
func (s server4) ServeHTTP(w http.ResponseWriter, r *http.Request) {
u, err := s.GetCookieUser(w, r)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
s.SetCookieUser(w, r, u)
w.WriteHeader(http.StatusOK)
}
func TestUserFromBasicAuth(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
s = server4{c.New(l, db, true, "test")}
ts = httptest.NewServer(s)
uname = uuid.New().String()
upass = uuid.New().String()
u = userT.NewMock(uname, upass)
)
db.EXPECT().UserGet(uname, upass).Return(u, nil).AnyTimes()
req, _ := http.NewRequest("GET", ts.URL, nil)
req.SetBasicAuth(uname, upass)
res, _ := http.DefaultClient.Do(req)
assert.Equal(t, res.StatusCode, http.StatusOK)
}
func TestUserFromFromCookie(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
s = server4{c.New(l, db, true, "test")}
ts = httptest.NewServer(s)
uname = uuid.New().String()
upass = uuid.New().String()
cookie = uuid.New().String()
u = userT.NewMock(uname, upass)
)
db.EXPECT().UserGetFromToken(cookie).Return(u, nil).AnyTimes()
req, _ := http.NewRequest("GET", ts.URL, nil)
req.AddCookie(&http.Cookie{
Name: string(c.KeyUserLogin),
Value: cookie,
MaxAge: 0,
Secure: false,
HttpOnly: false,
})
res, _ := http.DefaultClient.Do(req)
assert.Equal(t, res.StatusCode, http.StatusOK)
}
func TestUserFromFromCookieFail(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
s = server4{c.New(l, db, true, "test")}
ts = httptest.NewServer(s)
cookie = uuid.New().String()
)
db.EXPECT().UserGetFromToken(cookie).Return(nil, errors.New("no user")).AnyTimes()
req, _ := http.NewRequest("GET", ts.URL, nil)
res, _ := http.DefaultClient.Do(req)
assert.Equal(t, res.StatusCode, http.StatusInternalServerError)
}
type server5 struct {
*c.Controller
typ int
str string
}
func (s server5) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch s.typ {
case 0:
s.String(w, r, s.str)
break
case 1:
s.ErrorString(w, r, 500+s.typ, s.str)
break
case 2:
s.Error(w, r, 500+s.typ, errors.New(s.str))
break
case 3:
s.Error(w, r, 500+s.typ, errors.New(s.str))
break
}
}
func TestStrAndErr(t *testing.T) {
t.Parallel()
var (
ctrl = gomock.NewController(t)
db = mock_c.NewMockdber(ctrl)
l *log.Logger
)
type spec struct {
typ int
str string
}
tests := []spec{
spec{0, "sup earth"},
spec{1, "err1"},
spec{2, "err2"},
spec{3, "err3"},
}
for _, test := range tests {
var (
s = server5{c.New(l, db, true, "test"), test.typ, test.str}
ts = httptest.NewServer(s)
)
res, _ := http.Get(ts.URL)
if test.typ == 0 {
assert.Equal(t, res.StatusCode, http.StatusOK)
} else {
assert.Equal(t, res.StatusCode, 500+test.typ)
}
}
}