From 9155ee88f102718b6c6488340274b32120d9bc69 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 13 Oct 2014 09:23:02 -0800 Subject: [PATCH] Genera: router & models --- models/client.go | 4 +- models/genera.go | 135 ++++++++++++++++++++++++++++++++++++++++++ models/genera_test.go | 107 +++++++++++++++++++++++++++++++++ router/api.go | 7 +++ router/routes.go | 9 ++- 5 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 models/genera.go create mode 100644 models/genera_test.go 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..2cad177 --- /dev/null +++ b/models/genera.go @@ -0,0 +1,135 @@ +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) +} + +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 +} + +type MockGeneraService struct { + Get_ func(id int64) (*Genus, error) + List_ func(opt *GenusListOptions) ([]*Genus, error) + Create_ func(post *Genus) (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) +} diff --git a/models/genera_test.go b/models/genera_test.go new file mode 100644 index 0000000..08269c5 --- /dev/null +++ b/models/genera_test.go @@ -0,0 +1,107 @@ +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) + } +} diff --git a/router/api.go b/router/api.go index df2effb..f545a6e 100644 --- a/router/api.go +++ b/router/api.go @@ -4,8 +4,15 @@ 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) return m } diff --git a/router/routes.go b/router/routes.go index 4e7dd46..4abfa86 100644 --- a/router/routes.go +++ b/router/routes.go @@ -1,7 +1,10 @@ package router const ( - User = "user" - CreateUser = "user:create" - Users = "users" + User = "user" + CreateUser = "user:create" + Users = "users" + Genus = "genus" + CreateGenus = "genus:create" + Genera = "genera" )