diff --git a/api/genera.go b/api/genera.go new file mode 100644 index 0000000..e34196a --- /dev/null +++ b/api/genera.go @@ -0,0 +1,94 @@ +package api + +import ( + "encoding/json" + "strconv" + + "github.com/gorilla/mux" + + "net/http" + + "github.com/thermokarst/bactdb/models" +) + +func serveGenus(w http.ResponseWriter, r *http.Request) error { + id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0) + if err != nil { + return err + } + + genus, err := store.Genera.Get(id) + if err != nil { + return err + } + + return writeJSON(w, genus) +} + +func serveCreateGenus(w http.ResponseWriter, r *http.Request) error { + var genus models.Genus + err := json.NewDecoder(r.Body).Decode(&genus) + if err != nil { + return err + } + + created, err := store.Genera.Create(&genus) + if err != nil { + return err + } + if created { + w.WriteHeader(http.StatusCreated) + } + + return writeJSON(w, genus) +} + +func serveGenera(w http.ResponseWriter, r *http.Request) error { + var opt models.GenusListOptions + if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil { + return err + } + + genera, err := store.Genera.List(&opt) + if err != nil { + return err + } + if genera == nil { + genera = []*models.Genus{} + } + + return writeJSON(w, genera) +} + +func serveUpdateGenus(w http.ResponseWriter, r *http.Request) error { + id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0) + var genus models.Genus + err := json.NewDecoder(r.Body).Decode(&genus) + if err != nil { + return err + } + + updated, err := store.Genera.Update(id, &genus) + if err != nil { + return err + } + if updated { + w.WriteHeader(http.StatusOK) + } + + return writeJSON(w, genus) +} + +func serveDeleteGenus(w http.ResponseWriter, r *http.Request) error { + id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0) + + deleted, err := store.Genera.Delete(id) + if err != nil { + return err + } + if deleted { + w.WriteHeader(http.StatusOK) + } + + return writeJSON(w, &models.Genus{}) +} diff --git a/api/genera_test.go b/api/genera_test.go new file mode 100644 index 0000000..c5b1949 --- /dev/null +++ b/api/genera_test.go @@ -0,0 +1,147 @@ +package api + +import ( + "testing" + + "github.com/thermokarst/bactdb/models" +) + +func TestGenus_Get(t *testing.T) { + setup() + + want := &models.Genus{Id: 1, GenusName: "Test Genus"} + + calledGet := false + store.Genera.(*models.MockGeneraService).Get_ = func(id int64) (*models.Genus, error) { + if id != want.Id { + t.Errorf("wanted request for genus %d but got %d", want.Id, id) + } + calledGet = true + return want, nil + } + + got, err := apiClient.Genera.Get(want.Id) + if err != nil { + t.Fatal(err) + } + + if !calledGet { + t.Error("!calledGet") + } + if !normalizeDeepEqual(want, got) { + t.Errorf("got genus %+v but wanted genus %+v", got, want) + } +} + +func TestGenus_Create(t *testing.T) { + setup() + + want := &models.Genus{Id: 1, GenusName: "Test Genus"} + + calledPost := false + store.Genera.(*models.MockGeneraService).Create_ = func(genus *models.Genus) (bool, error) { + if !normalizeDeepEqual(want, genus) { + t.Errorf("wanted request for genus %d but got %d", want, genus) + } + calledPost = true + return true, nil + } + + success, err := apiClient.Genera.Create(want) + if err != nil { + t.Fatal(err) + } + + if !calledPost { + t.Error("!calledPost") + } + if !success { + t.Error("!success") + } +} + +func TestGenus_List(t *testing.T) { + setup() + + want := []*models.Genus{{Id: 1, GenusName: "Test Genus"}} + wantOpt := &models.GenusListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}} + + calledList := false + store.Genera.(*models.MockGeneraService).List_ = func(opt *models.GenusListOptions) ([]*models.Genus, error) { + if !normalizeDeepEqual(wantOpt, opt) { + t.Errorf("wanted options %d but got %d", wantOpt, opt) + } + calledList = true + return want, nil + } + + genera, err := apiClient.Genera.List(wantOpt) + if err != nil { + t.Fatal(err) + } + + if !calledList { + t.Error("!calledList") + } + + if !normalizeDeepEqual(&want, &genera) { + t.Errorf("got genera %+v but wanted genera %+v", genera, want) + } +} + +func TestGenus_Update(t *testing.T) { + setup() + + want := &models.Genus{Id: 1, GenusName: "Test Genus"} + + calledPut := false + store.Genera.(*models.MockGeneraService).Update_ = func(id int64, genus *models.Genus) (bool, error) { + if id != want.Id { + t.Errorf("wanted request for genus %d but got %d", want.Id, id) + } + if !normalizeDeepEqual(want, genus) { + t.Errorf("wanted request for genus %d but got %d", want, genus) + } + calledPut = true + return true, nil + } + + success, err := apiClient.Genera.Update(1, want) + if err != nil { + t.Fatal(err) + } + + if !calledPut { + t.Error("!calledPut") + } + if !success { + t.Error("!success") + } +} + +func TestGenus_Delete(t *testing.T) { + setup() + + want := &models.Genus{Id: 1, GenusName: "Test Genus"} + + calledDelete := false + store.Genera.(*models.MockGeneraService).Delete_ = func(id int64) (bool, error) { + if id != want.Id { + t.Errorf("wanted request for genus %d but got %d", want.Id, id) + } + calledDelete = true + return true, nil + } + + success, err := apiClient.Genera.Delete(1) + if err != nil { + t.Fatal(err) + } + + if !calledDelete { + t.Error("!calledDelete") + } + if !success { + t.Error("!success") + } +} diff --git a/api/handler.go b/api/handler.go index 93dd042..a01506b 100644 --- a/api/handler.go +++ b/api/handler.go @@ -18,9 +18,17 @@ var ( func Handler() *mux.Router { m := router.API() + m.Get(router.User).Handler(handler(serveUser)) m.Get(router.CreateUser).Handler(handler(serveCreateUser)) m.Get(router.Users).Handler(handler(serveUsers)) + + m.Get(router.Genus).Handler(handler(serveGenus)) + m.Get(router.CreateGenus).Handler(handler(serveCreateGenus)) + m.Get(router.Genera).Handler(handler(serveGenera)) + m.Get(router.UpdateGenus).Handler(handler(serveUpdateGenus)) + m.Get(router.DeleteGenus).Handler(handler(serveDeleteGenus)) + return m } diff --git a/datastore/datastore.go b/datastore/datastore.go index b18c012..43faafd 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -1,16 +1,24 @@ package datastore import ( + "errors" + "github.com/jmoiron/modl" "github.com/thermokarst/bactdb/models" ) // A datastore access point (in PostgreSQL) type Datastore struct { - Users models.UsersService - dbh modl.SqlExecutor + Users models.UsersService + Genera models.GeneraService + dbh modl.SqlExecutor } +var ( + ErrNoRowsUpdated = errors.New(`no rows updated`) + ErrNoRowsDeleted = errors.New(`no rows deleted`) +) + // NewDatastore creates a new client for accessing the datastore (in PostgreSQL). // If dbh is nil, it uses the global DB handle. func NewDatastore(dbh modl.SqlExecutor) *Datastore { @@ -20,11 +28,13 @@ func NewDatastore(dbh modl.SqlExecutor) *Datastore { d := &Datastore{dbh: dbh} d.Users = &usersStore{d} + d.Genera = &generaStore{d} return d } func NewMockDatastore() *Datastore { return &Datastore{ - Users: &models.MockUsersService{}, + Users: &models.MockUsersService{}, + Genera: &models.MockGeneraService{}, } } diff --git a/datastore/db.go b/datastore/db.go index e8a6b93..71d613e 100644 --- a/datastore/db.go +++ b/datastore/db.go @@ -26,7 +26,7 @@ var connectOnce sync.Once func Connect() { connectOnce.Do(func() { var err error - DB.Dbx, err = sqlx.Open("postgres", "sslmode=disable") + DB.Dbx, err = sqlx.Open("postgres", "timezone=UTC sslmode=disable") if err != nil { log.Fatal("Error connecting to PostgreSQL database (using PG* environment variables): ", err) } diff --git a/datastore/genera.go b/datastore/genera.go new file mode 100644 index 0000000..637c58b --- /dev/null +++ b/datastore/genera.go @@ -0,0 +1,85 @@ +package datastore + +import ( + "strings" + + "github.com/thermokarst/bactdb/models" +) + +func init() { + DB.AddTableWithName(models.Genus{}, "genera").SetKeys(true, "Id") +} + +type generaStore struct { + *Datastore +} + +func (s *generaStore) Get(id int64) (*models.Genus, error) { + var genus []*models.Genus + if err := s.dbh.Select(&genus, `SELECT * FROM genera WHERE id=$1;`, id); err != nil { + return nil, err + } + if len(genus) == 0 { + return nil, models.ErrGenusNotFound + } + return genus[0], nil +} + +func (s *generaStore) Create(genus *models.Genus) (bool, error) { + if err := s.dbh.Insert(genus); err != nil { + if strings.Contains(err.Error(), `violates unique constraint "genus_idx"`) { + return false, err + } + } + return true, nil +} + +func (s *generaStore) List(opt *models.GenusListOptions) ([]*models.Genus, error) { + if opt == nil { + opt = &models.GenusListOptions{} + } + var genera []*models.Genus + err := s.dbh.Select(&genera, `SELECT * FROM genera LIMIT $1 OFFSET $2;`, opt.PerPageOrDefault(), opt.Offset()) + if err != nil { + return nil, err + } + return genera, nil +} + +func (s *generaStore) Update(id int64, genus *models.Genus) (bool, error) { + _, err := s.Get(id) + if err != nil { + return false, err + } + + if id != genus.Id { + return false, models.ErrGenusNotFound + } + + changed, err := s.dbh.Update(genus) + if err != nil { + return false, err + } + + if changed == 0 { + return false, ErrNoRowsUpdated + } + + return true, nil +} + +func (s *generaStore) Delete(id int64) (bool, error) { + genus, err := s.Get(id) + if err != nil { + return false, err + } + + deleted, err := s.dbh.Delete(genus) + if err != nil { + return false, err + } + if deleted == 0 { + return false, ErrNoRowsDeleted + } + return true, nil +} diff --git a/datastore/genera_test.go b/datastore/genera_test.go new file mode 100644 index 0000000..32b9d77 --- /dev/null +++ b/datastore/genera_test.go @@ -0,0 +1,140 @@ +package datastore + +import ( + "reflect" + "testing" + + "github.com/thermokarst/bactdb/models" +) + +func TestGeneraStore_Get_db(t *testing.T) { + want := &models.Genus{Id: 1, GenusName: "Test Genus"} + + tx, _ := DB.Begin() + defer tx.Rollback() + + // Test on a clean database + tx.Exec(`DELETE FROM genera;`) + if err := tx.Insert(want); err != nil { + t.Fatal(err) + } + + d := NewDatastore(tx) + genus, err := d.Genera.Get(1) + if err != nil { + t.Fatal(err) + } + + normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) + if !reflect.DeepEqual(genus, want) { + t.Errorf("got genus %+v, want %+v", genus, want) + } +} + +func TestGeneraStore_Create_db(t *testing.T) { + genus := &models.Genus{Id: 1, GenusName: "Test Genus"} + + tx, _ := DB.Begin() + defer tx.Rollback() + + // Test on a clean database + tx.Exec(`DELETE FROM genera;`) + + d := NewDatastore(tx) + created, err := d.Genera.Create(genus) + if err != nil { + t.Fatal(err) + } + + if !created { + t.Error("!created") + } + if genus.Id == 0 { + t.Error("want nonzero genus.Id after submitting") + } +} + +func TestGeneraStore_List_db(t *testing.T) { + want := []*models.Genus{{Id: 1, GenusName: "Test Genus"}} + + tx, _ := DB.Begin() + defer tx.Rollback() + + // Test on a clean database + tx.Exec(`DELETE FROM genera;`) + if err := tx.Insert(want[0]); err != nil { + t.Fatal(err) + } + + d := NewDatastore(tx) + genera, err := d.Genera.List(&models.GenusListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}) + if err != nil { + t.Fatal(err) + } + + for _, g := range want { + normalizeTime(&g.CreatedAt, &g.UpdatedAt, &g.DeletedAt) + } + if !reflect.DeepEqual(genera, want) { + t.Errorf("got genera %+v, want %+v", genera, want) + } +} + +func TestGeneraStore_Update_db(t *testing.T) { + tx, _ := DB.Begin() + defer tx.Rollback() + + // Test on a clean database + tx.Exec(`DELETE FROM genera;`) + + d := NewDatastore(nil) + // Add a new record + genus := &models.Genus{GenusName: "Test Genus"} + created, err := d.Genera.Create(genus) + if err != nil { + t.Fatal(err) + } + if !created { + t.Error("!created") + } + + // Tweak it + genus.GenusName = "Updated Genus" + updated, err := d.Genera.Update(genus.Id, genus) + if err != nil { + t.Fatal(err) + } + + if !updated { + t.Error("!updated") + } +} + +func TestGeneraStore_Delete_db(t *testing.T) { + tx, _ := DB.Begin() + defer tx.Rollback() + + // Test on a clean database + tx.Exec(`DELETE FROM genera;`) + + d := NewDatastore(tx) + // Add a new record + genus := &models.Genus{GenusName: "Test Genus"} + created, err := d.Genera.Create(genus) + if err != nil { + t.Fatal(err) + } + if !created { + t.Error("!created") + } + + // Delete it + deleted, err := d.Genera.Delete(genus.Id) + if err != nil { + t.Fatal(err) + } + + if !deleted { + t.Error("!delete") + } +} diff --git a/datastore/migrations/00002_AddGenera_down.sql b/datastore/migrations/00002_AddGenera_down.sql new file mode 100644 index 0000000..672e1fc --- /dev/null +++ b/datastore/migrations/00002_AddGenera_down.sql @@ -0,0 +1,5 @@ +-- bactdb +-- Matthew R Dillon + +DROP TABLE genera; + diff --git a/datastore/migrations/00002_AddGenera_up.sql b/datastore/migrations/00002_AddGenera_up.sql new file mode 100644 index 0000000..3fa4d79 --- /dev/null +++ b/datastore/migrations/00002_AddGenera_up.sql @@ -0,0 +1,19 @@ +-- bactdb +-- Matthew R Dillon + +CREATE TABLE genera ( + id BIGSERIAL NOT NULL, + genusname CHARACTER VARYING(100), + + createdat TIMESTAMP WITH TIME ZONE, + updatedat TIMESTAMP WITH TIME ZONE, + deletedat TIMESTAMP WITH TIME ZONE, + + CONSTRAINT genus_pkey PRIMARY KEY (id) +); + +CREATE UNIQUE INDEX genusname_idx + ON genera + USING btree + (genusname COLLATE pg_catalog."default"); + diff --git a/models/client.go b/models/client.go index e65f082..bb321e7 100644 --- a/models/client.go +++ b/models/client.go @@ -16,7 +16,8 @@ import ( // A Client communicates with bactdb's HTTP API. type Client struct { - Users UsersService + Users UsersService + Genera GeneraService // BaseURL for HTTP requests to bactdb's API. BaseURL *url.URL @@ -45,6 +46,7 @@ func NewClient(httpClient *http.Client) *Client { httpClient: httpClient, } c.Users = &usersService{c} + c.Genera = &generaService{c} return c } diff --git a/models/genera.go b/models/genera.go new file mode 100644 index 0000000..fb87694 --- /dev/null +++ b/models/genera.go @@ -0,0 +1,200 @@ +package models + +import ( + "errors" + "net/http" + "strconv" + "time" + + "github.com/thermokarst/bactdb/router" +) + +// A Genus is a high-level classifier in bactdb. +type Genus struct { + Id int64 `json:"id,omitempty"` + GenusName string `json:"genus_name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt time.Time `json:"deleted_at"` +} + +// GeneraService interacts with the genus-related endpoints in bactdb's API. +type GeneraService interface { + // Get a genus. + Get(id int64) (*Genus, error) + + // List all genera. + List(opt *GenusListOptions) ([]*Genus, error) + + // Create a new genus. The newly created genus's ID is written to genus.Id + Create(genus *Genus) (created bool, err error) + + // Update an existing genus. + Update(id int64, genus *Genus) (updated bool, err error) + + // Delete an existing genus. + Delete(id int64) (deleted bool, err error) +} + +var ( + ErrGenusNotFound = errors.New("genus not found") +) + +type generaService struct { + client *Client +} + +func (s *generaService) Get(id int64) (*Genus, error) { + // Pass in key value pairs as strings, so that the gorilla mux URL + // generation is happy. + strId := strconv.FormatInt(id, 10) + + url, err := s.client.url(router.Genus, map[string]string{"Id": strId}, nil) + if err != nil { + return nil, err + } + + req, err := s.client.NewRequest("GET", url.String(), nil) + if err != nil { + return nil, err + } + + var genus *Genus + _, err = s.client.Do(req, &genus) + if err != nil { + return nil, err + } + + return genus, nil +} + +func (s *generaService) Create(genus *Genus) (bool, error) { + url, err := s.client.url(router.CreateGenus, nil, nil) + if err != nil { + return false, err + } + + req, err := s.client.NewRequest("POST", url.String(), genus) + if err != nil { + return false, err + } + + resp, err := s.client.Do(req, &genus) + if err != nil { + return false, err + } + + return resp.StatusCode == http.StatusCreated, nil +} + +type GenusListOptions struct { + ListOptions +} + +func (s *generaService) List(opt *GenusListOptions) ([]*Genus, error) { + url, err := s.client.url(router.Genera, nil, opt) + if err != nil { + return nil, err + } + + req, err := s.client.NewRequest("GET", url.String(), nil) + if err != nil { + return nil, err + } + + var genera []*Genus + _, err = s.client.Do(req, &genera) + if err != nil { + return nil, err + } + + return genera, nil +} + +func (s *generaService) Update(id int64, genus *Genus) (bool, error) { + strId := strconv.FormatInt(id, 10) + + url, err := s.client.url(router.UpdateGenus, map[string]string{"Id": strId}, nil) + if err != nil { + return false, err + } + + req, err := s.client.NewRequest("PUT", url.String(), genus) + if err != nil { + return false, err + } + + resp, err := s.client.Do(req, &genus) + if err != nil { + return false, err + } + + return resp.StatusCode == http.StatusOK, nil +} + +func (s *generaService) Delete(id int64) (bool, error) { + strId := strconv.FormatInt(id, 10) + + url, err := s.client.url(router.DeleteGenus, map[string]string{"Id": strId}, nil) + if err != nil { + return false, err + } + + req, err := s.client.NewRequest("DELETE", url.String(), nil) + if err != nil { + return false, err + } + + var genus *Genus + resp, err := s.client.Do(req, &genus) + if err != nil { + return false, err + } + + return resp.StatusCode == http.StatusOK, nil +} + +type MockGeneraService struct { + Get_ func(id int64) (*Genus, error) + List_ func(opt *GenusListOptions) ([]*Genus, error) + Create_ func(genus *Genus) (bool, error) + Update_ func(id int64, genus *Genus) (bool, error) + Delete_ func(id int64) (bool, error) +} + +var _ GeneraService = &MockGeneraService{} + +func (s *MockGeneraService) Get(id int64) (*Genus, error) { + if s.Get_ == nil { + return nil, nil + } + return s.Get_(id) +} + +func (s *MockGeneraService) Create(genus *Genus) (bool, error) { + if s.Create_ == nil { + return false, nil + } + return s.Create_(genus) +} + +func (s *MockGeneraService) List(opt *GenusListOptions) ([]*Genus, error) { + if s.List_ == nil { + return nil, nil + } + return s.List_(opt) +} + +func (s *MockGeneraService) Update(id int64, genus *Genus) (bool, error) { + if s.Update_ == nil { + return false, nil + } + return s.Update_(id, genus) +} + +func (s *MockGeneraService) Delete(id int64) (bool, error) { + if s.Delete_ == nil { + return false, nil + } + return s.Delete_(id) +} diff --git a/models/genera_test.go b/models/genera_test.go new file mode 100644 index 0000000..453f0bf --- /dev/null +++ b/models/genera_test.go @@ -0,0 +1,167 @@ +package models + +import ( + "net/http" + "reflect" + "testing" + + "github.com/thermokarst/bactdb/router" +) + +func TestGeneraService_Get(t *testing.T) { + setup() + defer teardown() + + want := &Genus{Id: 1, GenusName: "Test Genus"} + + var called bool + mux.HandleFunc(urlPath(t, router.Genus, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "GET") + + writeJSON(w, want) + }) + + genus, err := client.Genera.Get(1) + if err != nil { + t.Errorf("Genera.Get returned error: %v", err) + } + + if !called { + t.Fatal("!called") + } + + normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) + + if !reflect.DeepEqual(genus, want) { + t.Errorf("Genera.Get returned %+v, want %+v", genus, want) + } +} + +func TestGeneraService_Create(t *testing.T) { + setup() + defer teardown() + + want := &Genus{Id: 1, GenusName: "Test Genus"} + + var called bool + mux.HandleFunc(urlPath(t, router.CreateGenus, nil), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "POST") + testBody(t, r, `{"id":1,"genus_name":"Test Genus","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":"0001-01-01T00:00:00Z"}`+"\n") + + w.WriteHeader(http.StatusCreated) + writeJSON(w, want) + }) + + genus := &Genus{Id: 1, GenusName: "Test Genus"} + created, err := client.Genera.Create(genus) + if err != nil { + t.Errorf("Genera.Create returned error: %v", err) + } + + if !created { + t.Error("!created") + } + + if !called { + t.Fatal("!called") + } + + normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) + if !reflect.DeepEqual(genus, want) { + t.Errorf("Genera.Create returned %+v, want %+v", genus, want) + } +} + +func TestGeneraService_List(t *testing.T) { + setup() + defer teardown() + + want := []*Genus{{Id: 1, GenusName: "Test Genus"}} + + var called bool + mux.HandleFunc(urlPath(t, router.Genera, nil), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "GET") + testFormValues(t, r, values{}) + + writeJSON(w, want) + }) + + genera, err := client.Genera.List(nil) + if err != nil { + t.Errorf("Genera.List returned error: %v", err) + } + + if !called { + t.Fatal("!called") + } + + for _, u := range want { + normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt) + } + if !reflect.DeepEqual(genera, want) { + t.Errorf("Genera.List return %+v, want %+v", genera, want) + } +} + +func TestGeneraService_Update(t *testing.T) { + setup() + defer teardown() + + want := &Genus{Id: 1, GenusName: "Test Genus"} + + var called bool + mux.HandleFunc(urlPath(t, router.UpdateGenus, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "PUT") + testBody(t, r, `{"id":1,"genus_name":"Test Genus Updated","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":"0001-01-01T00:00:00Z"}`+"\n") + + w.WriteHeader(http.StatusOK) + writeJSON(w, want) + }) + + genus := &Genus{Id: 1, GenusName: "Test Genus Updated"} + updated, err := client.Genera.Update(1, genus) + if err != nil { + t.Errorf("Genera.Update returned error: %v", err) + } + + if !updated { + t.Error("!updated") + } + + if !called { + t.Fatal("!called") + } +} + +func TestGeneraService_Delete(t *testing.T) { + setup() + defer teardown() + + want := &Genus{Id: 1, GenusName: "Test Genus"} + + var called bool + mux.HandleFunc(urlPath(t, router.DeleteGenus, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "DELETE") + + w.WriteHeader(http.StatusOK) + writeJSON(w, want) + }) + + deleted, err := client.Genera.Delete(1) + if err != nil { + t.Errorf("Genera.Delete returned error: %v", err) + } + + if !deleted { + t.Error("!deleted") + } + + if !called { + t.Fatal("!called") + } +} diff --git a/router/api.go b/router/api.go index df2effb..1df34ee 100644 --- a/router/api.go +++ b/router/api.go @@ -4,8 +4,17 @@ import "github.com/gorilla/mux" func API() *mux.Router { m := mux.NewRouter() + + // Users m.Path("/users").Methods("GET").Name(Users) m.Path("/users").Methods("POST").Name(CreateUser) m.Path("/users/{Id:.+}").Methods("GET").Name(User) + + // Genera + m.Path("/genera").Methods("GET").Name(Genera) + m.Path("/genera").Methods("POST").Name(CreateGenus) + m.Path("/genera/{Id:.+}").Methods("GET").Name(Genus) + m.Path("/genera/{Id:.+}").Methods("PUT").Name(UpdateGenus) + m.Path("/genera/{Id:.+}").Methods("DELETE").Name(DeleteGenus) return m } diff --git a/router/routes.go b/router/routes.go index 4e7dd46..e3bb7bb 100644 --- a/router/routes.go +++ b/router/routes.go @@ -4,4 +4,10 @@ const ( User = "user" CreateUser = "user:create" Users = "users" + + Genus = "genus" + CreateGenus = "genus:create" + Genera = "genera" + UpdateGenus = "genus:update" + DeleteGenus = "genus:delete" ) diff --git a/test.sh b/test.sh index 9670bba..89a7703 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -PGTZ=UTC PGSSLMODE=disable go test -v ./... +go test -v ./...