Create a strain.
This commit is contained in:
		
							parent
							
								
									6c118f47f7
								
							
						
					
					
						commit
						6bba9058aa
					
				
					 9 changed files with 146 additions and 2 deletions
				
			
		|  | @ -36,6 +36,7 @@ func Handler() *mux.Router { | ||||||
| 	m.Get(router.DeleteSpecies).Handler(handler(serveDeleteSpecies)) | 	m.Get(router.DeleteSpecies).Handler(handler(serveDeleteSpecies)) | ||||||
| 
 | 
 | ||||||
| 	m.Get(router.Strain).Handler(handler(serveStrain)) | 	m.Get(router.Strain).Handler(handler(serveStrain)) | ||||||
|  | 	m.Get(router.CreateStrain).Handler(handler(serveCreateStrain)) | ||||||
| 
 | 
 | ||||||
| 	return m | 	return m | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,12 @@ | ||||||
| package api | package api | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/json" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	"github.com/gorilla/mux" | 	"github.com/gorilla/mux" | ||||||
|  | 	"github.com/thermokarst/bactdb/models" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func serveStrain(w http.ResponseWriter, r *http.Request) error { | func serveStrain(w http.ResponseWriter, r *http.Request) error { | ||||||
|  | @ -20,3 +22,21 @@ func serveStrain(w http.ResponseWriter, r *http.Request) error { | ||||||
| 
 | 
 | ||||||
| 	return writeJSON(w, strain) | 	return writeJSON(w, strain) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func serveCreateStrain(w http.ResponseWriter, r *http.Request) error { | ||||||
|  | 	var strain models.Strain | ||||||
|  | 	err := json.NewDecoder(r.Body).Decode(&strain) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	created, err := store.Strains.Create(&strain) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if created { | ||||||
|  | 		w.WriteHeader(http.StatusCreated) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return writeJSON(w, strain) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -40,3 +40,30 @@ func TestStrain_Get(t *testing.T) { | ||||||
| 		t.Errorf("got strain %+v but wanted strain %+v", got, want) | 		t.Errorf("got strain %+v but wanted strain %+v", got, want) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestStrain_Create(t *testing.T) { | ||||||
|  | 	setup() | ||||||
|  | 
 | ||||||
|  | 	want := newStrain() | ||||||
|  | 
 | ||||||
|  | 	calledPost := false | ||||||
|  | 	store.Strains.(*models.MockStrainsService).Create_ = func(strain *models.Strain) (bool, error) { | ||||||
|  | 		if !normalizeDeepEqual(want, strain) { | ||||||
|  | 			t.Errorf("wanted request for strain %d but got %d", want, strain) | ||||||
|  | 		} | ||||||
|  | 		calledPost = true | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	success, err := apiClient.Strains.Create(want) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !calledPost { | ||||||
|  | 		t.Error("!calledPost") | ||||||
|  | 	} | ||||||
|  | 	if !success { | ||||||
|  | 		t.Error("!success") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -20,3 +20,10 @@ func (s *strainsStore) Get(id int64) (*models.Strain, error) { | ||||||
| 	} | 	} | ||||||
| 	return strain[0], nil | 	return strain[0], nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (s *strainsStore) Create(strain *models.Strain) (bool, error) { | ||||||
|  | 	if err := s.dbh.Insert(strain); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -45,3 +45,23 @@ func TestStrainsStore_Get_db(t *testing.T) { | ||||||
| 		t.Errorf("got strain %+v, want %+v", strain, want) | 		t.Errorf("got strain %+v, want %+v", strain, want) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestStrainsStore_Create_db(t *testing.T) { | ||||||
|  | 	tx, _ := DB.Begin() | ||||||
|  | 	defer tx.Rollback() | ||||||
|  | 
 | ||||||
|  | 	strain := newStrain(t, tx) | ||||||
|  | 
 | ||||||
|  | 	d := NewDatastore(tx) | ||||||
|  | 
 | ||||||
|  | 	created, err := d.Strains.Create(strain) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	if !created { | ||||||
|  | 		t.Error("!created") | ||||||
|  | 	} | ||||||
|  | 	if strain.Id == 0 { | ||||||
|  | 		t.Error("want nonzero strain.Id after submitting") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ package models | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"net/http" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | @ -30,6 +31,9 @@ func NewStrain() *Strain { | ||||||
| type StrainsService interface { | type StrainsService interface { | ||||||
| 	// Get a strain | 	// Get a strain | ||||||
| 	Get(id int64) (*Strain, error) | 	Get(id int64) (*Strain, error) | ||||||
|  | 
 | ||||||
|  | 	// Create a strain record | ||||||
|  | 	Create(strain *Strain) (bool, error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
|  | @ -62,8 +66,28 @@ func (s *strainsService) Get(id int64) (*Strain, error) { | ||||||
| 	return strain, nil | 	return 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(), 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 MockStrainsService struct { | type MockStrainsService struct { | ||||||
| 	Get_    func(id int64) (*Strain, error) | 	Get_    func(id int64) (*Strain, error) | ||||||
|  | 	Create_ func(strain *Strain) (bool, error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var _ StrainsService = &MockStrainsService{} | var _ StrainsService = &MockStrainsService{} | ||||||
|  | @ -74,3 +98,10 @@ func (s *MockStrainsService) Get(id int64) (*Strain, error) { | ||||||
| 	} | 	} | ||||||
| 	return s.Get_(id) | 	return s.Get_(id) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (s *MockStrainsService) Create(strain *Strain) (bool, error) { | ||||||
|  | 	if s.Create_ == nil { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 	return s.Create_(strain) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -44,3 +44,39 @@ func TestStrainService_Get(t *testing.T) { | ||||||
| 		t.Errorf("Strain.Get return %+v, want %+v", 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, `{"id":1,"species_id":1,"strain_name":"Test Strain","strain_type":"Test Type","etymology":"Test Etymology","accession_banks":"Test Accession","genbank_eml_ddb":"Test Genbank","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":"0001-01-01T00:00:00Z"}`+"\n") | ||||||
|  | 
 | ||||||
|  | 		w.WriteHeader(http.StatusCreated) | ||||||
|  | 		writeJSON(w, want) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ func API() *mux.Router { | ||||||
| 	m.Path("/species/{Id:.+}").Methods("DELETE").Name(DeleteSpecies) | 	m.Path("/species/{Id:.+}").Methods("DELETE").Name(DeleteSpecies) | ||||||
| 
 | 
 | ||||||
| 	// Strains | 	// Strains | ||||||
|  | 	m.Path("/strains").Methods("POST").Name(CreateStrain) | ||||||
| 	m.Path("/strains/{Id:.+}").Methods("GET").Name(Strain) | 	m.Path("/strains/{Id:.+}").Methods("GET").Name(Strain) | ||||||
| 
 | 
 | ||||||
| 	return m | 	return m | ||||||
|  |  | ||||||
|  | @ -18,4 +18,5 @@ const ( | ||||||
| 	DeleteSpecies = "species:delete" | 	DeleteSpecies = "species:delete" | ||||||
| 
 | 
 | ||||||
| 	Strain       = "strain:get" | 	Strain       = "strain:get" | ||||||
|  | 	CreateStrain = "strain:create" | ||||||
| ) | ) | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon