Rebooting
This commit is contained in:
parent
41ee2857ee
commit
6030310caa
149 changed files with 1489 additions and 9755 deletions
|
@ -1,208 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Characteristic Type is a lookup type
|
||||
type CharacteristicType struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
CharacteristicTypeName string `db:"characteristic_type_name" json:"characteristicTypeName"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
func (m *CharacteristicType) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewCharacteristicType() *CharacteristicType {
|
||||
return &CharacteristicType{
|
||||
CharacteristicTypeName: "Test Char Type",
|
||||
}
|
||||
}
|
||||
|
||||
type CharacteristicTypesService interface {
|
||||
// Get a characteristic type
|
||||
Get(id int64) (*CharacteristicType, error)
|
||||
|
||||
// List all characteristic types
|
||||
List(opt *CharacteristicTypeListOptions) ([]*CharacteristicType, error)
|
||||
|
||||
// Create a characteristic type record
|
||||
Create(characteristic_type *CharacteristicType) (bool, error)
|
||||
|
||||
// Update an existing characteristic type
|
||||
Update(id int64, characteristic_type *CharacteristicType) (updated bool, err error)
|
||||
|
||||
// Delete an existing characteristic type
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrCharacteristicTypeNotFound = errors.New("characteristic type not found")
|
||||
)
|
||||
|
||||
type characteristicTypesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *characteristicTypesService) Get(id int64) (*CharacteristicType, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.CharacteristicType, 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 characteristic_type *CharacteristicType
|
||||
_, err = s.client.Do(req, &characteristic_type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return characteristic_type, nil
|
||||
}
|
||||
|
||||
func (s *characteristicTypesService) Create(characteristic_type *CharacteristicType) (bool, error) {
|
||||
url, err := s.client.url(router.CreateCharacteristicType, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), characteristic_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &characteristic_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type CharacteristicTypeListOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
func (s *characteristicTypesService) List(opt *CharacteristicTypeListOptions) ([]*CharacteristicType, error) {
|
||||
url, err := s.client.url(router.CharacteristicTypes, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var characteristic_types []*CharacteristicType
|
||||
_, err = s.client.Do(req, &characteristic_types)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return characteristic_types, nil
|
||||
}
|
||||
|
||||
func (s *characteristicTypesService) Update(id int64, characteristic_type *CharacteristicType) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateCharacteristicType, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), characteristic_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &characteristic_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *characteristicTypesService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteCharacteristicType, 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 characteristic_type *CharacteristicType
|
||||
resp, err := s.client.Do(req, &characteristic_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockCharacteristicTypesService struct {
|
||||
Get_ func(id int64) (*CharacteristicType, error)
|
||||
List_ func(opt *CharacteristicTypeListOptions) ([]*CharacteristicType, error)
|
||||
Create_ func(characteristic_type *CharacteristicType) (bool, error)
|
||||
Update_ func(id int64, characteristic_type *CharacteristicType) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ CharacteristicTypesService = &MockCharacteristicTypesService{}
|
||||
|
||||
func (s *MockCharacteristicTypesService) Get(id int64) (*CharacteristicType, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicTypesService) Create(characteristic_type *CharacteristicType) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(characteristic_type)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicTypesService) List(opt *CharacteristicTypeListOptions) ([]*CharacteristicType, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicTypesService) Update(id int64, characteristic_type *CharacteristicType) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, characteristic_type)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicTypesService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newCharacteristicType() *CharacteristicType {
|
||||
characteristic_type := NewCharacteristicType()
|
||||
characteristic_type.Id = 1
|
||||
return characteristic_type
|
||||
}
|
||||
|
||||
func TestCharacteristicTypeService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristicType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CharacteristicType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
characteristic_type, err := client.CharacteristicTypes.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("CharacteristicTypes.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(characteristic_type, want) {
|
||||
t.Errorf("CharacteristicTypes.Get return %+v, want %+v", characteristic_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicTypeService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristicType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateCharacteristicType, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"id":1,"characteristicTypeName":"Test Char Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
characteristic_type := newCharacteristicType()
|
||||
created, err := client.CharacteristicTypes.Create(characteristic_type)
|
||||
if err != nil {
|
||||
t.Errorf("CharacteristicTypes.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(characteristic_type, want) {
|
||||
t.Errorf("CharacteristicTypes.Create returned %+v, want %+v", characteristic_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicTypeService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*CharacteristicType{newCharacteristicType()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CharacteristicTypes, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
characteristic_types, err := client.CharacteristicTypes.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("CharacteristicTypes.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(characteristic_types, want) {
|
||||
t.Errorf("CharacteristicTypes.List return %+v, want %+v", characteristic_types, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicTypeService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristicType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateCharacteristicType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"id":1,"characteristicTypeName":"Test Char Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
characteristic_type := newCharacteristicType()
|
||||
characteristic_type.CharacteristicTypeName = "Test Char Type Updated"
|
||||
updated, err := client.CharacteristicTypes.Update(characteristic_type.Id, characteristic_type)
|
||||
if err != nil {
|
||||
t.Errorf("CharacteristicTypes.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicTypeService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristicType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteCharacteristicType, 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.CharacteristicTypes.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("CharacteristicTypes.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Characteristic is a lookup type
|
||||
type CharacteristicBase struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
CharacteristicName string `db:"characteristic_name" json:"characteristicName"`
|
||||
CharacteristicTypeId int64 `db:"characteristic_type_id" json:"characteristicTypeId"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
type Characteristic struct {
|
||||
*CharacteristicBase
|
||||
Measurements NullSliceInt64 `db:"measurements" json:"measurements"`
|
||||
}
|
||||
|
||||
type CharacteristicJSON struct {
|
||||
Characteristic *Characteristic `json:"characteristic"`
|
||||
}
|
||||
|
||||
type CharacteristicsJSON struct {
|
||||
Characteristics []*Characteristic `json:"characteristics"`
|
||||
}
|
||||
|
||||
func (m *Characteristic) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewCharacteristic() *Characteristic {
|
||||
return &Characteristic{
|
||||
&CharacteristicBase{
|
||||
CharacteristicName: "Test Characteristic",
|
||||
},
|
||||
make([]int64, 0),
|
||||
}
|
||||
}
|
||||
|
||||
type CharacteristicsService interface {
|
||||
// Get an characteristic
|
||||
Get(id int64) (*Characteristic, error)
|
||||
|
||||
// List all characteristics
|
||||
List(opt *CharacteristicListOptions) ([]*Characteristic, error)
|
||||
|
||||
// Create an characteristic
|
||||
Create(characteristic *Characteristic) (bool, error)
|
||||
|
||||
// Update an characteristic
|
||||
Update(id int64, Characteristic *Characteristic) (updated bool, err error)
|
||||
|
||||
// Delete an characteristic
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrCharacteristicNotFound = errors.New("characteristic not found")
|
||||
)
|
||||
|
||||
type characteristicsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *characteristicsService) Get(id int64) (*Characteristic, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.Characteristic, 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 characteristic *CharacteristicJSON
|
||||
_, err = s.client.Do(req, &characteristic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return characteristic.Characteristic, nil
|
||||
}
|
||||
|
||||
func (s *characteristicsService) Create(characteristic *Characteristic) (bool, error) {
|
||||
url, err := s.client.url(router.CreateCharacteristic, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), CharacteristicJSON{Characteristic: characteristic})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &characteristic)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type CharacteristicListOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
func (s *characteristicsService) List(opt *CharacteristicListOptions) ([]*Characteristic, error) {
|
||||
url, err := s.client.url(router.Characteristics, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var characteristics *CharacteristicsJSON
|
||||
_, err = s.client.Do(req, &characteristics)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return characteristics.Characteristics, nil
|
||||
}
|
||||
|
||||
func (s *characteristicsService) Update(id int64, characteristic *Characteristic) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateCharacteristic, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), CharacteristicJSON{Characteristic: characteristic})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &characteristic)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *characteristicsService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteCharacteristic, 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 characteristic *Characteristic
|
||||
resp, err := s.client.Do(req, &characteristic)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockCharacteristicsService struct {
|
||||
Get_ func(id int64) (*Characteristic, error)
|
||||
List_ func(opt *CharacteristicListOptions) ([]*Characteristic, error)
|
||||
Create_ func(characteristic *Characteristic) (bool, error)
|
||||
Update_ func(id int64, characteristic *Characteristic) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ CharacteristicsService = &MockCharacteristicsService{}
|
||||
|
||||
func (s *MockCharacteristicsService) Get(id int64) (*Characteristic, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicsService) Create(characteristic *Characteristic) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(characteristic)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicsService) List(opt *CharacteristicListOptions) ([]*Characteristic, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicsService) Update(id int64, characteristic *Characteristic) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, characteristic)
|
||||
}
|
||||
|
||||
func (s *MockCharacteristicsService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newCharacteristic() *Characteristic {
|
||||
characteristic := NewCharacteristic()
|
||||
characteristic.Id = 1
|
||||
return characteristic
|
||||
}
|
||||
|
||||
func TestCharacteristicService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristic()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Characteristic, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, CharacteristicJSON{Characteristic: want})
|
||||
})
|
||||
|
||||
characteristic, err := client.Characteristics.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Characteristics.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(characteristic, want) {
|
||||
t.Errorf("Characteristics.Get return %+v, want %+v", characteristic, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristic()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateCharacteristic, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"characteristic":{"id":1,"characteristicName":"Test Characteristic","characteristicTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"measurements":[]}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
characteristic := newCharacteristic()
|
||||
created, err := client.Characteristics.Create(characteristic)
|
||||
if err != nil {
|
||||
t.Errorf("Characteristics.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(characteristic, want) {
|
||||
t.Errorf("Characteristics.Create returned %+v, want %+v", characteristic, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*Characteristic{newCharacteristic()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Characteristics, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, CharacteristicsJSON{Characteristics: want})
|
||||
})
|
||||
|
||||
characteristics, err := client.Characteristics.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("Characteristics.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(characteristics, want) {
|
||||
t.Errorf("Characteristics.List return %+v, want %+v", characteristics, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristic()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateCharacteristic, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"characteristic":{"id":1,"characteristicName":"Test Char Updated","characteristicTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"measurements":[]}}`+"\n")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
characteristic := newCharacteristic()
|
||||
characteristic.CharacteristicName = "Test Char Updated"
|
||||
updated, err := client.Characteristics.Update(characteristic.Id, characteristic)
|
||||
if err != nil {
|
||||
t.Errorf("Characteristics.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCharacteristicService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newCharacteristic()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteCharacteristic, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "DELETE")
|
||||
testBody(t, r, "")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
deleted, err := client.Characteristics.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Characteristics.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
211
models/client.go
211
models/client.go
|
@ -1,211 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Client communicates with bactdb's HTTP API.
|
||||
type Client struct {
|
||||
Users UsersService
|
||||
Genera GeneraService
|
||||
Species SpeciesService
|
||||
Strains StrainsService
|
||||
CharacteristicTypes CharacteristicTypesService
|
||||
Characteristics CharacteristicsService
|
||||
TextMeasurementTypes TextMeasurementTypesService
|
||||
UnitTypes UnitTypesService
|
||||
Measurements MeasurementsService
|
||||
|
||||
// BaseURL for HTTP requests to bactdb's API.
|
||||
BaseURL *url.URL
|
||||
|
||||
//UserAgent used for HTTP requests to bactdb's API.
|
||||
UserAgent string
|
||||
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
const (
|
||||
libraryVersion = "0.0.1"
|
||||
userAgent = "bactdb-client/" + libraryVersion
|
||||
)
|
||||
|
||||
// NewClient creates a new HTTP API client for bactdb. If httpClient == nil,
|
||||
// then http.DefaultClient is used.
|
||||
func NewClient(httpClient *http.Client) *Client {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
c := &Client{
|
||||
BaseURL: &url.URL{Scheme: "http", Host: "bactdb.org", Path: "/api/"},
|
||||
UserAgent: userAgent,
|
||||
httpClient: httpClient,
|
||||
}
|
||||
c.Users = &usersService{c}
|
||||
c.Genera = &generaService{c}
|
||||
c.Species = &speciesService{c}
|
||||
c.Strains = &strainsService{c}
|
||||
c.CharacteristicTypes = &characteristicTypesService{c}
|
||||
c.Characteristics = &characteristicsService{c}
|
||||
c.TextMeasurementTypes = &textMeasurementTypesService{c}
|
||||
c.UnitTypes = &unitTypesService{c}
|
||||
c.Measurements = &measurementsService{c}
|
||||
return c
|
||||
}
|
||||
|
||||
// ListOptions specifies general pagination options for fetching a list of results
|
||||
type ListOptions struct {
|
||||
PerPage int `url:",omitempty" json:",omitempty"`
|
||||
Page int `url:",omitempty" json:",omitempty"`
|
||||
}
|
||||
|
||||
func (o ListOptions) PageOrDefault() int {
|
||||
if o.Page <= 0 {
|
||||
return 1
|
||||
}
|
||||
return o.Page
|
||||
}
|
||||
|
||||
func (o ListOptions) Offset() int {
|
||||
return (o.PageOrDefault() - 1) * o.PerPageOrDefault()
|
||||
}
|
||||
|
||||
func (o ListOptions) PerPageOrDefault() int {
|
||||
if o.PerPage <= 0 {
|
||||
return DefaultPerPage
|
||||
}
|
||||
return o.PerPage
|
||||
}
|
||||
|
||||
// DefaultPerPage is the default number of items to return in a paginated result set
|
||||
const DefaultPerPage = 10
|
||||
|
||||
// apiRouter is used to generate URLs for bactdb's HTTP API.
|
||||
var apiRouter = router.API()
|
||||
|
||||
// url generates the URL to the named bactdb API endpoint, using the
|
||||
// specified route variables and query options.
|
||||
func (c *Client) url(apiRouteName string, routeVars map[string]string, opt interface{}) (*url.URL, error) {
|
||||
route := apiRouter.Get(apiRouteName)
|
||||
if route == nil {
|
||||
return nil, fmt.Errorf("no API route named %q", apiRouteName)
|
||||
}
|
||||
|
||||
routeVarsList := make([]string, 2*len(routeVars))
|
||||
i := 0
|
||||
for name, val := range routeVars {
|
||||
routeVarsList[i*2] = name
|
||||
routeVarsList[i*2+1] = val
|
||||
i++
|
||||
}
|
||||
url, err := route.URL(routeVarsList...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// make the route URL path relative to BaseURL by trimming the leading "/"
|
||||
url.Path = strings.TrimPrefix(url.Path, "/")
|
||||
|
||||
if opt != nil {
|
||||
err = addOptions(url, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
func (c *Client) URL(apiRouteName string, routeVars map[string]string, opt interface{}) (*url.URL, error) {
|
||||
u, err := c.url(apiRouteName, routeVars, opt)
|
||||
absURL := c.BaseURL.ResolveReference(u)
|
||||
return absURL, err
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided in urlStr,
|
||||
// in which case it is resolved relative to the BaseURL of the Client. Relative
|
||||
// URLs should always be specified without a preceding slash. If specified, the
|
||||
// value pointed to by body is JSON encoded and included as the request body.
|
||||
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
|
||||
rel, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u := c.BaseURL.ResolveReference(rel)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if body != nil {
|
||||
err := json.NewEncoder(buf).Encode(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u.String(), buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("User-Agent", c.UserAgent)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Do sends an API request and returns the API response. The API response is
|
||||
// JSON-decoded and stored in the value pointed to by v, or returned as an error
|
||||
// if an API error has occurred.
|
||||
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = CheckResponse(resp)
|
||||
if err != nil {
|
||||
// even though there was an error, we still return the response
|
||||
// in case the caller wants to inspect it further
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
if bp, ok := v.(*[]byte); ok {
|
||||
*bp, err = ioutil.ReadAll(resp.Body)
|
||||
} else {
|
||||
err = json.NewDecoder(resp.Body).Decode(v)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading response from %s %s: %s", req.Method, req.URL.RequestURI(), err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// addOptions adds the parameters in opt as URL query parameters to u. opt
|
||||
// must be a struct whose fields may contain "url" tags.
|
||||
func addOptions(u *url.URL, opt interface{}) error {
|
||||
v := reflect.ValueOf(opt)
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return nil
|
||||
}
|
||||
|
||||
qs, err := query.Values(opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.RawQuery = qs.Encode()
|
||||
return nil
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
var (
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux *http.ServeMux
|
||||
|
||||
// client is the bactdb client being tested.
|
||||
client *Client
|
||||
|
||||
// server is a test HTTP server used to provide mock API responses.
|
||||
server *httptest.Server
|
||||
)
|
||||
|
||||
// setup sets up a test HTTP server along with a Client that is
|
||||
// configured to talk to that test server. Tests should register handlers on
|
||||
// mux which provide mock responses for the API method being tested.
|
||||
func setup() {
|
||||
// test server
|
||||
mux = http.NewServeMux()
|
||||
server = httptest.NewServer(mux)
|
||||
|
||||
// bactdb client configured to use test server
|
||||
client = NewClient(nil)
|
||||
url, _ := url.Parse(server.URL)
|
||||
client.BaseURL = url
|
||||
}
|
||||
|
||||
// teardown closes the test HTTP server.
|
||||
func teardown() {
|
||||
server.Close()
|
||||
}
|
||||
|
||||
func urlPath(t *testing.T, routeName string, routeVars map[string]string) string {
|
||||
url, err := client.url(routeName, routeVars, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing URL path for route %q with vars %+v: %s", routeName, routeVars, err)
|
||||
}
|
||||
return "/" + url.Path
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, v interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
err := json.NewEncoder(w).Encode(v)
|
||||
if err != nil {
|
||||
panic("writeJSON: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testMethod(t *testing.T, r *http.Request, want string) {
|
||||
if want != r.Method {
|
||||
t.Errorf("Request method = %v, want %v", r.Method, want)
|
||||
}
|
||||
}
|
||||
|
||||
type values map[string]string
|
||||
|
||||
func testFormValues(t *testing.T, r *http.Request, values values) {
|
||||
want := url.Values{}
|
||||
for k, v := range values {
|
||||
want.Add(k, v)
|
||||
}
|
||||
|
||||
r.ParseForm()
|
||||
if !reflect.DeepEqual(want, r.Form) {
|
||||
t.Errorf("Request parameters = %v, want %v", r.Form, want)
|
||||
}
|
||||
}
|
||||
|
||||
func testBody(t *testing.T, r *http.Request, want string) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to read body")
|
||||
}
|
||||
str := string(b)
|
||||
if want != str {
|
||||
t.Errorf("Body = %s, want: %s", str, want)
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeTime(t ...interface{}) {
|
||||
for _, v := range t {
|
||||
switch u := v.(type) {
|
||||
default:
|
||||
fmt.Printf("unexpected type %T", u)
|
||||
case *time.Time:
|
||||
x, _ := v.(*time.Time)
|
||||
*x = x.In(time.UTC)
|
||||
case *NullTime:
|
||||
x, _ := v.(*NullTime)
|
||||
*x = NullTime{pq.NullTime{Time: x.Time.In(time.UTC), Valid: x.Valid}}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// An ErrorResponse reports errors caused by an API request.
|
||||
type ErrorResponse struct {
|
||||
Response *http.Response `json:",omitempty"`
|
||||
Message string
|
||||
}
|
||||
|
||||
func (r *ErrorResponse) Error() string {
|
||||
return fmt.Sprintf("%v %v: %d %v",
|
||||
r.Response.Request.Method, r.Response.Request.URL,
|
||||
r.Response.StatusCode, r.Message)
|
||||
}
|
||||
|
||||
func (r *ErrorResponse) HTTPStatusCode() int {
|
||||
return r.Response.StatusCode
|
||||
}
|
||||
|
||||
// CheckResponse checks the API response for errors, and returns them if
|
||||
// present. A response is considered an error if it has a status code outside
|
||||
// the 200 range. API error responses are expected to have either no response
|
||||
// body, or a JSON response body that maps to ErrorResponse. Any other
|
||||
// response body will be silently ignored.
|
||||
func CheckResponse(r *http.Response) error {
|
||||
if c := r.StatusCode; 200 <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
errorResponse := &ErrorResponse{Response: r}
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err == nil && data != nil {
|
||||
json.Unmarshal(data, errorResponse)
|
||||
}
|
||||
return errorResponse
|
||||
}
|
||||
|
||||
func IsHTTPErrorCode(err error, statusCode int) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
type httpError interface {
|
||||
Error() string
|
||||
HTTPStatusCode() int
|
||||
}
|
||||
if httpErr, ok := err.(httpError); ok {
|
||||
return statusCode == httpErr.HTTPStatusCode()
|
||||
}
|
||||
return false
|
||||
}
|
226
models/genera.go
226
models/genera.go
|
@ -1,226 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Genus is a high-level classifier in bactdb.
|
||||
type GenusBase struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
GenusName string `db:"genus_name" json:"genusName"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
type Genus struct {
|
||||
*GenusBase
|
||||
Species NullSliceInt64 `db:"species" json:"species"`
|
||||
}
|
||||
|
||||
type GenusJSON struct {
|
||||
Genus *Genus `json:"genus"`
|
||||
}
|
||||
|
||||
type GeneraJSON struct {
|
||||
Genera []*Genus `json:"genera"`
|
||||
}
|
||||
|
||||
func (m *Genus) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func (m *GenusBase) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewGenus() *Genus {
|
||||
return &Genus{&GenusBase{GenusName: "Test Genus"}, make([]int64, 0)}
|
||||
}
|
||||
|
||||
// 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 *GenusJSON
|
||||
_, err = s.client.Do(req, &genus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return genus.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(), GenusJSON{Genus: 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 *GeneraJSON
|
||||
_, err = s.client.Do(req, &genera)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return genera.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(), GenusJSON{Genus: 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)
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newGenus() *Genus {
|
||||
genus := NewGenus()
|
||||
genus.Id = 1
|
||||
return genus
|
||||
}
|
||||
|
||||
func TestGeneraService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newGenus()
|
||||
|
||||
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, GenusJSON{Genus: want})
|
||||
})
|
||||
|
||||
genus, err := client.Genera.Get(want.Id)
|
||||
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 := newGenus()
|
||||
|
||||
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, `{"genus":{"id":1,"genusName":"Test Genus","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"species":[]}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
genus := newGenus()
|
||||
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{newGenus()}
|
||||
|
||||
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, GeneraJSON{Genera: 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 := newGenus()
|
||||
|
||||
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, `{"genus":{"id":1,"genusName":"Test Genus Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"species":[]}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
genus := newGenus()
|
||||
genus.GenusName = "Test Genus Updated"
|
||||
updated, err := client.Genera.Update(genus.Id, 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 := newGenus()
|
||||
|
||||
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")
|
||||
testBody(t, r, "")
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Measurement is the main data type for this application
|
||||
// There are two types of supported measurements: text & numerical. The table
|
||||
// has a constraint that will allow one or the other for a particular
|
||||
// combination of strain & characteristic, but not both.
|
||||
type Measurement struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
StrainId int64 `db:"strain_id" json:"strain"`
|
||||
CharacteristicId int64 `db:"characteristic_id" json:"characteristic"`
|
||||
TextMeasurementTypeId NullInt64 `db:"text_measurement_type_id" json:"textMeasurementTypeId"`
|
||||
TxtValue NullString `db:"txt_value" json:"txtValue"`
|
||||
NumValue NullFloat64 `db:"num_value" json:"numValue"`
|
||||
ConfidenceInterval NullFloat64 `db:"confidence_interval" json:"confidenceInterval"`
|
||||
UnitTypeId NullInt64 `db:"unit_type_id" json:"unitTypeId"`
|
||||
Notes NullString `db:"notes" json:"notes"`
|
||||
TestMethodId NullInt64 `db:"test_method_id" json:"testMethodId"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
}
|
||||
|
||||
type MeasurementJSON struct {
|
||||
Measurement *Measurement `json:"measurement"`
|
||||
}
|
||||
|
||||
type MeasurementsJSON struct {
|
||||
Measurements []*Measurement `json:"measurements"`
|
||||
}
|
||||
|
||||
func (m *Measurement) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewMeasurement() *Measurement {
|
||||
return &Measurement{
|
||||
NumValue: NullFloat64{sql.NullFloat64{Float64: 1.23, Valid: true}},
|
||||
}
|
||||
}
|
||||
|
||||
type MeasurementsService interface {
|
||||
// Get a measurement
|
||||
Get(id int64) (*Measurement, error)
|
||||
|
||||
// List all measurements
|
||||
List(opt *MeasurementListOptions) ([]*Measurement, error)
|
||||
|
||||
// Create a measurement
|
||||
Create(measurement *Measurement) (bool, error)
|
||||
|
||||
// Update an existing measurement
|
||||
Update(id int64, MeasurementType *Measurement) (bool, error)
|
||||
|
||||
// Delete a measurement
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrMeasurementNotFound = errors.New("measurement not found")
|
||||
)
|
||||
|
||||
type measurementsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *measurementsService) Get(id int64) (*Measurement, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.Measurement, 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 measurement *MeasurementJSON
|
||||
_, err = s.client.Do(req, &measurement)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return measurement.Measurement, nil
|
||||
}
|
||||
|
||||
func (s *measurementsService) Create(measurement *Measurement) (bool, error) {
|
||||
url, err := s.client.url(router.CreateMeasurement, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), MeasurementJSON{Measurement: measurement})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &measurement)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type MeasurementListOptions struct {
|
||||
ListOptions
|
||||
Genus string
|
||||
}
|
||||
|
||||
func (s *measurementsService) List(opt *MeasurementListOptions) ([]*Measurement, error) {
|
||||
url, err := s.client.url(router.Measurements, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var measurements *MeasurementsJSON
|
||||
_, err = s.client.Do(req, &measurements)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return measurements.Measurements, nil
|
||||
}
|
||||
|
||||
func (s *measurementsService) Update(id int64, measurement *Measurement) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateMeasurement, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), MeasurementJSON{Measurement: measurement})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &measurement)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *measurementsService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteMeasurement, 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 measurement *Measurement
|
||||
resp, err := s.client.Do(req, &measurement)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockMeasurementsService struct {
|
||||
Get_ func(id int64) (*Measurement, error)
|
||||
List_ func(opt *MeasurementListOptions) ([]*Measurement, error)
|
||||
Create_ func(measurement *Measurement) (bool, error)
|
||||
Update_ func(id int64, measurement *Measurement) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ MeasurementsService = &MockMeasurementsService{}
|
||||
|
||||
func (s *MockMeasurementsService) Get(id int64) (*Measurement, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockMeasurementsService) Create(measurement *Measurement) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(measurement)
|
||||
}
|
||||
|
||||
func (s *MockMeasurementsService) List(opt *MeasurementListOptions) ([]*Measurement, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockMeasurementsService) Update(id int64, measurement *Measurement) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, measurement)
|
||||
}
|
||||
|
||||
func (s *MockMeasurementsService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newMeasurement() *Measurement {
|
||||
measurement := NewMeasurement()
|
||||
measurement.Id = 1
|
||||
measurement.StrainId = 1
|
||||
measurement.CharacteristicId = 1
|
||||
measurement.UnitTypeId = NullInt64{sql.NullInt64{Int64: 1, Valid: true}}
|
||||
measurement.Notes = NullString{sql.NullString{String: "a note", Valid: true}}
|
||||
return measurement
|
||||
}
|
||||
|
||||
func TestMeasurementService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newMeasurement()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Measurement, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, MeasurementJSON{Measurement: want})
|
||||
})
|
||||
|
||||
measurement, err := client.Measurements.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Measurements.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt)
|
||||
|
||||
if !reflect.DeepEqual(measurement, want) {
|
||||
t.Errorf("Measurements.Get return %+v, want %+v", measurement, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeasurementService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newMeasurement()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateMeasurement, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"measurement":{"id":1,"strain":1,"characteristic":1,"textMeasurementTypeId":null,"txtValue":null,"numValue":1.23,"confidenceInterval":null,"unitTypeId":1,"notes":"a note","testMethodId":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
measurement := newMeasurement()
|
||||
created, err := client.Measurements.Create(measurement)
|
||||
if err != nil {
|
||||
t.Errorf("Measurements.Create returned error: %v", err)
|
||||
}
|
||||
|
||||
if !created {
|
||||
t.Error("!created")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt)
|
||||
if !reflect.DeepEqual(measurement, want) {
|
||||
t.Errorf("Measurements.Create returned %+v, want %+v", measurement, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeasurementService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*Measurement{newMeasurement()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Measurements, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, MeasurementsJSON{Measurements: want})
|
||||
})
|
||||
|
||||
measurements, err := client.Measurements.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("Measurements.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(measurements, want) {
|
||||
t.Errorf("Measurements.List return %+v, want %+v", measurements, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeasurementService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newMeasurement()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateMeasurement, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"measurement":{"id":1,"strain":1,"characteristic":1,"textMeasurementTypeId":null,"txtValue":null,"numValue":4.56,"confidenceInterval":null,"unitTypeId":1,"notes":"a note","testMethodId":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}}`+"\n")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
measurement := newMeasurement()
|
||||
measurement.NumValue = NullFloat64{sql.NullFloat64{Float64: 4.56, Valid: true}}
|
||||
updated, err := client.Measurements.Update(measurement.Id, measurement)
|
||||
if err != nil {
|
||||
t.Errorf("Measurements.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeasurementService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newMeasurement()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteMeasurement, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "DELETE")
|
||||
testBody(t, r, "")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
deleted, err := client.Measurements.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Measurements.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Species is a high-level classifier in bactdb.
|
||||
type SpeciesBase struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
GenusId int64 `db:"genus_id" json:"genus"`
|
||||
SpeciesName string `db:"species_name" json:"speciesName"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
type Species struct {
|
||||
*SpeciesBase
|
||||
Strains NullSliceInt64 `db:"strains" json:"strains"`
|
||||
}
|
||||
|
||||
type SpeciesJSON struct {
|
||||
Species *Species `json:"species"`
|
||||
}
|
||||
|
||||
type SpeciesListJSON struct {
|
||||
Species []*Species `json:"species"`
|
||||
}
|
||||
|
||||
func (m *Species) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewSpecies() *Species {
|
||||
return &Species{&SpeciesBase{SpeciesName: "Test Species"}, make([]int64, 0)}
|
||||
}
|
||||
|
||||
// SpeciesService interacts with the species-related endpoints in bactdb's API.
|
||||
type SpeciesService interface {
|
||||
// Get a species
|
||||
Get(id int64) (*Species, error)
|
||||
|
||||
// List all species
|
||||
List(opt *SpeciesListOptions) ([]*Species, error)
|
||||
|
||||
// Create a species record
|
||||
Create(species *Species) (bool, error)
|
||||
|
||||
// Update an existing species
|
||||
Update(id int64, species *Species) (updated bool, err error)
|
||||
|
||||
// Delete an existing species
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrSpeciesNotFound = errors.New("species not found")
|
||||
)
|
||||
|
||||
type speciesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *speciesService) Get(id int64) (*Species, error) {
|
||||
// Pass in key value pairs as strings, sp that the gorilla mux URL generation is happy
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.Species, 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 species *SpeciesJSON
|
||||
_, err = s.client.Do(req, &species)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return species.Species, nil
|
||||
}
|
||||
|
||||
func (s *speciesService) Create(species *Species) (bool, error) {
|
||||
url, err := s.client.url(router.CreateSpecies, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), SpeciesJSON{Species: species})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &species)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type SpeciesListOptions struct {
|
||||
ListOptions
|
||||
Genus string
|
||||
}
|
||||
|
||||
func (s *speciesService) List(opt *SpeciesListOptions) ([]*Species, error) {
|
||||
url, err := s.client.url(router.SpeciesList, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var species *SpeciesListJSON
|
||||
_, err = s.client.Do(req, &species)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return species.Species, nil
|
||||
}
|
||||
|
||||
func (s *speciesService) Update(id int64, species *Species) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateSpecies, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), SpeciesJSON{Species: species})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &species)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *speciesService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteSpecies, 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 species *Species
|
||||
resp, err := s.client.Do(req, &species)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockSpeciesService struct {
|
||||
Get_ func(id int64) (*Species, error)
|
||||
List_ func(opt *SpeciesListOptions) ([]*Species, error)
|
||||
Create_ func(species *Species) (bool, error)
|
||||
Update_ func(id int64, species *Species) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ SpeciesService = &MockSpeciesService{}
|
||||
|
||||
func (s *MockSpeciesService) Get(id int64) (*Species, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockSpeciesService) Create(species *Species) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(species)
|
||||
}
|
||||
|
||||
func (s *MockSpeciesService) List(opt *SpeciesListOptions) ([]*Species, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockSpeciesService) Update(id int64, species *Species) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, species)
|
||||
}
|
||||
|
||||
func (s *MockSpeciesService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newSpecies() *Species {
|
||||
species := NewSpecies()
|
||||
species.Id = 1
|
||||
species.GenusId = 1
|
||||
return species
|
||||
}
|
||||
|
||||
func TestSpeciesService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newSpecies()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Species, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, SpeciesJSON{Species: want})
|
||||
})
|
||||
|
||||
species, err := client.Species.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Species.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(species, want) {
|
||||
t.Errorf("Species.Get returned %+v, want %+v", species, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpeciesService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newSpecies()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateSpecies, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"species":{"id":1,"genus":1,"speciesName":"Test Species","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"strains":[]}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
species := newSpecies()
|
||||
created, err := client.Species.Create(species)
|
||||
if err != nil {
|
||||
t.Errorf("Species.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(species, want) {
|
||||
t.Errorf("Species.Create returned %+v, want %+v", species, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpeciesService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*Species{newSpecies()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.SpeciesList, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, SpeciesListJSON{Species: want})
|
||||
})
|
||||
|
||||
species, err := client.Species.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("Species.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(species, want) {
|
||||
t.Errorf("Species.List return %+v, want %+v", species, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpeciesService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newSpecies()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateSpecies, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"species":{"id":1,"genus":1,"speciesName":"Test Species Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"strains":[]}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
species := newSpecies()
|
||||
species.SpeciesName = "Test Species Updated"
|
||||
updated, err := client.Species.Update(species.Id, species)
|
||||
if err != nil {
|
||||
t.Errorf("Species.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpeciesService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newSpecies()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteSpecies, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "DELETE")
|
||||
testBody(t, r, "")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
deleted, err := client.Species.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Species.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A Strain is a subclass of species
|
||||
type StrainBase struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
SpeciesId int64 `db:"species_id" json:"species"`
|
||||
StrainName string `db:"strain_name" json:"strainName"`
|
||||
StrainType string `db:"strain_type" json:"strainType"`
|
||||
Etymology NullString `db:"etymology" json:"etymology"`
|
||||
AccessionBanks string `db:"accession_banks" json:"accessionBanks"`
|
||||
GenbankEmblDdb NullString `db:"genbank_embl_ddb" json:"genbankEmblDdb"`
|
||||
IsolatedFrom NullString `db:"isolated_from" json:"isolatedFrom"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
type Strain struct {
|
||||
*StrainBase
|
||||
Measurements NullSliceInt64 `db:"measurements" json:"measurements"`
|
||||
}
|
||||
|
||||
type StrainJSON struct {
|
||||
Strain *Strain `json:"strain"`
|
||||
}
|
||||
|
||||
type StrainsJSON struct {
|
||||
Strains []*Strain `json:"strains"`
|
||||
}
|
||||
|
||||
func (s *Strain) String() string {
|
||||
return fmt.Sprintf("%v", *s)
|
||||
}
|
||||
|
||||
func NewStrain() *Strain {
|
||||
return &Strain{
|
||||
&StrainBase{
|
||||
StrainName: "Test Strain",
|
||||
StrainType: "Test Type",
|
||||
Etymology: NullString{
|
||||
sql.NullString{
|
||||
String: "Test Etymology",
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
AccessionBanks: "Test Accession",
|
||||
GenbankEmblDdb: NullString{
|
||||
sql.NullString{
|
||||
String: "Test Genbank",
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
IsolatedFrom: NullString{
|
||||
sql.NullString{
|
||||
String: "",
|
||||
Valid: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
make([]int64, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// StrainService interacts with the strain-related endpoints in bactdb's API
|
||||
type StrainsService interface {
|
||||
// Get a strain
|
||||
Get(id int64) (*Strain, error)
|
||||
|
||||
// List all strains
|
||||
List(opt *StrainListOptions) ([]*Strain, error)
|
||||
|
||||
// Create a strain record
|
||||
Create(strain *Strain) (bool, error)
|
||||
|
||||
// Update an existing strain
|
||||
Update(id int64, strain *Strain) (updated bool, err error)
|
||||
|
||||
// Delete an existing strain
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrStrainNotFound = errors.New("strain not found")
|
||||
)
|
||||
|
||||
type strainsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *strainsService) Get(id int64) (*Strain, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.Strain, 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 strain *StrainJSON
|
||||
_, err = s.client.Do(req, &strain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strain.Strain, nil
|
||||
}
|
||||
|
||||
func (s *strainsService) Create(strain *Strain) (bool, error) {
|
||||
url, err := s.client.url(router.CreateStrain, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), StrainJSON{Strain: strain})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &strain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type StrainListOptions struct {
|
||||
ListOptions
|
||||
Genus string
|
||||
}
|
||||
|
||||
func (s *strainsService) List(opt *StrainListOptions) ([]*Strain, error) {
|
||||
url, err := s.client.url(router.Strains, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var strains *StrainsJSON
|
||||
_, err = s.client.Do(req, &strains)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strains.Strains, nil
|
||||
}
|
||||
|
||||
func (s *strainsService) Update(id int64, strain *Strain) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateStrain, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), StrainJSON{Strain: strain})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &strain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *strainsService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteStrain, 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 strain *Strain
|
||||
resp, err := s.client.Do(req, &strain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockStrainsService struct {
|
||||
Get_ func(id int64) (*Strain, error)
|
||||
List_ func(opt *StrainListOptions) ([]*Strain, error)
|
||||
Create_ func(strain *Strain) (bool, error)
|
||||
Update_ func(id int64, strain *Strain) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ StrainsService = &MockStrainsService{}
|
||||
|
||||
func (s *MockStrainsService) Get(id int64) (*Strain, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockStrainsService) Create(strain *Strain) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(strain)
|
||||
}
|
||||
|
||||
func (s *MockStrainsService) List(opt *StrainListOptions) ([]*Strain, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockStrainsService) Update(id int64, strain *Strain) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, strain)
|
||||
}
|
||||
|
||||
func (s *MockStrainsService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newStrain() *Strain {
|
||||
strain := NewStrain()
|
||||
strain.Id = 1
|
||||
strain.SpeciesId = 1
|
||||
return strain
|
||||
}
|
||||
|
||||
func TestStrainService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newStrain()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Strain, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, StrainJSON{Strain: want})
|
||||
})
|
||||
|
||||
strain, err := client.Strains.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Strain.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(strain, want) {
|
||||
t.Errorf("Strain.Get return %+v, want %+v", strain, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrainService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newStrain()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateStrain, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"strain":{"id":1,"species":1,"strainName":"Test Strain","strainType":"Test Type","etymology":"Test Etymology","accessionBanks":"Test Accession","genbankEmblDdb":"Test Genbank","isolatedFrom":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"measurements":[]}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
strain := newStrain()
|
||||
created, err := client.Strains.Create(strain)
|
||||
if err != nil {
|
||||
t.Errorf("Strains.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(strain, want) {
|
||||
t.Errorf("Strains.Create returned %+v, want %+v", strain, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrainService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*Strain{newStrain()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Strains, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, StrainsJSON{Strains: want})
|
||||
})
|
||||
|
||||
strains, err := client.Strains.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("Strains.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(strains, want) {
|
||||
t.Errorf("Strains.List return %+v, want %+v", strains, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrainService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newStrain()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateStrain, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"strain":{"id":1,"species":1,"strainName":"Test Strain Updated","strainType":"Test Type Updated","etymology":"Test Etymology","accessionBanks":"Test Accession Updated","genbankEmblDdb":"Test Genbank Updated","isolatedFrom":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null,"measurements":[]}}`+"\n")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
strain := newStrain()
|
||||
strain.StrainName = "Test Strain Updated"
|
||||
strain.StrainType = "Test Type Updated"
|
||||
strain.AccessionBanks = "Test Accession Updated"
|
||||
strain.GenbankEmblDdb.String = "Test Genbank Updated"
|
||||
updated, err := client.Strains.Update(strain.Id, strain)
|
||||
if err != nil {
|
||||
t.Errorf("Strains.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrainService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newStrain()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteStrain, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "DELETE")
|
||||
testBody(t, r, "")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
deleted, err := client.Strains.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("Strains.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A TextMeasurementType is a lookup type
|
||||
type TextMeasurementType struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
TextMeasurementName string `db:"text_measurement_name" json:"textMeasurementName"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
func (m *TextMeasurementType) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewTextMeasurementType() *TextMeasurementType {
|
||||
return &TextMeasurementType{
|
||||
TextMeasurementName: "Test Text Measurement Type",
|
||||
}
|
||||
}
|
||||
|
||||
type TextMeasurementTypesService interface {
|
||||
// Get a text measurement type
|
||||
Get(id int64) (*TextMeasurementType, error)
|
||||
|
||||
// List all text measurement types
|
||||
List(opt *TextMeasurementTypeListOptions) ([]*TextMeasurementType, error)
|
||||
|
||||
// Create a text measurement type
|
||||
Create(text_measurement_type *TextMeasurementType) (bool, error)
|
||||
|
||||
// Update a text measurement type
|
||||
Update(id int64, TextMeasurementType *TextMeasurementType) (updated bool, err error)
|
||||
|
||||
// Delete a text measurement type
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrTextMeasurementTypeNotFound = errors.New("text measurement type not found")
|
||||
)
|
||||
|
||||
type textMeasurementTypesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *textMeasurementTypesService) Get(id int64) (*TextMeasurementType, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.TextMeasurementType, 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 text_measurement_type *TextMeasurementType
|
||||
_, err = s.client.Do(req, &text_measurement_type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return text_measurement_type, nil
|
||||
}
|
||||
|
||||
func (s *textMeasurementTypesService) Create(text_measurement_type *TextMeasurementType) (bool, error) {
|
||||
url, err := s.client.url(router.CreateTextMeasurementType, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), text_measurement_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &text_measurement_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type TextMeasurementTypeListOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
func (s *textMeasurementTypesService) List(opt *TextMeasurementTypeListOptions) ([]*TextMeasurementType, error) {
|
||||
url, err := s.client.url(router.TextMeasurementTypes, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var text_measurement_types []*TextMeasurementType
|
||||
_, err = s.client.Do(req, &text_measurement_types)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return text_measurement_types, nil
|
||||
}
|
||||
|
||||
func (s *textMeasurementTypesService) Update(id int64, text_measurement_type *TextMeasurementType) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateTextMeasurementType, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), text_measurement_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &text_measurement_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *textMeasurementTypesService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteTextMeasurementType, 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 text_measurement_type *TextMeasurementType
|
||||
resp, err := s.client.Do(req, &text_measurement_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockTextMeasurementTypesService struct {
|
||||
Get_ func(id int64) (*TextMeasurementType, error)
|
||||
List_ func(opt *TextMeasurementTypeListOptions) ([]*TextMeasurementType, error)
|
||||
Create_ func(text_measurement_type *TextMeasurementType) (bool, error)
|
||||
Update_ func(id int64, text_measurement_type *TextMeasurementType) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ TextMeasurementTypesService = &MockTextMeasurementTypesService{}
|
||||
|
||||
func (s *MockTextMeasurementTypesService) Get(id int64) (*TextMeasurementType, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockTextMeasurementTypesService) Create(text_measurement_type *TextMeasurementType) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(text_measurement_type)
|
||||
}
|
||||
|
||||
func (s *MockTextMeasurementTypesService) List(opt *TextMeasurementTypeListOptions) ([]*TextMeasurementType, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockTextMeasurementTypesService) Update(id int64, text_measurement_type *TextMeasurementType) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, text_measurement_type)
|
||||
}
|
||||
|
||||
func (s *MockTextMeasurementTypesService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newTextMeasurementType() *TextMeasurementType {
|
||||
text_measurement_type := NewTextMeasurementType()
|
||||
text_measurement_type.Id = 1
|
||||
return text_measurement_type
|
||||
}
|
||||
|
||||
func TestTextMeasurementTypeService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newTextMeasurementType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.TextMeasurementType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
text_measurement_type, err := client.TextMeasurementTypes.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("TextMeasurementTypes.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(text_measurement_type, want) {
|
||||
t.Errorf("TextMeasurementTypes.Get return %+v, want %+v", text_measurement_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextMeasurementTypeService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newTextMeasurementType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateTextMeasurementType, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"id":1,"textMeasurementName":"Test Text Measurement Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
text_measurement_type := newTextMeasurementType()
|
||||
created, err := client.TextMeasurementTypes.Create(text_measurement_type)
|
||||
if err != nil {
|
||||
t.Errorf("TextMeasurementTypes.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(text_measurement_type, want) {
|
||||
t.Errorf("TextMeasurementTypes.Create returned %+v, want %+v", text_measurement_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextMeasurementTypeService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*TextMeasurementType{newTextMeasurementType()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.TextMeasurementTypes, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
text_measurement_type, err := client.TextMeasurementTypes.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("TextMeasurementTypes.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(text_measurement_type, want) {
|
||||
t.Errorf("TextMeasurementTypes.List return %+v, want %+v", text_measurement_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextMeasurementTypeService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newTextMeasurementType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateTextMeasurementType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"id":1,"textMeasurementName":"Test Text Measurement Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
text_measurement_type := newTextMeasurementType()
|
||||
text_measurement_type.TextMeasurementName = "Test Text Measurement Type Updated"
|
||||
updated, err := client.TextMeasurementTypes.Update(text_measurement_type.Id, text_measurement_type)
|
||||
if err != nil {
|
||||
t.Errorf("TextMeasurementTypes.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextMeasurementTypeService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newTextMeasurementType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteTextMeasurementType, 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.TextMeasurementTypes.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("TextMeasurementTypes.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
158
models/types.go
158
models/types.go
|
@ -1,158 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
type NullString struct {
|
||||
sql.NullString
|
||||
}
|
||||
|
||||
func (s *NullString) MarshalJSON() ([]byte, error) {
|
||||
if !s.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(s.String)
|
||||
}
|
||||
|
||||
func (s *NullString) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte("null")) {
|
||||
s.String = ""
|
||||
s.Valid = false
|
||||
return nil
|
||||
}
|
||||
var x interface{}
|
||||
var err error
|
||||
json.Unmarshal(b, &x)
|
||||
switch x.(type) {
|
||||
case string:
|
||||
err = json.Unmarshal(b, &s.String)
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(b, &s.NullString)
|
||||
}
|
||||
s.Valid = true
|
||||
return err
|
||||
}
|
||||
|
||||
type NullInt64 struct {
|
||||
sql.NullInt64
|
||||
}
|
||||
|
||||
func (i *NullInt64) MarshalJSON() ([]byte, error) {
|
||||
if !i.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(i.Int64)
|
||||
}
|
||||
|
||||
func (i *NullInt64) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte("null")) {
|
||||
i.Int64 = 0
|
||||
i.Valid = false
|
||||
return nil
|
||||
}
|
||||
var x interface{}
|
||||
var err error
|
||||
json.Unmarshal(b, &x)
|
||||
switch x.(type) {
|
||||
case float64:
|
||||
err = json.Unmarshal(b, &i.Int64)
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(b, &i.NullInt64)
|
||||
}
|
||||
i.Valid = true
|
||||
return err
|
||||
}
|
||||
|
||||
type NullFloat64 struct {
|
||||
sql.NullFloat64
|
||||
}
|
||||
|
||||
func (f *NullFloat64) MarshalJSON() ([]byte, error) {
|
||||
if !f.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(f.Float64)
|
||||
}
|
||||
|
||||
func (f *NullFloat64) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte("null")) {
|
||||
f.Float64 = 0
|
||||
f.Valid = false
|
||||
return nil
|
||||
}
|
||||
var x interface{}
|
||||
var err error
|
||||
json.Unmarshal(b, &x)
|
||||
switch x.(type) {
|
||||
case float64:
|
||||
err = json.Unmarshal(b, &f.Float64)
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(b, &f.NullFloat64)
|
||||
}
|
||||
f.Valid = true
|
||||
return err
|
||||
}
|
||||
|
||||
type NullTime struct {
|
||||
pq.NullTime
|
||||
}
|
||||
|
||||
func (t *NullTime) MarshalJSON() ([]byte, error) {
|
||||
if !t.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(t.Time)
|
||||
}
|
||||
|
||||
func (t *NullTime) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte("null")) {
|
||||
var nt time.Time
|
||||
t.Time = nt.In(time.UTC)
|
||||
t.Valid = false
|
||||
return nil
|
||||
}
|
||||
var x interface{}
|
||||
var err error
|
||||
json.Unmarshal(b, &x)
|
||||
switch x.(type) {
|
||||
case time.Time:
|
||||
err = json.Unmarshal(b, &t.Time)
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(b, &t.NullTime)
|
||||
}
|
||||
t.Valid = true
|
||||
return err
|
||||
}
|
||||
|
||||
type NullSliceInt64 []int64
|
||||
|
||||
func (i *NullSliceInt64) Scan(src interface{}) error {
|
||||
asBytes, ok := src.([]byte)
|
||||
if !ok {
|
||||
return errors.New("Scan source was not []byte")
|
||||
}
|
||||
asString := string(asBytes)
|
||||
(*i) = strToIntSlice(asString)
|
||||
return nil
|
||||
}
|
||||
|
||||
func strToIntSlice(s string) []int64 {
|
||||
r := strings.Trim(s, "{}")
|
||||
a := []int64(nil)
|
||||
if r != "NULL" {
|
||||
for _, t := range strings.Split(r, ",") {
|
||||
i, _ := strconv.ParseInt(t, 10, 64)
|
||||
a = append(a, i)
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A UnitType is a lookup type
|
||||
type UnitType struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Symbol string `db:"symbol" json:"symbol"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
func (m *UnitType) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewUnitType() *UnitType {
|
||||
return &UnitType{
|
||||
Name: "Test Unit Type",
|
||||
Symbol: "x",
|
||||
}
|
||||
}
|
||||
|
||||
type UnitTypesService interface {
|
||||
// Get a unit type
|
||||
Get(id int64) (*UnitType, error)
|
||||
|
||||
// List all unit types
|
||||
List(opt *UnitTypeListOptions) ([]*UnitType, error)
|
||||
|
||||
// Create a unit type
|
||||
Create(unit_type *UnitType) (bool, error)
|
||||
|
||||
// Update a unit type
|
||||
Update(id int64, UnitType *UnitType) (bool, error)
|
||||
|
||||
// Delete a unit type
|
||||
Delete(id int64) (deleted bool, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrUnitTypeNotFound = errors.New("unit type not found")
|
||||
)
|
||||
|
||||
type unitTypesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *unitTypesService) Get(id int64) (*UnitType, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UnitType, 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 unit_type *UnitType
|
||||
_, err = s.client.Do(req, &unit_type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unit_type, nil
|
||||
}
|
||||
|
||||
func (s *unitTypesService) Create(unit_type *UnitType) (bool, error) {
|
||||
url, err := s.client.url(router.CreateUnitType, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), unit_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &unit_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type UnitTypeListOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
func (s *unitTypesService) List(opt *UnitTypeListOptions) ([]*UnitType, error) {
|
||||
url, err := s.client.url(router.UnitTypes, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var unit_types []*UnitType
|
||||
_, err = s.client.Do(req, &unit_types)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unit_types, nil
|
||||
}
|
||||
|
||||
func (s *unitTypesService) Update(id int64, unit_type *UnitType) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.UpdateUnitType, map[string]string{"Id": strId}, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url.String(), unit_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &unit_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (s *unitTypesService) Delete(id int64) (bool, error) {
|
||||
strId := strconv.FormatInt(id, 10)
|
||||
|
||||
url, err := s.client.url(router.DeleteUnitType, 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 unit_type *UnitType
|
||||
resp, err := s.client.Do(req, &unit_type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, nil
|
||||
}
|
||||
|
||||
type MockUnitTypesService struct {
|
||||
Get_ func(id int64) (*UnitType, error)
|
||||
List_ func(opt *UnitTypeListOptions) ([]*UnitType, error)
|
||||
Create_ func(unit_type *UnitType) (bool, error)
|
||||
Update_ func(id int64, unit_type *UnitType) (bool, error)
|
||||
Delete_ func(id int64) (bool, error)
|
||||
}
|
||||
|
||||
var _ UnitTypesService = &MockUnitTypesService{}
|
||||
|
||||
func (s *MockUnitTypesService) Get(id int64) (*UnitType, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockUnitTypesService) Create(unit_type *UnitType) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(unit_type)
|
||||
}
|
||||
|
||||
func (s *MockUnitTypesService) List(opt *UnitTypeListOptions) ([]*UnitType, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockUnitTypesService) Update(id int64, unit_type *UnitType) (bool, error) {
|
||||
if s.Update_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Update_(id, unit_type)
|
||||
}
|
||||
|
||||
func (s *MockUnitTypesService) Delete(id int64) (bool, error) {
|
||||
if s.Delete_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Delete_(id)
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newUnitType() *UnitType {
|
||||
unit_type := NewUnitType()
|
||||
unit_type.Id = 1
|
||||
return unit_type
|
||||
}
|
||||
|
||||
func TestUnitTypeService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newUnitType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UnitType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
unit_type, err := client.UnitTypes.Get(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("UnitTypes.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(unit_type, want) {
|
||||
t.Errorf("UnitTypes.Get return %+v, want %+v", unit_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnitTypeService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newUnitType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateUnitType, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"id":1,"name":"Test Unit Type","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
unit_type := newUnitType()
|
||||
created, err := client.UnitTypes.Create(unit_type)
|
||||
if err != nil {
|
||||
t.Errorf("UnitTypes.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(unit_type, want) {
|
||||
t.Errorf("UnitTypes.Create returned %+v, want %+v", unit_type, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnitTypeService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*UnitType{newUnitType()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UnitTypes, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
unit_types, err := client.UnitTypes.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("UnitTypes.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(unit_types, want) {
|
||||
t.Errorf("UnitTypes.List return %+v, want %+v", unit_types, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnitTypeService_Update(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newUnitType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.UpdateUnitType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "PUT")
|
||||
testBody(t, r, `{"id":1,"name":"Test Unit Type Updated","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
unit_type := newUnitType()
|
||||
unit_type.Name = "Test Unit Type Updated"
|
||||
updated, err := client.UnitTypes.Update(unit_type.Id, unit_type)
|
||||
if err != nil {
|
||||
t.Errorf("UnitTypes.Update returned error: %v", err)
|
||||
}
|
||||
|
||||
if !updated {
|
||||
t.Error("!updated")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnitTypeService_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newUnitType()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.DeleteUnitType, 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.UnitTypes.Delete(want.Id)
|
||||
if err != nil {
|
||||
t.Errorf("UnitTypes.Delete returned error: %v", err)
|
||||
}
|
||||
|
||||
if !deleted {
|
||||
t.Error("!deleted")
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
}
|
191
models/users.go
191
models/users.go
|
@ -1,191 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
// A User is a person that has administrative access to bactdb.
|
||||
// Todo: add password
|
||||
type User struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Username string `db:"username" json:"username"`
|
||||
Password string `db:"password" json:"-"`
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
|
||||
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
|
||||
}
|
||||
|
||||
type UserJSON struct {
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
type UsersJSON struct {
|
||||
Users []*User `json:"users"`
|
||||
}
|
||||
|
||||
func (m *User) String() string {
|
||||
return fmt.Sprintf("%v", *m)
|
||||
}
|
||||
|
||||
func NewUser() *User {
|
||||
return &User{Username: "Test User"}
|
||||
}
|
||||
|
||||
// UsersService interacts with the user-related endpoints in bactdb's API.
|
||||
type UsersService interface {
|
||||
// Get a user.
|
||||
Get(id int64) (*User, error)
|
||||
|
||||
// List all users.
|
||||
List(opt *UserListOptions) ([]*User, error)
|
||||
|
||||
// Create a new user. The newly created user's ID is written to user.Id
|
||||
Create(user *User) (created bool, err error)
|
||||
|
||||
// Authenticate a user, returns their access level.
|
||||
Authenticate(username string, password string) (user_session *UserSession, err error)
|
||||
}
|
||||
|
||||
type UserSession struct {
|
||||
Token string `json:"token"`
|
||||
AccessLevel string `json:"access_level"`
|
||||
Genus string `json:"genus"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrUserNotFound = errors.New("user not found")
|
||||
)
|
||||
|
||||
type usersService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *usersService) Get(id int64) (*User, 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.User, 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 user *UserJSON
|
||||
_, err = s.client.Do(req, &user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user.User, nil
|
||||
}
|
||||
|
||||
func (s *usersService) Create(user *User) (bool, error) {
|
||||
url, err := s.client.url(router.CreateUser, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), UserJSON{User: user})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req, &user)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusCreated, nil
|
||||
}
|
||||
|
||||
type UserListOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
func (s *usersService) List(opt *UserListOptions) ([]*User, error) {
|
||||
url, err := s.client.url(router.Users, nil, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var users *UsersJSON
|
||||
_, err = s.client.Do(req, &users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users.Users, nil
|
||||
}
|
||||
|
||||
func (s *usersService) Authenticate(username string, password string) (*UserSession, error) {
|
||||
url, err := s.client.url(router.GetToken, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var user_session *UserSession
|
||||
_, err = s.client.Do(req, &user_session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user_session, nil
|
||||
}
|
||||
|
||||
type MockUsersService struct {
|
||||
Get_ func(id int64) (*User, error)
|
||||
List_ func(opt *UserListOptions) ([]*User, error)
|
||||
Create_ func(user *User) (bool, error)
|
||||
Authenticate_ func(username string, password string) (*UserSession, error)
|
||||
}
|
||||
|
||||
var _ UsersService = &MockUsersService{}
|
||||
|
||||
func (s *MockUsersService) Get(id int64) (*User, error) {
|
||||
if s.Get_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.Get_(id)
|
||||
}
|
||||
|
||||
func (s *MockUsersService) Create(user *User) (bool, error) {
|
||||
if s.Create_ == nil {
|
||||
return false, nil
|
||||
}
|
||||
return s.Create_(user)
|
||||
}
|
||||
|
||||
func (s *MockUsersService) List(opt *UserListOptions) ([]*User, error) {
|
||||
if s.List_ == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.List_(opt)
|
||||
}
|
||||
|
||||
func (s *MockUsersService) Authenticate(username string, password string) (*UserSession, error) {
|
||||
if s.Authenticate_ == nil {
|
||||
return &UserSession{}, nil
|
||||
}
|
||||
return s.Authenticate_(username, password)
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thermokarst/bactdb/router"
|
||||
)
|
||||
|
||||
func newUser() *User {
|
||||
user := NewUser()
|
||||
user.Id = 1
|
||||
return user
|
||||
}
|
||||
|
||||
func TestUsersService_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newUser()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.User, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
|
||||
writeJSON(w, UserJSON{User: want})
|
||||
})
|
||||
|
||||
user, err := client.Users.Get(1)
|
||||
if err != nil {
|
||||
t.Errorf("Users.Get returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
|
||||
|
||||
if !reflect.DeepEqual(user, want) {
|
||||
t.Errorf("Users.Get returned %+v, want %+v", user, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersService_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := newUser()
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.CreateUser, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "POST")
|
||||
testBody(t, r, `{"user":{"id":1,"username":"Test User","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}}`+"\n")
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
writeJSON(w, want)
|
||||
})
|
||||
|
||||
user := newUser()
|
||||
created, err := client.Users.Create(user)
|
||||
if err != nil {
|
||||
t.Errorf("Users.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(user, want) {
|
||||
t.Errorf("Users.Create returned %+v, want %+v", user, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersService_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []*User{newUser()}
|
||||
|
||||
var called bool
|
||||
mux.HandleFunc(urlPath(t, router.Users, nil), func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
testMethod(t, r, "GET")
|
||||
testFormValues(t, r, values{})
|
||||
|
||||
writeJSON(w, UsersJSON{Users: want})
|
||||
})
|
||||
|
||||
users, err := client.Users.List(nil)
|
||||
if err != nil {
|
||||
t.Errorf("Users.List returned error: %v", err)
|
||||
}
|
||||
|
||||
if !called {
|
||||
t.Fatal("!called")
|
||||
}
|
||||
|
||||
for _, u := range want {
|
||||
normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(users, want) {
|
||||
t.Errorf("Users.List return %+v, want %+v", users, want)
|
||||
}
|
||||
}
|
Reference in a new issue