func TestWriteSuccessMessage(t *testing.T) { h := testhelper.New(t) tests := []struct { ecode int ebody string }{ // Test A success message. The rest are tested above. { ecode: http.StatusOK, ebody: `{"Type":"success","Message":"Success."}`, }, } // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/", nil) h.FatalNotNil("creating request", err) // Call the test function WriteSuccessMessage(c, w, r) // Check the values. h.ErrorNotEqual("response code", w.Code, test.ecode) h.ErrorNotEqual("response body", w.Body.String(), test.ebody) } }
func TestUnmarshalOrFail(t *testing.T) { h := testhelper.New(t) tests := []struct { result bool ecode int ebody string bytes []byte where interface{} }{ // Test a good unmarshal. { result: true, ecode: 0, ebody: "", bytes: []byte(`{"C":123}`), where: &struct{ C int64 }{}, }, // Test a bad unmarshal. { result: false, ecode: http.StatusBadRequest, ebody: `{"Type":"error","Message":"Failed."}`, bytes: []byte(`{"C":12`), where: &struct{ C int64 }{}, }, } // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/", nil) h.FatalNotNil("creating request", err) // Call the test function results := UnmarshalOrFail(c, w, r, test.bytes, test.where) h.SetFunc("UnmarshalOrFail(c, w, r, test.bytes, test.where)") h.FatalNotEqual("umarshal results", results, test.result) // We don't get anything back on the wire if it succeeded. if test.result == true { continue } // Check the values. h.ErrorNotEqual("response code", w.Code, test.ecode) h.ErrorNotEqual("response body", w.Body.String(), test.ebody) } }
func TestWriteJSON(t *testing.T) { h := testhelper.New(t) tests := []struct { data interface{} code int response string }{ // Test the error case. { data: struct { C complex128 }{ C: complex(1, 1), }, code: http.StatusInternalServerError, response: `{"Type":"error","Message":"Something unexpected happened."}`, }, // Test a normal case. { data: struct { C int64 }{ C: 123, }, code: http.StatusOK, response: `{"C":123}`, }, } // We can use the same context for all tests. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/", nil) h.FatalNotNil("creating request", err) WriteJSON(c, w, r, test.data) // Check the values. h.ErrorNotEqual("response code", w.Code, test.code) h.ErrorNotEqual("response body", w.Body.String(), test.response) } }
func TestLogAndMessage(t *testing.T) { h := testhelper.New(t) tests := []struct { method string url string err error ecode int ebody string mtype string msg string }{ // Test A success message. The rest are tested above. { method: "GET", url: "/", err: nil, ecode: http.StatusOK, ebody: `{"Type":"success","Message":"Success."}`, mtype: "success", msg: "Success.", }, } // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest(test.method, test.url, nil) h.FatalNotNil("creating request", err) h.SetFunc(`LogAndMessage(c, w, r, err("%v"), "%s, "%s", %d)`, test.err, test.mtype, test.msg, test.ecode) // Call the test function LogAndMessage(c, w, r, test.err, test.mtype, test.msg, test.ecode) // Check the values. h.ErrorNotEqual("response code", w.Code, test.ecode) h.ErrorNotEqual("response body", w.Body.String(), test.ebody) } }
func TestNewKey(t *testing.T) { h := testhelper.New(t) // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating contxt", err) defer c.Close() // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/newkey", nil) h.FatalNotNil("creating request", err) skey, key, ok := NewKey(c, w, r, "Item", nil) h.ErrorNotEqual("new key", ok, true) h.ErrorNotEqual("keys", skey, key.Encode()) }
func TestGetUserLogoutURL(t *testing.T) { h := testhelper.New(t) c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/", nil) h.FatalNotNil("creating request", err) url, ok := GetUserLogoutURL(c, w, r, "/") h.FatalNotEqual("getting url", ok, true) surl := "/_ah/login?continue=http%3A//127.0.0.1%3A" eurl := "/&action=Logout" if !strings.HasPrefix(url, surl) || !strings.HasSuffix(url, eurl) { t.Errorf("Expecting '%v' for url, but got: %v", surl+"[PORT]"+eurl, url) } }
func TestDeleteStringKeyAndAncestors(t *testing.T) { // This also tests DeleteKeys. h := testhelper.New(t) // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating contxt", err) defer c.Close() // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/datastore", nil) h.FatalNotNil("creating request", err) // Make the parent parent := makeKey(c, nil) ok := PutStringKeys(c, w, r, []string{parent.Encode()}, []stringer{stringer{"parent"}}) h.FatalNotEqual("put parent", ok, true) // Make the child child := makeKey(c, parent) ok = PutStringKeys(c, w, r, []string{child.Encode()}, []stringer{stringer{"child"}}) h.FatalNotEqual("put child", ok, true) // Call the delete ok = DeleteStringKeyAndAncestors(c, w, r, "Item", parent.Encode()) h.FatalNotEqual("delete ancestors", ok, true) // Check the parent var value stringer err = datastore.Get(c, parent, &value) h.ErrorNil("deleted parent", err) // Check the child err = datastore.Get(c, child, &value) h.ErrorNil("deleted child", err) }
func TestGetUserOrUnexpected(t *testing.T) { h := testhelper.New(t) // We are going to reuse the context here. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() tests := []struct { f func() success bool email string admin bool ecode int ebody string }{ // Test login for an admin user. { f: func() { c.Login("*****@*****.**", true) }, success: true, email: "*****@*****.**", admin: true, ecode: 0, ebody: "", }, // Test login for a non admin user. { f: func() { c.Logout() c.Login("*****@*****.**", false) }, success: true, email: "*****@*****.**", admin: false, ecode: 0, ebody: "", }, // Test being logged out. { f: func() { c.Logout() }, success: false, email: "", admin: false, ecode: http.StatusInternalServerError, ebody: `{"Type":"error","Message":"Something unexpected happened."}`, }, } for i, test := range tests { h.SetIndex(i) // Prep the test. test.f() // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/", nil) h.FatalNotNil("creating request", err) // Call the normal function u, ok := GetUserOrUnexpected(c, w, r) h.FatalNotEqual("success", ok, test.success) if test.success { // Check the user credentials h.ErrorNotEqual("email", u.Email, test.email) h.ErrorNotEqual("admin", u.Admin, test.admin) } else { // Check the values. h.ErrorNotEqual("response code", w.Code, test.ecode) h.ErrorNotEqual("response body", w.Body.String(), test.ebody) } } }
func TestLogAnds(t *testing.T) { h := testhelper.New(t) // These are our test cases. tests := []struct { f LogAndFunc fn string method string url string err error ecode int ebody string }{ // LogAndNotFound { f: LogAndNotFound, fn: "LogAndNotFound", method: "GET", url: "/", err: fmt.Errorf("no such file or directory"), ecode: http.StatusNotFound, ebody: `{"Type":"error","Message":"Not found."}`, }, // LogAndFailed { f: LogAndFailed, fn: "LogAndFailed", method: "GET", url: "/", err: fmt.Errorf("oopsie, you failed"), ecode: http.StatusBadRequest, ebody: `{"Type":"error","Message":"Failed."}`, }, // LogAndUnexpected { f: LogAndUnexpected, fn: "LogAndUnexpected", method: "GET", url: "/", err: fmt.Errorf("oopsie, i failed"), ecode: http.StatusInternalServerError, ebody: `{"Type":"error","Message":"Something unexpected happened."}`, }, } // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating contxt", err) defer c.Close() for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest(test.method, test.url, nil) h.FatalNotNil("creating request", err) h.SetFunc(`%s(c, w, r, err("%v"))`, test.fn, test.err) // Call the test function test.f(c, w, r, test.err) // Check the values. h.ErrorNotEqual("response code", w.Code, test.ecode) h.ErrorNotEqual("response body", w.Body.String(), test.ebody) } }
func TestUnmarshalFromBodyOrFail(t *testing.T) { h := testhelper.New(t) tests := []struct { body string result bool ecode int ebody string request *http.Request where interface{} }{ // Test a nil body. { result: false, ecode: http.StatusBadRequest, ebody: `{"Type":"error","Message":"Failed."}`, request: newRequest("GET", "/", nil), where: nil, }, // Test a body that will fail reading. { result: false, ecode: http.StatusInternalServerError, ebody: `{"Type":"error","Message":"Something unexpected happened."}`, request: newRequest("GET", "/", ErrorReader{}), where: nil, }, // Test a normal body. { result: true, ecode: 0, ebody: "", request: newRequest("GET", "/", strings.NewReader(`{"C":123}`)), where: &struct{ C int64 }{}, }, // Test a JSON decoding error. { result: false, ecode: http.StatusBadRequest, ebody: `{"Type":"error","Message":"Failed."}`, request: newRequest("GET", "/", strings.NewReader(`{"C":12`)), where: &struct{ C int64 }{}, }, } // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating context", err) defer c.Close() for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() // Call the test function results := UnmarshalFromBodyOrFail(c, w, test.request, test.where) h.SetFunc("UnmarshalFromBodyOrFail(c, w, test.request, test.where)") h.FatalNotEqual("umarshal results", results, test.result) // If we failed, we should test the wire. if test.result == false { // Check the values. h.ErrorNotEqual("response code", w.Code, test.ecode) h.ErrorNotEqual("response body", w.Body.String(), test.ebody) } } }
func TestPutStringKeys(t *testing.T) { // This also tests PutKeys. h := testhelper.New(t) // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating contxt", err) defer c.Close() // These are the tests tests := []struct { keys []string values []stringer expect bool }{ // An empty list. { keys: []string{}, values: []stringer{}, expect: true, }, // A normal list. { keys: []string{makeKey(c, nil).Encode(), makeKey(c, nil).Encode()}, values: []stringer{stringer{"one"}, stringer{"two"}}, expect: true, }, // More keys than values. { keys: []string{makeKey(c, nil).Encode(), makeKey(c, nil).Encode()}, values: []stringer{stringer{"one"}}, expect: false, }, // More values than keys. { keys: []string{makeKey(c, nil).Encode(), makeKey(c, nil).Encode()}, values: []stringer{stringer{"one"}, stringer{"two"}, stringer{"three"}}, expect: false, }, // Invalid key. { keys: []string{makeKey(c, nil).Encode(), makeKey(c, nil).Encode(), "hahaha"}, values: []stringer{stringer{"one"}, stringer{"two"}, stringer{"three"}}, expect: false, }, } for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/datastore", nil) h.FatalNotNil("creating request", err) result := PutStringKeys(c, w, r, test.keys, test.values) h.FatalNotEqual("put keys", result, test.expect) if test.expect == false { // Test the output. h.ErrorNotEqual("response code", w.Code, http.StatusInternalServerError) h.ErrorNotEqual("response body", w.Body.String(), `{"Type":"error","Message":"Something unexpected happened."}`) } else { for _, key := range test.keys { // Make sure each of the keys persisted. var value stringer k, err := datastore.DecodeKey(key) h.FatalNotNil("decoding key", err) err = datastore.Get(c, k, &value) h.FatalNotNil("datastore get", err) // High replication seems to make this impossible. // h.ErrorNotEqual("datastore value", test.values[j].s, value.s) } } } }
func TestDeleteStringKeys(t *testing.T) { // This also tests DeleteKeys. h := testhelper.New(t) // We are going to reuse the context. c, err := appenginetesting.NewContext(nil) h.FatalNotNil("creating contxt", err) defer c.Close() // These are the tests tests := []struct { keys []string values []stringer inserts []bool deletes []bool expects []bool }{ // A normal list. { keys: []string{ makeKey(c, nil).Encode(), makeKey(c, nil).Encode(), makeKey(c, nil).Encode(), makeKey(c, nil).Encode(), makeKey(c, nil).Encode(), makeKey(c, nil).Encode(), }, values: []stringer{ stringer{"one"}, stringer{"two"}, stringer{"three"}, stringer{"four"}, stringer{"five"}, stringer{"six"}, }, deletes: []bool{false, false, true, false, true, false}, }, } for i, test := range tests { h.SetIndex(i) // Make the request and writer. w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/datastore", nil) h.FatalNotNil("creating request", err) // insert the items. ok := PutStringKeys(c, w, r, test.keys, test.values) h.FatalNotEqual("put keys", ok, true) // make the items to delete dkeys := make([]string, 0, 0) for j, key := range test.keys { if test.deletes[j] { dkeys = append(dkeys, key) } } h.SetFunc("DeleteStringKeys(c, w, r, %v)", dkeys) // delete the items ok = DeleteStringKeys(c, w, r, dkeys) // Check each of the items. for j, key := range test.keys { var value stringer k, err := datastore.DecodeKey(key) h.FatalNotNil("decoding key", err) err = datastore.Get(c, k, &value) if test.deletes[j] { h.ErrorNil("deleted item", err) } else { h.ErrorNotNil("deleted item", err) } } } }