func TestLocationAgent(t *testing.T) { db := mem.NewDB() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatal(err) } changes := data.FilterKind(db.Changes(), models.ProfileKind) ctx, stop := context.WithCancel(context.Background()) go agents.LocationAgent(ctx, db, u) defer stop() // give control to agent thread time.Sleep(1 * time.Millisecond) _, loc, err := event.LocationUpdate(db, u, 50, 50, 50) if err != nil { t.Fatal(err) } select { case profileChange := <-*changes: p := profileChange.Record.(*models.Profile) if loc.Id != p.LocationId { t.Fatal("Expected profile's location id to now match be the new location ") } case <-time.After(100 * time.Millisecond): t.Fatal("Timed out waiting for profile update") } }
func BenchmarkRecordPostEvent(b *testing.B) { db := mem.NewDB() u, _, err := user.Create(db, "username", "password") if err != nil { b.Fatalf("user.Create error: %v", err) } ctx := user.NewContext(context.Background(), u) logger := services.NewTestLogger(b) for i := 0; i < b.N; i++ { rec := httptest.NewRecorder() req, err := http.NewRequest( "POST", "http://www.elos.pw/record/?"+url.Values{ "kind": []string{models.EventKind.String()}, }.Encode(), bytes.NewBuffer( []byte(`{ "name": "event name", "data": { "sensor1": 34, "sensor2": 4.3 }, "owner_id": "`+u.ID().String()+`" }`), )) if err != nil { b.Fatalf("http.NewRequest error: %v", err) } routes.RecordPOST(ctx, rec, req, logger, db) } }
func TestWebSensorsAgent(t *testing.T) { db := mem.NewDB() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatal(err) } changes := data.FilterKind(db.Changes(), models.EventKind) ctx, stop := context.WithCancel(context.Background()) go agents.WebSensorsAgent(ctx, db, u) defer stop() // give control to agent thread time.Sleep(1 * time.Millisecond) _, err = event.WebSensorLocation(db, u, 50, 50) if err != nil { t.Fatal(err) } // read off the event we just created <-*changes select { case eventChange := <-*changes: e := eventChange.Record.(*models.Event) if e.Name != "Location Update" { t.Fatal("Expected a location update to be produced") } case <-time.After(100 * time.Millisecond): t.Fatal("Timed out waiting for event creation") } }
func TestRecordsQueryTemplate(t *testing.T) { db := mem.NewDB() creds := make([]map[string]interface{}, 5) for i := 0; i < 5; i++ { _, c, err := user.Create(db, "username", "password") if err != nil { t.Fatal("user.Create error: %s", err) } m := make(map[string]interface{}) transfer.TransferAttrs(c, &m) creds[i] = m } s := &records.QueryData{ Model: models.Metis[models.CredentialKind], Records: creds, } var b bytes.Buffer if err := records.QueryTemplate.Execute(&b, s); err != nil { t.Fatalf("template.Execute error: %s", err) } o := b.String() t.Logf("TemplateOutput:\n%s", o) if got, want := strings.Contains(o, "username"), true; got != want { t.Errorf("strings.Contains(\"username\"): got %t, want %t", got, want) } if got, want := strings.Contains(o, "password"), true; got != want { t.Errorf("strings.Contains(\"password\"): got %t, want %t", got, want) } }
func testUser(t *testing.T, db data.DB) (*models.User, *models.Credential) { u, c, err := user.Create(db, "public", "private") if err != nil { t.Fatal(err) } return u, c }
func TestEditGET(t *testing.T) { db := mem.NewDB() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create error: %v", err) } e := &models.Event{ Id: db.NewID().String(), OwnerId: u.Id, Name: "old name", Data: map[string]interface{}{ "sensor": 4, }, } if err := db.Save(e); err != nil { t.Fatalf("db.Save error: %v", err) } s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { records.EditGET(user.NewContext(context.Background(), u), w, r, db, services.NewTestLogger(t)) })) p := s.URL + "?" + url.Values{ "kind": []string{"event"}, "id": []string{e.Id}, }.Encode() resp, err := http.Get(p) if err != nil { t.Fatalf("http.Get(%q) error: %v", p, err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("ioutil.ReadAll error: %v", err) } t.Logf("resp.Body:\n%s", body) if got, want := bytes.Contains(body, []byte(`event`)), true; got != want { t.Fatalf("bytes.Contains(body, %q): got %t, want %t", "event", got, want) } if got, want := bytes.Contains(body, []byte(`old name`)), true; got != want { t.Fatalf("bytes.Contains(body, %q): got %t, want %t", "old name", got, want) } if got, want := bytes.Contains(body, []byte(`/records/view/?kind=event&id=3`)), true; got != want { t.Fatalf("bytes.Contains(body, %q): got %t, want %t", `/records/view/?kind=event&id=3`, got, want) } }
func TestRecordsNewGET(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := Authenticate(ctx, w, r, logger, db) if !ok { t.Fatal("authentication failed") } Records.NewGET(ctx, w, r, db, logger) })) defer s.Close() _, _, err := user.Create(db, "username", "password") if err != nil { t.Fatal(err) } c := new(http.Client) req, err := http.NewRequest("GET", s.URL, nil) if err != nil { t.Fatal(err) } req.SetBasicAuth("username", "password") resp, err := c.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } t.Logf("Body:\n%s", body) doc := string(body) contains := map[string]bool{ "user": false, "event": true, "New": true, } for c, want := range contains { if got := strings.Contains(doc, c); got != want { t.Fatalf("strings.Contains(%q): got %t, want %t", c, got, want) } } }
func TestDeletePOST(t *testing.T) { db := mem.NewDB() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create error: %v", err) } e := &models.Event{ Id: db.NewID().String(), OwnerId: u.Id, Name: "event name", Data: map[string]interface{}{ "sensor": 45.3, }, } if err := db.Save(e); err != nil { t.Fatalf("db.Save error: %v", err) } s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.Contains(r.RequestURI, "/records/delete/") { records.DeletePOST(user.NewContext(context.Background(), u), w, r, db, services.NewTestLogger(t)) } records.QueryGET(user.NewContext(context.Background(), u), w, r, db, services.NewTestLogger(t)) })) p := s.URL + "/records/delete/?" + url.Values{ "kind": []string{"event"}, "id": []string{e.Id}, }.Encode() resp, err := http.Post(p, "", new(bytes.Buffer)) if err != nil { t.Fatalf("http.Post error: %v", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("ioutil.ReadAll error: %v", err) } t.Logf("resp.Body:\n%s", body) if got, want := db.PopulateByID(e), data.ErrNotFound; got != want { t.Fatalf("db.PopulateByID: got %v, want %v", got, want) } }
func TestRecordsQueryGET(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := Authenticate(ctx, w, r, logger, db) if !ok { t.Fatal("authentication failed") } Records.QueryGET(ctx, w, r, db, logger) })) defer s.Close() _, _, err := user.Create(db, "username", "password") if err != nil { t.Fatal(err) } c := new(http.Client) req, err := http.NewRequest("GET", s.URL+"?"+url.Values{ "query/Kind": []string{"credential"}, }.Encode(), nil) if err != nil { t.Fatal(err) } req.SetBasicAuth("username", "password") resp, err := c.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } t.Logf("Body:\n%s", body) doc := string(body) if got, want := strings.Contains(doc, "username"), true; got != want { t.Fatalf("strings.Contains(doc, \"username\"): got %t, want %t", got, want) } if got, want := strings.Contains(doc, "password"), true; got != want { t.Fatalf("strings.Contains(doc, \"password\"): got %t, want %t", got, want) } }
func TestMarshalTask(t *testing.T) { t.Skip() db := mem.NewDB() user, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create error: %v", err) } bytes, err := form.Marshal(user, "user") if err != nil { t.Fatalf("form.Marshal error: %v", err) } if got, want := string(bytes), ""; got != want { t.Fatalf("form.Marshal: got\n%s\nwant,\n%s", got, want) } }
func TestAuthenticateQueryParams(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) var userContext context.Context var authed bool s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { userContext, authed = routes.Authenticate(ctx, w, r, logger, db) if authed { w.WriteHeader(http.StatusOK) } })) defer s.Close() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create(db, \"username\", \"password\") error: %s", err) } client := new(http.Client) req, err := http.NewRequest("GET", s.URL, new(bytes.Buffer)) if err != nil { t.Fatalf("http.NewRequest error: %s", err) } client.Do(req) if got, want := authed, false; got != want { t.Fatalf("authed: got %t, want %t", got, want) } req, err = http.NewRequest("GET", s.URL+"?public=username&private=password", new(bytes.Buffer)) if err != nil { t.Fatalf("http.NewRequest error: %s", err) } client.Do(req) if got, want := authed, true; got != want { t.Fatalf("authed: got %t, want %t") } authedU, ok := user.FromContext(userContext) if got, want := ok, true; got != want { t.Fatalf("_, ok := user.FromContext: got %t, want %t") } if got, want := data.Equivalent(authedU, u), true; got != want { t.Errorf("data.Equivalent(authedU, u): got %t, want %t", got, want) } }
func TestAuthenticatePostForm(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) var userContext context.Context var authed bool s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { userContext, authed = routes.Authenticate(ctx, w, r, logger, db) if authed { w.WriteHeader(http.StatusOK) } })) defer s.Close() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create(db, \"username\", \"password\") error: %s", err) } client := new(http.Client) client.PostForm(s.URL, url.Values{ "public": []string{"username"}, "private": []string{"password"}, }) if got, want := authed, true; got != want { t.Fatalf("authed: got %t, want %t", got, want) } authedU, ok := user.FromContext(userContext) if got, want := ok, true; got != want { t.Fatalf("_, ok := user.FromContext: got %t, want %t", got, want) } if got, want := data.Equivalent(authedU, u), true; got != want { t.Fatal("data.Equivalent(authedU, u): got %t ,want %t", got, want) } }
func TestEditPOST(t *testing.T) { db := mem.NewDB() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create error: %v", err) } e := &models.Event{ Id: db.NewID().String(), OwnerId: u.Id, Name: "old name", Data: map[string]interface{}{ "sensor": 4, }, Time: time.Now(), } if err := db.Save(e); err != nil { t.Fatalf("db.Save error: %v", err) } s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.Contains(r.RequestURI, "/records/edit/") { records.EditPOST(user.NewContext(context.Background(), u), w, r, db, services.NewTestLogger(t)) return } w.WriteHeader(http.StatusOK) w.Write([]byte(`default test handler`)) })) p := s.URL + "/records/edit/?" + url.Values{ "kind": []string{"event"}, "id": []string{e.Id}, "event/Name": []string{"new eman"}, "event/Data": []string{`{"sensor": 4, "sensor2": 9}`}, }.Encode() resp, err := http.Post(p, "", new(bytes.Buffer)) if err != nil { t.Fatalf("http.Post error: %v", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("iotuil.ReadAll error: %v", err) } t.Logf("resp.Body:\n%s", body) ue := &models.Event{Id: e.Id} if err := db.PopulateByID(ue); err != nil { t.Fatalf("db.PopulateByID error: %v", err) } if got, want := ue.Name, "new eman"; got != want { t.Errorf("ue.Name: got %q, want %q", got, want) } if got, want := ue.Data, map[string]interface{}{"sensor": 4.0, "sensor2": 9.0}; !reflect.DeepEqual(got, want) { t.Errorf("ue.Data: got %v, want %v", got, want) } if got, want := ue.Time, e.Time; got != want { t.Errorf("ue.Time: got %v, want %v", got, want) } if got, want := ue.OwnerId, e.OwnerId; got != want { t.Errorf("ue.OwnerId: got %q, want %q", got, want) } }
func main() { flag.Parse() var db data.DB var err error log.Printf("== Setting Up Database ==") log.Printf("\tDatabase Type: %s", *dbtype) switch *dbtype { case "mem": db = mem.NewDB() case "mongo": db, err = models.MongoDB(*dbaddr) if err != nil { log.Fatal(err) } log.Printf("\tConnected to mongo@%s", *dbaddr) default: log.Fatal("Unrecognized database type: '%s'", *dbtype) } log.Printf("== Set up Database ==") // DB CLIENT conn, err := grpc.Dial(":3334", grpc.WithInsecure()) if err != nil { log.Fatalf("failed to dial: %v", err) } defer conn.Close() adbc := access.NewDBClient(conn) // AUTH CLIENT conn, err = grpc.Dial(":3333", grpc.WithInsecure()) if err != nil { log.Fatalf("failed to dial: %v", err) } defer conn.Close() ac := auth.NewAuthClient(conn) // WEBUI SERVER lis, err := net.Listen("tcp", ":1113") if err != nil { log.Fatalf("failed to listen on :1113: %v", err) } g := grpc.NewServer() records.RegisterWebUIServer(g, records.Logged(records.NewWebUI(adbc, ac))) go g.Serve(lis) // WEB UI CLIENT conn, err = grpc.Dial(":1113", grpc.WithInsecure()) if err != nil { log.Fatalf("failed to dial: %v", err) } defer conn.Close() webuiclient := records.NewWebUIClient(conn) // calendar WEBUI SERVER lis, err = net.Listen("tcp", ":1114") if err != nil { log.Fatalf("failed to listen on :1114: %v", err) } g = grpc.NewServer() cal.RegisterWebUIServer(g, cal.NewWebUI(adbc, ac)) go g.Serve(lis) // cal WEB UI CLIENT conn, err = grpc.Dial(":1114", grpc.WithInsecure()) if err != nil { log.Fatalf("failed to dial: %v", err) } defer conn.Close() calwebui := cal.NewWebUIClient(conn) if _, _, err := user.Create(db, "u", "p"); err != nil { log.Fatal("user.Create error: %s", err) } background := context.Background() log.Printf("== Connecting to Twilio ==") twilioClient := twilio.NewClient(TwilioAccountSid, TwilioAuthToken, nil) log.Printf("== Connected to Twilio ==") log.Printf("== Starting SMS Command Sessions ==") smsMux := services.NewSMSMux() go smsMux.Start( background, db, services.SMSFromTwilio(twilioClient, TwilioFromNumber), ) log.Printf("== Started SMS Command Sessions ==") log.Printf("== Initiliazing Gaia Core ==") ga := gaia.New( context.Background(), new(gaia.Middleware), &gaia.Services{ AppFileSystem: http.Dir(*appdir), SMSCommandSessions: smsMux, DB: db, Logger: services.NewLogger(os.Stderr), WebUIClient: webuiclient, CalWebUIClient: calwebui, }, ) log.Printf("== Initiliazed Gaia Core ==") log.Printf("== Starting Agents ===") user.Map(db, func(db data.DB, u *models.User) error { go agents.LocationAgent(background, db, u) go agents.TaskAgent(background, db, u) go agents.WebSensorsAgent(background, db, u) return nil }) log.Printf("== Started Agents ===") log.Printf("== Starting HTTP Server ==") host := fmt.Sprintf("%s:%d", *addr, *port) log.Printf("\tServing on %s", host) if *certFile != "" && *keyFile != "" { if *port != 443 { log.Print("WARNING: serving HTTPS on a port that isn't 443") } if err = http.ListenAndServeTLS(host, *certFile, *keyFile, ga); err != nil { log.Fatal(err) } } else { log.Print("NOT SERVING SECURELY") if *port != 80 { log.Print("WARNING: serving HTTP on a port that isn't 80") } if err = http.ListenAndServe(host, ga); err != nil { log.Fatal(err) } } log.Printf("== Started HTTP Server ==") }
func TestLoginPOST(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) m := http.NewServeMux() m.Handle("/login/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := routes.Authenticate(ctx, w, r, logger, db) if !ok { t.Fatal("bad authentication") } routes.LoginPOST(ctx, w, r, db, logger) })) m.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusAccepted) })) s := httptest.NewServer(http.HandlerFunc(m.ServeHTTP)) defer s.Close() _, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create(db, \"username\", \"password\") error: %s", err) } req, err := http.NewRequest("GET", s.URL+"/login/", new(bytes.Buffer)) if err != nil { t.Fatalf("http.NewRequest error: %s", err) } req.SetBasicAuth("username", "password") jar, err := cookiejar.New(new(cookiejar.Options)) if err != nil { t.Fatalf("cookiejar.New error: %s", err) } client := &http.Client{ Jar: jar, } resp, err := client.Do(req) if err != nil { t.Fatalf("error posting to LoginPOST: %s", err) } t.Logf("Response:\n\t%v", resp) if got, want := resp.StatusCode, http.StatusAccepted; got != want { t.Errorf("resp.StatusCode: got %d, want %d", got, want) } iter, err := db.Query(models.SessionKind).Execute() if err != nil { t.Fatalf("db.Query(models.SessionKind).Execute(): %s", err) } seshes := mem.Slice(iter, func() data.Record { return new(models.Session) }) if got, want := len(seshes), 1; got != want { t.Fatalf("len(seshes): got %d, want %d", got, want) } uri, err := url.Parse(s.URL) if err != nil { t.Fatalf("url.Prase(s.URL) error: %s", err) } t.Logf("URL: %s", uri) cookies := jar.Cookies(uri) if got, want := len(cookies), 1; got != want { t.Fatalf("len(cookies): got %d, want %d", got, want) } if got, want := cookies[0].Value, seshes[0].(*models.Session).Token; got != want { t.Errorf("cookies[0].Value: got %s, want %s", got, want) } }
// --- TestAuthenticateSession {{{ func TestAuthenticateSession(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) var userContext context.Context var authed bool s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { userContext, authed = routes.Authenticate(ctx, w, r, logger, db) if authed { w.WriteHeader(http.StatusOK) } })) defer s.Close() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create(db, \"username\", \"password\") error: %s", err) } client := new(http.Client) req, err := http.NewRequest("GET", s.URL, new(bytes.Buffer)) if err != nil { t.Fatalf("http.NewRequest error: %s", err) } req.AddCookie(&http.Cookie{ Name: "elos-session-token", Value: "garbage", }) client.Do(req) if got, want := authed, false; got != want { t.Errorf("authed: got %t, want %t", got, want) } sesh := models.NewSessionForUser(u) sesh.SetID(db.NewID()) if err := db.Save(sesh); err != nil { t.Fatalf("db.Save(sesh) error: %s", err) } req, err = http.NewRequest("GET", s.URL, new(bytes.Buffer)) if err != nil { t.Fatalf("http.NewRequest error: %s", err) } req.AddCookie(&http.Cookie{ Name: "elos-session-token", Value: sesh.Token, }) client.Do(req) if got, want := authed, true; got != want { t.Fatalf("authed: got %t, want %t", got, want) } authedU, ok := user.FromContext(userContext) if got, want := ok, true; got != want { t.Fatalf("_, ok := user.FromContext: got %t, want %t", got, want) } if got, want := data.Equivalent(authedU, u), true; got != want { t.Errorf("data.Equivalent(authedU, u): got %t, want %t", got, want) } }
func TestRecordsEditGET(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := Authenticate(ctx, w, r, logger, db) if !ok { t.Fatal("authentication failed") } Records.EditGET(ctx, w, r, db, logger) })) defer s.Close() u, _, err := user.Create(db, "username", "password") if err != nil { t.Fatal(err) } e := new(models.Event) e.SetID(db.NewID()) e.SetOwner(u) e.Name = "eventname" if err := db.Save(e); err != nil { t.Fatal("db.Save(e) error: %s", err) } c := new(http.Client) req, err := http.NewRequest("GET", s.URL+"?"+url.Values{ "kind": []string{string(models.EventKind)}, "id": []string{e.Id}, }.Encode(), nil) if err != nil { t.Fatal(err) } req.SetBasicAuth("username", "password") resp, err := c.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } t.Logf("Body:\n%s", body) doc := string(body) contains := map[string]bool{ "eventname": true, "name": true, } for c, want := range contains { if got := strings.Contains(doc, c); got != want { t.Fatalf("strings.Contains(%q): got %t, want %t", c, got, want) } } }
// TestEventPOST tests a POST request to the '/event/' endpoint. // in the happy case (i.e., all parameters present). // We verify: // * The event's name // * The event's data // * The event's tags func TestEventPOST(t *testing.T) { ctx := context.Background() db := mem.NewDB() logger := services.NewTestLogger(t) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, ok := routes.Authenticate(ctx, w, r, logger, db) if !ok { t.Error("routes.Authenticate failed") } routes.EventPOST(ctx, w, r, db, logger) })) defer s.Close() _, _, err := user.Create(db, "username", "password") if err != nil { t.Fatalf("user.Create(db, \"username\", \"password\") error: %s", err) } u := s.URL + "?" + url.Values{ "tags": []string{"tag1", "tag2"}, }.Encode() body := map[string]interface{}{ "name": "event name", "time": time.Now(), "data": map[string]interface{}{ "arbitrary": []string{"data"}, "here": 1.0, "foo": map[string]interface{}{ "bar": "there", }, }, } b, err := json.Marshal(body) if err != nil { t.Fatal("json.Marshal(body) error: %s", err) } req, err := http.NewRequest("POST", u, bytes.NewBuffer(b)) req.SetBasicAuth("username", "password") client := new(http.Client) resp, err := client.Do(req) if err != nil { t.Fatalf("client.Do(req) error: %s", err) } defer resp.Body.Close() if got, want := resp.StatusCode, http.StatusCreated; got != want { t.Fatalf("resp.StatusCode: got %d, want %d", got, want) } b, err = ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("ioutil.ReadAll(resp.Body) error: %s", err) } e := new(models.Event) if err := json.Unmarshal(b, e); err != nil { t.Fatalf("json.Unmarshal(b, e) error: %s", err) } t.Logf("Event:\n\t%v", e) if got, want := e.Name, "event name"; got != want { t.Errorf("e.Name: got %q, want %q", got, want) } if got, want := e.Data["foo"].(map[string]interface{})["bar"], "there"; got != want { t.Errorf("e.Data[\"foo\"][\"bar\"]: got %q, want %q", got, want) } if got, want := len(e.TagsIds), 2; got != want { t.Fatalf("len(e.TagsIds): got %d, want %d", got, want) } tags, err := e.Tags(db) if err != nil { t.Fatalf("e.Tags(db) error: %s", err) } if got, want := len(tags), 2; got != want { t.Fatalf("len(tags): got %d, want %d", got, want) } if got, want := tags[0].Name, "tag1"; got != want { t.Errorf("tags[0].Name: got %q, want %q", got, want) } if got, want := tags[1].Name, "tag2"; got != want { t.Errorf("tags[1].Name: got %q, want %q", got, want) } }