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) } } }