Rebooting

This commit is contained in:
Matthew Dillon 2015-03-20 15:52:29 -08:00
parent 41ee2857ee
commit 6030310caa
149 changed files with 1489 additions and 9755 deletions

View file

@ -1,101 +0,0 @@
package api
import (
"errors"
"net/http"
"os"
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/gorilla/mux"
)
const (
tokenName = "AccessToken"
)
var (
verifyKey, signKey []byte
errWhileSigningToken = errors.New("error while signing token")
errPleaseLogIn = errors.New("please log in")
errWhileParsingCookie = errors.New("error while parsing cookie")
errTokenExpired = errors.New("token expired")
errGenericError = errors.New("generic error")
errAccessDenied = errors.New("insufficient privileges")
)
func SetupCerts() error {
signkey := os.Getenv("PRIVATE_KEY")
if signkey == "" {
return errors.New("please set PRIVATE_KEY")
}
signKey = []byte(signkey)
verifykey := os.Getenv("PUBLIC_KEY")
if verifykey == "" {
return errors.New("please set PUBLIC_KEY")
}
verifyKey = []byte(verifykey)
return nil
}
type authHandler func(http.ResponseWriter, *http.Request) error
// Only accessible with a valid token
func (h authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Even though writeJSON sets the content type, we need to set it here because
// calls to WriteHeader write out the entire header.
w.Header().Set("content-type", "application/json; charset=utf-8")
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
w.WriteHeader(http.StatusUnauthorized)
writeJSON(w, Error{errPleaseLogIn})
return
}
s := strings.Split(authHeader, " ")
// Validate the token
token, err := jwt.Parse(s[1], func(token *jwt.Token) (interface{}, error) {
return []byte(verifyKey), nil
})
// Branch out into the possible error from signing
switch err.(type) {
case nil: // No error
if !token.Valid { // But may still be invalid
w.WriteHeader(http.StatusUnauthorized)
writeJSON(w, Error{errPleaseLogIn})
return
}
case *jwt.ValidationError: // Something was wrong during the validation
vErr := err.(*jwt.ValidationError)
switch vErr.Errors {
case jwt.ValidationErrorExpired:
w.WriteHeader(http.StatusUnauthorized)
writeJSON(w, Error{errTokenExpired})
return
default:
w.WriteHeader(http.StatusInternalServerError)
writeJSON(w, Error{errGenericError})
return
}
default: // Something else went wrong
w.WriteHeader(http.StatusInternalServerError)
writeJSON(w, Error{errGenericError})
return
}
genus := mux.Vars(r)["genus"]
// We don't care about this if we aren't accessing one of the subrouter routes.
if genus != "" && genus != token.Claims["genus"] {
w.WriteHeader(http.StatusInternalServerError)
writeJSON(w, Error{errAccessDenied})
return
}
hErr := h(w, r)
if hErr != nil {
w.WriteHeader(http.StatusInternalServerError)
writeJSON(w, Error{hErr})
}
}

View file

@ -1,92 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveCharacteristicType(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
characteristic_type, err := store.CharacteristicTypes.Get(id)
if err != nil {
return err
}
return writeJSON(w, characteristic_type)
}
func serveCreateCharacteristicType(w http.ResponseWriter, r *http.Request) error {
var characteristic_type models.CharacteristicType
err := json.NewDecoder(r.Body).Decode(&characteristic_type)
if err != nil {
return err
}
created, err := store.CharacteristicTypes.Create(&characteristic_type)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, characteristic_type)
}
func serveCharacteristicTypeList(w http.ResponseWriter, r *http.Request) error {
var opt models.CharacteristicTypeListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
characteristic_types, err := store.CharacteristicTypes.List(&opt)
if err != nil {
return err
}
if characteristic_types == nil {
characteristic_types = []*models.CharacteristicType{}
}
return writeJSON(w, characteristic_types)
}
func serveUpdateCharacteristicType(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var characteristic_type models.CharacteristicType
err := json.NewDecoder(r.Body).Decode(&characteristic_type)
if err != nil {
return err
}
updated, err := store.CharacteristicTypes.Update(id, &characteristic_type)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, characteristic_type)
}
func serveDeleteCharacteristicType(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.CharacteristicTypes.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, &models.CharacteristicType{})
}

View file

@ -1,153 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newCharacteristicType() *models.CharacteristicType {
characteristic_type := models.NewCharacteristicType()
return characteristic_type
}
func TestCharacteristicType_Get(t *testing.T) {
setup()
want := newCharacteristicType()
calledGet := false
store.CharacteristicTypes.(*models.MockCharacteristicTypesService).Get_ = func(id int64) (*models.CharacteristicType, error) {
if id != want.Id {
t.Errorf("wanted request for characteristic_type %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.CharacteristicTypes.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got %+v but wanted %+v", got, want)
}
}
func TestCharacteristicType_Create(t *testing.T) {
setup()
want := newCharacteristicType()
calledPost := false
store.CharacteristicTypes.(*models.MockCharacteristicTypesService).Create_ = func(characteristic_type *models.CharacteristicType) (bool, error) {
if !normalizeDeepEqual(want, characteristic_type) {
t.Errorf("wanted request for characteristic_type %d but got %d", want, characteristic_type)
}
calledPost = true
return true, nil
}
success, err := apiClient.CharacteristicTypes.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestCharacteristicType_List(t *testing.T) {
setup()
want := []*models.CharacteristicType{newCharacteristicType()}
wantOpt := &models.CharacteristicTypeListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.CharacteristicTypes.(*models.MockCharacteristicTypesService).List_ = func(opt *models.CharacteristicTypeListOptions) ([]*models.CharacteristicType, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
characteristic_types, err := apiClient.CharacteristicTypes.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &characteristic_types) {
t.Errorf("got characteristic_types %+v but wanted characteristic_types %+v", characteristic_types, want)
}
}
func TestCharacteristicType_Update(t *testing.T) {
setup()
want := newCharacteristicType()
calledPut := false
store.CharacteristicTypes.(*models.MockCharacteristicTypesService).Update_ = func(id int64, characteristic_type *models.CharacteristicType) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for characteristic_type %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, characteristic_type) {
t.Errorf("wanted request for characteristic_type %d but got %d", want, characteristic_type)
}
calledPut = true
return true, nil
}
success, err := apiClient.CharacteristicTypes.Update(want.Id, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestCharacteristicType_Delete(t *testing.T) {
setup()
want := newCharacteristicType()
calledDelete := false
store.CharacteristicTypes.(*models.MockCharacteristicTypesService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for characteristic_type %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.CharacteristicTypes.Delete(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,92 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveCharacteristic(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
characteristic, err := store.Characteristics.Get(id)
if err != nil {
return err
}
return writeJSON(w, models.CharacteristicJSON{Characteristic: characteristic})
}
func serveCreateCharacteristic(w http.ResponseWriter, r *http.Request) error {
var characteristic models.CharacteristicJSON
err := json.NewDecoder(r.Body).Decode(&characteristic)
if err != nil {
return err
}
created, err := store.Characteristics.Create(characteristic.Characteristic)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, characteristic)
}
func serveCharacteristicList(w http.ResponseWriter, r *http.Request) error {
var opt models.CharacteristicListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
characteristics, err := store.Characteristics.List(&opt)
if err != nil {
return err
}
if characteristics == nil {
characteristics = []*models.Characteristic{}
}
return writeJSON(w, models.CharacteristicsJSON{Characteristics: characteristics})
}
func serveUpdateCharacteristic(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var characteristic models.CharacteristicJSON
err := json.NewDecoder(r.Body).Decode(&characteristic)
if err != nil {
return err
}
updated, err := store.Characteristics.Update(id, characteristic.Characteristic)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, characteristic)
}
func serveDeleteCharacteristic(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.Characteristics.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, nil)
}

View file

@ -1,153 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newCharacteristic() *models.Characteristic {
characteristic := models.NewCharacteristic()
return characteristic
}
func TestCharacteristic_Get(t *testing.T) {
setup()
want := newCharacteristic()
calledGet := false
store.Characteristics.(*models.MockCharacteristicsService).Get_ = func(id int64) (*models.Characteristic, error) {
if id != want.Id {
t.Errorf("wanted request for characteristic %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.Characteristics.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got %+v but wanted %+v", got, want)
}
}
func TestCharacteristic_Create(t *testing.T) {
setup()
want := newCharacteristic()
calledPost := false
store.Characteristics.(*models.MockCharacteristicsService).Create_ = func(characteristic *models.Characteristic) (bool, error) {
if !normalizeDeepEqual(want, characteristic) {
t.Errorf("wanted request for characteristic %d but got %d", want, characteristic)
}
calledPost = true
return true, nil
}
success, err := apiClient.Characteristics.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestCharacteristic_List(t *testing.T) {
setup()
want := []*models.Characteristic{newCharacteristic()}
wantOpt := &models.CharacteristicListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.Characteristics.(*models.MockCharacteristicsService).List_ = func(opt *models.CharacteristicListOptions) ([]*models.Characteristic, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
characteristics, err := apiClient.Characteristics.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &characteristics) {
t.Errorf("got characteristics %+v but wanted characteristics %+v", characteristics, want)
}
}
func TestCharacteristic_Update(t *testing.T) {
setup()
want := newCharacteristic()
calledPut := false
store.Characteristics.(*models.MockCharacteristicsService).Update_ = func(id int64, characteristic *models.Characteristic) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for characteristic %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, characteristic) {
t.Errorf("wanted request for characteristic %d but got %d", want, characteristic)
}
calledPut = true
return true, nil
}
success, err := apiClient.Characteristics.Update(want.Id, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestCharacteristic_Delete(t *testing.T) {
setup()
want := newCharacteristic()
calledDelete := false
store.Characteristics.(*models.MockCharacteristicsService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for characteristic %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.Characteristics.Delete(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,94 +0,0 @@
package api
import (
"encoding/json"
"strconv"
"github.com/gorilla/mux"
"net/http"
"github.com/thermokarst/bactdb/models"
)
func serveGenus(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
genus, err := store.Genera.Get(id)
if err != nil {
return err
}
return writeJSON(w, models.GenusJSON{Genus: genus})
}
func serveCreateGenus(w http.ResponseWriter, r *http.Request) error {
var genus models.GenusJSON
err := json.NewDecoder(r.Body).Decode(&genus)
if err != nil {
return err
}
created, err := store.Genera.Create(genus.Genus)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, genus)
}
func serveGenera(w http.ResponseWriter, r *http.Request) error {
var opt models.GenusListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
genera, err := store.Genera.List(&opt)
if err != nil {
return err
}
if genera == nil {
genera = []*models.Genus{}
}
return writeJSON(w, models.GeneraJSON{Genera: genera})
}
func serveUpdateGenus(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var genus models.GenusJSON
err := json.NewDecoder(r.Body).Decode(&genus)
if err != nil {
return err
}
updated, err := store.Genera.Update(id, genus.Genus)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, genus)
}
func serveDeleteGenus(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.Genera.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, nil)
}

View file

@ -1,152 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newGenus() *models.Genus {
genus := models.NewGenus()
genus.Id = 1
return genus
}
func TestGenus_Get(t *testing.T) {
setup()
want := newGenus()
calledGet := false
store.Genera.(*models.MockGeneraService).Get_ = func(id int64) (*models.Genus, error) {
if id != want.Id {
t.Errorf("wanted request for genus %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.Genera.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got genus %+v but wanted genus %+v", got, want)
}
}
func TestGenus_Create(t *testing.T) {
setup()
want := newGenus()
calledPost := false
store.Genera.(*models.MockGeneraService).Create_ = func(genus *models.Genus) (bool, error) {
if !normalizeDeepEqual(want, genus) {
t.Errorf("wanted request for genus %d but got %d", want, genus)
}
calledPost = true
return true, nil
}
success, err := apiClient.Genera.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestGenus_List(t *testing.T) {
setup()
want := []*models.Genus{newGenus()}
wantOpt := &models.GenusListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.Genera.(*models.MockGeneraService).List_ = func(opt *models.GenusListOptions) ([]*models.Genus, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
genera, err := apiClient.Genera.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &genera) {
t.Errorf("got genera %+v but wanted genera %+v", genera, want)
}
}
func TestGenus_Update(t *testing.T) {
setup()
want := newGenus()
calledPut := false
store.Genera.(*models.MockGeneraService).Update_ = func(id int64, genus *models.Genus) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for genus %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, genus) {
t.Errorf("wanted request for genus %d but got %d", want, genus)
}
calledPut = true
return true, nil
}
success, err := apiClient.Genera.Update(1, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestGenus_Delete(t *testing.T) {
setup()
want := newGenus()
calledDelete := false
store.Genera.(*models.MockGeneraService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for genus %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.Genera.Delete(1)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,94 +0,0 @@
package api
import (
"net/http"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/thermokarst/bactdb/datastore"
"github.com/thermokarst/bactdb/router"
)
var (
store = datastore.NewDatastore(nil)
schemaDecoder = schema.NewDecoder()
)
func Handler() *mux.Router {
m := router.API()
m.Get(router.User).Handler(authHandler(serveUser))
m.Get(router.CreateUser).Handler(authHandler(serveCreateUser))
m.Get(router.Users).Handler(authHandler(serveUsers))
m.Get(router.GetToken).Handler(handler(serveAuthenticateUser))
m.Get(router.Genus).Handler(authHandler(serveGenus))
m.Get(router.CreateGenus).Handler(authHandler(serveCreateGenus))
m.Get(router.Genera).Handler(authHandler(serveGenera))
m.Get(router.UpdateGenus).Handler(authHandler(serveUpdateGenus))
m.Get(router.DeleteGenus).Handler(authHandler(serveDeleteGenus))
m.Get(router.Species).Handler(authHandler(serveSpecies))
m.Get(router.CreateSpecies).Handler(authHandler(serveCreateSpecies))
m.Get(router.SpeciesList).Handler(authHandler(serveSpeciesList))
m.Get(router.UpdateSpecies).Handler(authHandler(serveUpdateSpecies))
m.Get(router.DeleteSpecies).Handler(authHandler(serveDeleteSpecies))
m.Get(router.Strain).Handler(authHandler(serveStrain))
m.Get(router.CreateStrain).Handler(authHandler(serveCreateStrain))
m.Get(router.Strains).Handler(authHandler(serveStrainList))
m.Get(router.UpdateStrain).Handler(authHandler(serveUpdateStrain))
m.Get(router.DeleteStrain).Handler(authHandler(serveDeleteStrain))
m.Get(router.CharacteristicType).Handler(authHandler(serveCharacteristicType))
m.Get(router.CreateCharacteristicType).Handler(authHandler(serveCreateCharacteristicType))
m.Get(router.CharacteristicTypes).Handler(authHandler(serveCharacteristicTypeList))
m.Get(router.UpdateCharacteristicType).Handler(authHandler(serveUpdateCharacteristicType))
m.Get(router.DeleteCharacteristicType).Handler(authHandler(serveDeleteCharacteristicType))
m.Get(router.Characteristic).Handler(authHandler(serveCharacteristic))
m.Get(router.CreateCharacteristic).Handler(authHandler(serveCreateCharacteristic))
m.Get(router.Characteristics).Handler(authHandler(serveCharacteristicList))
m.Get(router.UpdateCharacteristic).Handler(authHandler(serveUpdateCharacteristic))
m.Get(router.DeleteCharacteristic).Handler(authHandler(serveDeleteCharacteristic))
m.Get(router.TextMeasurementType).Handler(authHandler(serveTextMeasurementType))
m.Get(router.CreateTextMeasurementType).Handler(authHandler(serveCreateTextMeasurementType))
m.Get(router.TextMeasurementTypes).Handler(authHandler(serveTextMeasurementTypeList))
m.Get(router.UpdateTextMeasurementType).Handler(authHandler(serveUpdateTextMeasurementType))
m.Get(router.DeleteTextMeasurementType).Handler(authHandler(serveDeleteTextMeasurementType))
m.Get(router.UnitType).Handler(authHandler(serveUnitType))
m.Get(router.CreateUnitType).Handler(authHandler(serveCreateUnitType))
m.Get(router.UnitTypes).Handler(authHandler(serveUnitTypeList))
m.Get(router.UpdateUnitType).Handler(authHandler(serveUpdateUnitType))
m.Get(router.DeleteUnitType).Handler(authHandler(serveDeleteUnitType))
m.Get(router.Measurement).Handler(authHandler(serveMeasurement))
m.Get(router.CreateMeasurement).Handler(authHandler(serveCreateMeasurement))
m.Get(router.Measurements).Handler(authHandler(serveMeasurementList))
m.Get(router.UpdateMeasurement).Handler(authHandler(serveUpdateMeasurement))
m.Get(router.DeleteMeasurement).Handler(authHandler(serveDeleteMeasurement))
m.Get(router.SubrouterListSpecies).Handler(authHandler(serveSubrouterSpeciesList))
m.Get(router.SubrouterListStrains).Handler(authHandler(serveSubrouterStrainsList))
m.Get(router.SubrouterListMeasurements).Handler(authHandler(serveSubrouterMeasurementsList))
m.Get(router.Health).Handler(handler(healthHandler))
return m
}
type handler func(http.ResponseWriter, *http.Request) error
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := h(w, r)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
writeJSON(w, Error{err})
}
}
func healthHandler(w http.ResponseWriter, r *http.Request) error {
return writeJSON(w, Message{"great success"})
}

View file

@ -1,37 +0,0 @@
package api
import (
"encoding/json"
"log"
"net/http"
)
// writeJSON writes a JSON Content-Type header and a JSON-encoded object to
// the http.ResponseWriter.
func writeJSON(w http.ResponseWriter, v interface{}) error {
data, err := json.MarshalIndent(v, "", " ")
if err != nil {
return err
}
w.Header().Set("content-type", "application/json; charset=utf-8")
_, err = w.Write(data)
return err
}
// Message is for returning simple message payloads to the user
type Message struct {
Message string `json:"message"`
}
// Error is for returning simple error payloads to the user, as well as logging
type Error struct {
Error error
}
func (e Error) MarshalJSON() ([]byte, error) {
log.Println(e.Error)
return json.Marshal(struct {
Error string `json:"error"`
}{e.Error.Error()})
}

View file

@ -1,25 +0,0 @@
package api
import (
"encoding/json"
"fmt"
"reflect"
)
// Helper function that normalizes structs for comparison with reflect.DeepEqual
func normalize(v interface{}) {
j, err := json.Marshal(v)
if err != nil {
panic(fmt.Sprintf("Could not normalize object %+v due to JSON marshalling error: %s", v, err))
}
err = json.Unmarshal(j, v)
if err != nil {
panic(fmt.Sprintf("Could not normalize object %+v due to JSON un-marshalling error: %s", v, err))
}
}
func normalizeDeepEqual(u, v interface{}) bool {
normalize(u)
normalize(v)
return reflect.DeepEqual(u, v)
}

View file

@ -1,111 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveMeasurement(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
measurement, err := store.Measurements.Get(id)
if err != nil {
return err
}
return writeJSON(w, models.MeasurementJSON{Measurement: measurement})
}
func serveCreateMeasurement(w http.ResponseWriter, r *http.Request) error {
var measurement models.MeasurementJSON
err := json.NewDecoder(r.Body).Decode(&measurement)
if err != nil {
return err
}
created, err := store.Measurements.Create(measurement.Measurement)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, measurement)
}
func serveMeasurementList(w http.ResponseWriter, r *http.Request) error {
var opt models.MeasurementListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
measurements, err := store.Measurements.List(&opt)
if err != nil {
return err
}
if measurements == nil {
measurements = []*models.Measurement{}
}
return writeJSON(w, models.MeasurementsJSON{Measurements: measurements})
}
func serveUpdateMeasurement(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var measurement models.MeasurementJSON
err := json.NewDecoder(r.Body).Decode(&measurement)
if err != nil {
return err
}
updated, err := store.Measurements.Update(id, measurement.Measurement)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, measurement)
}
func serveDeleteMeasurement(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.Measurements.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, nil)
}
func serveSubrouterMeasurementsList(w http.ResponseWriter, r *http.Request) error {
var opt models.MeasurementListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
opt.Genus = mux.Vars(r)["genus"]
measurements, err := store.Measurements.List(&opt)
if err != nil {
return err
}
if measurements == nil {
measurements = []*models.Measurement{}
}
return writeJSON(w, models.MeasurementsJSON{Measurements: measurements})
}

View file

@ -1,160 +0,0 @@
package api
import (
"database/sql"
"testing"
"github.com/thermokarst/bactdb/models"
)
func newMeasurement() *models.Measurement {
measurement := models.NewMeasurement()
measurement.Id = 1
measurement.StrainId = 2
measurement.CharacteristicId = 3
measurement.TextMeasurementTypeId = models.NullInt64{sql.NullInt64{Int64: 4, Valid: false}}
measurement.UnitTypeId = models.NullInt64{sql.NullInt64{Int64: 5, Valid: true}}
measurement.Notes = models.NullString{sql.NullString{String: "a note", Valid: true}}
return measurement
}
func TestMeasurement_Get(t *testing.T) {
setup()
want := newMeasurement()
calledGet := false
store.Measurements.(*models.MockMeasurementsService).Get_ = func(id int64) (*models.Measurement, error) {
if id != want.Id {
t.Errorf("wanted request for measurement %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.Measurements.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got %+v but wanted %+v", got, want)
}
}
func TestMeasurement_Create(t *testing.T) {
setup()
want := newMeasurement()
calledPost := false
store.Measurements.(*models.MockMeasurementsService).Create_ = func(measurement *models.Measurement) (bool, error) {
if !normalizeDeepEqual(want, measurement) {
t.Errorf("wanted request for measurement %d but got %d", want, measurement)
}
calledPost = true
return true, nil
}
success, err := apiClient.Measurements.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestMeasurement_List(t *testing.T) {
setup()
want := []*models.Measurement{newMeasurement()}
wantOpt := &models.MeasurementListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.Measurements.(*models.MockMeasurementsService).List_ = func(opt *models.MeasurementListOptions) ([]*models.Measurement, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
measurements, err := apiClient.Measurements.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &measurements) {
t.Errorf("got measurements %+v but wanted measurements %+v", measurements, want)
}
}
func TestMeasurement_Update(t *testing.T) {
setup()
want := newMeasurement()
calledPut := false
store.Measurements.(*models.MockMeasurementsService).Update_ = func(id int64, measurement *models.Measurement) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for measurement %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, measurement) {
t.Errorf("wanted request for measurement %d but got %d", want, measurement)
}
calledPut = true
return true, nil
}
success, err := apiClient.Measurements.Update(want.Id, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestMeasurement_Delete(t *testing.T) {
setup()
want := newMeasurement()
calledDelete := false
store.Measurements.(*models.MockMeasurementsService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for measurement %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.Measurements.Delete(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,97 +0,0 @@
package api
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"github.com/thermokarst/bactdb/datastore"
"github.com/thermokarst/bactdb/models"
"github.com/thermokarst/bactdb/router"
)
func init() {
signKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyXi+Q3rVv+NkBi3UWBXyylUN5SyHxQUtZvhbA6TwcF2fk3Io
Di3kipVWbfYAYijIxczACieCnadSynJpH4zNVJsRxp8DTG67Nx/K5n3TJyg5hLpa
PE+46lOS7E0O9JPT119zKCGHtHldpgjsPCXGHRXKZdFafSv8ktFhwvK5ZQO1NjH2
+NOsfhp2ubuQXL7O/45fC5wTCj0lLatdXtlTcIxJb7FUj3AsAC7TlKhtkKe+Syox
n1xNMQiYK1R24+goW44JO5uZDYP85ufgRn+DdOQF9DskmiQN9/REhH/5VQjEIYZ3
kjmKlNnjz3Jd1eOdtGALxTq3+neVawWMPBXOcQIDAQABAoIBAHMAYhKgrhxPTwwb
4ua4+JK4BCt5xLIYp3bscv9cigaJ2onOksCtP5Q/dEtmLYfaYehOXJwvO2aEWUTI
E+t3cslFjtsCb16UonbvxeDVl871LgfuW42rsBDJzcbmoY/IRhbdHB2fLhg9YtBg
rYATy8dUZejCnNVwY0bnD9e4t0zJ0lXUVy+dMvl69uNyP8f12LwvLGgCmAOWXh5p
NpGmT8/jRF9BrQvr9bhwxpV2JGsGEEyGvu+ayVR01AiyQ04kh9gZOJOVtsGa1fjx
AvgxzhkfLyAbCAgFTTUuhEbZoxXyCNBdOM0V3PXSbIbW+7gwLwXi71Czo08V050z
5SK9p2UCgYEA8JW+xIaAzYT+ZwPaJ/Ir1+WcisEI+AyCD1c5gblHrCmSwYHdKSX4
ZcX0QAcj+dzuF6SyQStoy1pIooUzadDZxXeyBoeOjGdyobqJpmaEHb9g594w2inS
AsEb4waxvrKlTuhFXnI2JbJrbMyjRBTKWZw4K/FT73IE8hQL9ivXYN8CgYEA1mFu
uLD95N/KOFtQ0JcLUelPZK7gYSdq21YHSbABeeesvabnn3hFEzDl5cXqKFJ/4Ltf
2QhpO4JGgHYNlrsfCvvivV5dRxFKfleoojL/0qlJxOqQVfulscT0XB3wUpoyP+Qr
8AdyvZwUfLWpSaYxDUB7w77U1VayP5JLuULKKq8CgYBOge8QnnullUKXRzCHXIVm
HG1q8fcFSr+eVe5UIKv8yEw1jTUoWlWmkGRWCH566NdhK8NndMzrnviY4DKY0yhd
QeP8MXwY4SENGZwVitqOAoeS4nS6nG8FqxJ4kRSrkAxVpYINgeOdhY18oYKdktM9
Trcdz9B+EI0Amf4VRNUxrQKBgQCTBXTagr9MhFF5vt44fy3LOhcxtGC7ID4/N8t9
tI/+m2yzD9DPY7rzg1hW8Rk6GAINDFOaUxNgNWLGXK/LDH8omEASoLGVuHz/Enza
5+DcBy9JNZhQ72jd9nWi6wFSlN8bRA8B6Qm+kVjXgfocQTZooS1/u9LYkEFkKZ92
6SAejwKBgH6V+dLUefC9w6N99VWpOAom9gE96imo1itTKxIB1WPdFsSDDe/CGXDG
W+l7ZiSjXaAfNF5UtuhO6yY0ob++Aa/d+l+Zo7CWn4SrmwTAp1CdRHxX3KxkqHNi
BsuYClbQh5Z9lOKn8FCNW3NyahJdYeWGhb/ZdeS0n+F6Ov4V+grc
-----END RSA PRIVATE KEY-----`)
verifyKey = []byte(`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyXi+Q3rVv+NkBi3UWBXy
ylUN5SyHxQUtZvhbA6TwcF2fk3IoDi3kipVWbfYAYijIxczACieCnadSynJpH4zN
VJsRxp8DTG67Nx/K5n3TJyg5hLpaPE+46lOS7E0O9JPT119zKCGHtHldpgjsPCXG
HRXKZdFafSv8ktFhwvK5ZQO1NjH2+NOsfhp2ubuQXL7O/45fC5wTCj0lLatdXtlT
cIxJb7FUj3AsAC7TlKhtkKe+Syoxn1xNMQiYK1R24+goW44JO5uZDYP85ufgRn+D
dOQF9DskmiQN9/REhH/5VQjEIYZ3kjmKlNnjz3Jd1eOdtGALxTq3+neVawWMPBXO
cQIDAQAB
-----END PUBLIC KEY-----`)
serveMux.Handle("/", http.StripPrefix("/api", Handler()))
}
var (
serveMux = http.NewServeMux()
httpClient = http.Client{
Transport: (*muxTransport)(serveMux),
}
apiClient = models.NewClient(&httpClient)
testToken models.UserSession
)
func setup() {
store = datastore.NewMockDatastore()
u, _ := apiClient.URL(router.GetToken, nil, nil)
resp, _ := httpClient.PostForm(u.String(),
url.Values{"username": {"test_user"}, "password": {"password"}})
defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&testToken); err != nil {
panic(err)
}
}
type muxTransport http.ServeMux
// RoundTrip is for testing API requests. It intercepts all requests during testing
// to serve up a local/internal response.
func (t *muxTransport) RoundTrip(req *http.Request) (*http.Response, error) {
rw := httptest.NewRecorder()
rw.Body = new(bytes.Buffer)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", testToken.Token))
(*http.ServeMux)(t).ServeHTTP(rw, req)
return &http.Response{
StatusCode: rw.Code,
Status: http.StatusText(rw.Code),
Header: rw.HeaderMap,
Body: ioutil.NopCloser(rw.Body),
ContentLength: int64(rw.Body.Len()),
Request: req,
}, nil
}

View file

@ -1,111 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveSpecies(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
species, err := store.Species.Get(id)
if err != nil {
return err
}
return writeJSON(w, models.SpeciesJSON{species})
}
func serveCreateSpecies(w http.ResponseWriter, r *http.Request) error {
var species models.SpeciesJSON
err := json.NewDecoder(r.Body).Decode(&species)
if err != nil {
return err
}
created, err := store.Species.Create(species.Species)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, species)
}
func serveSpeciesList(w http.ResponseWriter, r *http.Request) error {
var opt models.SpeciesListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
species, err := store.Species.List(&opt)
if err != nil {
return err
}
if species == nil {
species = []*models.Species{}
}
return writeJSON(w, models.SpeciesListJSON{Species: species})
}
func serveUpdateSpecies(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var species models.SpeciesJSON
err := json.NewDecoder(r.Body).Decode(&species)
if err != nil {
return err
}
updated, err := store.Species.Update(id, species.Species)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, species)
}
func serveDeleteSpecies(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.Species.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, nil)
}
func serveSubrouterSpeciesList(w http.ResponseWriter, r *http.Request) error {
var opt models.SpeciesListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
opt.Genus = mux.Vars(r)["genus"]
species, err := store.Species.List(&opt)
if err != nil {
return err
}
if species == nil {
species = []*models.Species{}
}
return writeJSON(w, models.SpeciesListJSON{Species: species})
}

View file

@ -1,154 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newSpecies() *models.Species {
species := models.NewSpecies()
species.Id = 1
species.GenusId = 1
return species
}
func TestSpecies_Get(t *testing.T) {
setup()
want := newSpecies()
calledGet := false
store.Species.(*models.MockSpeciesService).Get_ = func(id int64) (*models.Species, error) {
if id != want.Id {
t.Errorf("wanted request for species %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.Species.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got species %+v but wanted species %+v", got, want)
}
}
func TestSpecies_Create(t *testing.T) {
setup()
want := newSpecies()
calledPost := false
store.Species.(*models.MockSpeciesService).Create_ = func(species *models.Species) (bool, error) {
if !normalizeDeepEqual(want, species) {
t.Errorf("wanted request for species %d but got %d", want, species)
}
calledPost = true
return true, nil
}
success, err := apiClient.Species.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestSpecies_List(t *testing.T) {
setup()
want := []*models.Species{newSpecies()}
wantOpt := &models.SpeciesListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.Species.(*models.MockSpeciesService).List_ = func(opt *models.SpeciesListOptions) ([]*models.Species, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
species, err := apiClient.Species.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &species) {
t.Errorf("got species %+v but wanted species %+v", species, want)
}
}
func TestSpecies_Update(t *testing.T) {
setup()
want := newSpecies()
calledPut := false
store.Species.(*models.MockSpeciesService).Update_ = func(id int64, species *models.Species) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for species %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, species) {
t.Errorf("wanted request for species %d but got %d", want, species)
}
calledPut = true
return true, nil
}
success, err := apiClient.Species.Update(1, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestSpecies_Delete(t *testing.T) {
setup()
want := newSpecies()
calledDelete := false
store.Species.(*models.MockSpeciesService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for species %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.Species.Delete(1)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,111 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveStrain(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
strain, err := store.Strains.Get(id)
if err != nil {
return err
}
return writeJSON(w, models.StrainJSON{Strain: strain})
}
func serveCreateStrain(w http.ResponseWriter, r *http.Request) error {
var strain models.StrainJSON
err := json.NewDecoder(r.Body).Decode(&strain)
if err != nil {
return err
}
created, err := store.Strains.Create(strain.Strain)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, strain)
}
func serveStrainList(w http.ResponseWriter, r *http.Request) error {
var opt models.StrainListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
strains, err := store.Strains.List(&opt)
if err != nil {
return err
}
if strains == nil {
strains = []*models.Strain{}
}
return writeJSON(w, models.StrainsJSON{Strains: strains})
}
func serveUpdateStrain(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var strain models.StrainJSON
err := json.NewDecoder(r.Body).Decode(&strain)
if err != nil {
return err
}
updated, err := store.Strains.Update(id, strain.Strain)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, strain)
}
func serveDeleteStrain(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.Strains.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, nil)
}
func serveSubrouterStrainsList(w http.ResponseWriter, r *http.Request) error {
var opt models.StrainListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
opt.Genus = mux.Vars(r)["genus"]
strains, err := store.Strains.List(&opt)
if err != nil {
return err
}
if strains == nil {
strains = []*models.Strain{}
}
return writeJSON(w, models.StrainsJSON{Strains: strains})
}

View file

@ -1,155 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newStrain() *models.Strain {
strain := models.NewStrain()
strain.Id = 1
strain.SpeciesId = 1
return strain
}
func TestStrain_Get(t *testing.T) {
setup()
want := newStrain()
calledGet := false
store.Strains.(*models.MockStrainsService).Get_ = func(id int64) (*models.Strain, error) {
if id != want.Id {
t.Errorf("wanted request for strain %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.Strains.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
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")
}
}
func TestStrain_List(t *testing.T) {
setup()
want := []*models.Strain{newStrain()}
wantOpt := &models.StrainListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.Strains.(*models.MockStrainsService).List_ = func(opt *models.StrainListOptions) ([]*models.Strain, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
strains, err := apiClient.Strains.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &strains) {
t.Errorf("got strains %+v but wanted strains %+v", strains, want)
}
}
func TestStrain_Update(t *testing.T) {
setup()
want := newStrain()
calledPut := false
store.Strains.(*models.MockStrainsService).Update_ = func(id int64, strain *models.Strain) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for strain %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, strain) {
t.Errorf("wanted request for strain %d but got %d", want, strain)
}
calledPut = true
return true, nil
}
success, err := apiClient.Strains.Update(1, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestStrain_Delete(t *testing.T) {
setup()
want := newStrain()
calledDelete := false
store.Strains.(*models.MockStrainsService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for strain %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.Strains.Delete(1)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,92 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveTextMeasurementType(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
text_measurement_type, err := store.TextMeasurementTypes.Get(id)
if err != nil {
return err
}
return writeJSON(w, text_measurement_type)
}
func serveCreateTextMeasurementType(w http.ResponseWriter, r *http.Request) error {
var text_measurement_type models.TextMeasurementType
err := json.NewDecoder(r.Body).Decode(&text_measurement_type)
if err != nil {
return err
}
created, err := store.TextMeasurementTypes.Create(&text_measurement_type)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, text_measurement_type)
}
func serveTextMeasurementTypeList(w http.ResponseWriter, r *http.Request) error {
var opt models.TextMeasurementTypeListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
text_measurement_types, err := store.TextMeasurementTypes.List(&opt)
if err != nil {
return err
}
if text_measurement_types == nil {
text_measurement_types = []*models.TextMeasurementType{}
}
return writeJSON(w, text_measurement_types)
}
func serveUpdateTextMeasurementType(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var text_measurement_type models.TextMeasurementType
err := json.NewDecoder(r.Body).Decode(&text_measurement_type)
if err != nil {
return err
}
updated, err := store.TextMeasurementTypes.Update(id, &text_measurement_type)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, text_measurement_type)
}
func serveDeleteTextMeasurementType(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.TextMeasurementTypes.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, &models.TextMeasurementType{})
}

View file

@ -1,153 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newTextMeasurementType() *models.TextMeasurementType {
text_measurement_type := models.NewTextMeasurementType()
return text_measurement_type
}
func TestTextMeasurementType_Get(t *testing.T) {
setup()
want := newTextMeasurementType()
calledGet := false
store.TextMeasurementTypes.(*models.MockTextMeasurementTypesService).Get_ = func(id int64) (*models.TextMeasurementType, error) {
if id != want.Id {
t.Errorf("wanted request for text_measurement_type %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.TextMeasurementTypes.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got %+v but wanted %+v", got, want)
}
}
func TestTextMeasurementType_Create(t *testing.T) {
setup()
want := newTextMeasurementType()
calledPost := false
store.TextMeasurementTypes.(*models.MockTextMeasurementTypesService).Create_ = func(text_measurement_type *models.TextMeasurementType) (bool, error) {
if !normalizeDeepEqual(want, text_measurement_type) {
t.Errorf("wanted request for text_measurement_type %d but got %d", want, text_measurement_type)
}
calledPost = true
return true, nil
}
success, err := apiClient.TextMeasurementTypes.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestTextMeasurementType_List(t *testing.T) {
setup()
want := []*models.TextMeasurementType{newTextMeasurementType()}
wantOpt := &models.TextMeasurementTypeListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.TextMeasurementTypes.(*models.MockTextMeasurementTypesService).List_ = func(opt *models.TextMeasurementTypeListOptions) ([]*models.TextMeasurementType, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
text_measurement_types, err := apiClient.TextMeasurementTypes.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &text_measurement_types) {
t.Errorf("got text_measurement_types %+v but wanted text_measurement_types %+v", text_measurement_types, want)
}
}
func TestTextMeasurementType_Update(t *testing.T) {
setup()
want := newTextMeasurementType()
calledPut := false
store.TextMeasurementTypes.(*models.MockTextMeasurementTypesService).Update_ = func(id int64, text_measurement_type *models.TextMeasurementType) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for text_measurement_type %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, text_measurement_type) {
t.Errorf("wanted request for text_measurement_type %d but got %d", want, text_measurement_type)
}
calledPut = true
return true, nil
}
success, err := apiClient.TextMeasurementTypes.Update(want.Id, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestTextMeasurementType_Delete(t *testing.T) {
setup()
want := newTextMeasurementType()
calledDelete := false
store.TextMeasurementTypes.(*models.MockTextMeasurementTypesService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for text_measurement_type %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.TextMeasurementTypes.Delete(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,92 +0,0 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveUnitType(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
unit_type, err := store.UnitTypes.Get(id)
if err != nil {
return err
}
return writeJSON(w, unit_type)
}
func serveCreateUnitType(w http.ResponseWriter, r *http.Request) error {
var unit_type models.UnitType
err := json.NewDecoder(r.Body).Decode(&unit_type)
if err != nil {
return err
}
created, err := store.UnitTypes.Create(&unit_type)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, unit_type)
}
func serveUnitTypeList(w http.ResponseWriter, r *http.Request) error {
var opt models.UnitTypeListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
unit_types, err := store.UnitTypes.List(&opt)
if err != nil {
return err
}
if unit_types == nil {
unit_types = []*models.UnitType{}
}
return writeJSON(w, unit_types)
}
func serveUpdateUnitType(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
var unit_type models.UnitType
err := json.NewDecoder(r.Body).Decode(&unit_type)
if err != nil {
return err
}
updated, err := store.UnitTypes.Update(id, &unit_type)
if err != nil {
return err
}
if updated {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, unit_type)
}
func serveDeleteUnitType(w http.ResponseWriter, r *http.Request) error {
id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
deleted, err := store.UnitTypes.Delete(id)
if err != nil {
return err
}
if deleted {
w.WriteHeader(http.StatusOK)
}
return writeJSON(w, &models.UnitType{})
}

View file

@ -1,153 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newUnitType() *models.UnitType {
unit_type := models.NewUnitType()
return unit_type
}
func TestUnitType_Get(t *testing.T) {
setup()
want := newUnitType()
calledGet := false
store.UnitTypes.(*models.MockUnitTypesService).Get_ = func(id int64) (*models.UnitType, error) {
if id != want.Id {
t.Errorf("wanted request for unit_type %d but got %d", want.Id, id)
}
calledGet = true
return want, nil
}
got, err := apiClient.UnitTypes.Get(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(want, got) {
t.Errorf("got %+v but wanted %+v", got, want)
}
}
func TestUnitType_Create(t *testing.T) {
setup()
want := newUnitType()
calledPost := false
store.UnitTypes.(*models.MockUnitTypesService).Create_ = func(unit_type *models.UnitType) (bool, error) {
if !normalizeDeepEqual(want, unit_type) {
t.Errorf("wanted request for unit_type %d but got %d", want, unit_type)
}
calledPost = true
return true, nil
}
success, err := apiClient.UnitTypes.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestUnitType_List(t *testing.T) {
setup()
want := []*models.UnitType{newUnitType()}
wantOpt := &models.UnitTypeListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.UnitTypes.(*models.MockUnitTypesService).List_ = func(opt *models.UnitTypeListOptions) ([]*models.UnitType, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return want, nil
}
unit_types, err := apiClient.UnitTypes.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&want, &unit_types) {
t.Errorf("got unit_types %+v but wanted unit_types %+v", unit_types, want)
}
}
func TestUnitType_Update(t *testing.T) {
setup()
want := newUnitType()
calledPut := false
store.UnitTypes.(*models.MockUnitTypesService).Update_ = func(id int64, unit_type *models.UnitType) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for unit_type %d but got %d", want.Id, id)
}
if !normalizeDeepEqual(want, unit_type) {
t.Errorf("wanted request for unit_type %d but got %d", want, unit_type)
}
calledPut = true
return true, nil
}
success, err := apiClient.UnitTypes.Update(want.Id, want)
if err != nil {
t.Fatal(err)
}
if !calledPut {
t.Error("!calledPut")
}
if !success {
t.Error("!success")
}
}
func TestUnitType_Delete(t *testing.T) {
setup()
want := newUnitType()
calledDelete := false
store.UnitTypes.(*models.MockUnitTypesService).Delete_ = func(id int64) (bool, error) {
if id != want.Id {
t.Errorf("wanted request for unit_type %d but got %d", want.Id, id)
}
calledDelete = true
return true, nil
}
success, err := apiClient.UnitTypes.Delete(want.Id)
if err != nil {
t.Fatal(err)
}
if !calledDelete {
t.Error("!calledDelete")
}
if !success {
t.Error("!success")
}
}

View file

@ -1,87 +0,0 @@
package api
import (
"encoding/json"
"strconv"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gorilla/mux"
"net/http"
"github.com/thermokarst/bactdb/models"
)
func serveUser(w http.ResponseWriter, r *http.Request) error {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
if err != nil {
return err
}
user, err := store.Users.Get(id)
if err != nil {
return err
}
return writeJSON(w, models.UserJSON{user})
}
func serveCreateUser(w http.ResponseWriter, r *http.Request) error {
var user models.UserJSON
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
return err
}
created, err := store.Users.Create(user.User)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, user)
}
func serveUsers(w http.ResponseWriter, r *http.Request) error {
var opt models.UserListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
return err
}
users, err := store.Users.List(&opt)
if err != nil {
return err
}
if users == nil {
users = []*models.User{}
}
return writeJSON(w, models.UsersJSON{Users: users})
}
func serveAuthenticateUser(w http.ResponseWriter, r *http.Request) error {
username := r.FormValue("username")
password := r.FormValue("password")
user_session, err := store.Users.Authenticate(username, password)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return err
}
t := jwt.New(jwt.GetSigningMethod("RS256"))
t.Claims["auth_level"] = user_session.AccessLevel
t.Claims["genus"] = user_session.Genus
t.Claims["exp"] = time.Now().Add(time.Minute * 60 * 24).Unix()
tokenString, err := t.SignedString(signKey)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return err
}
user_session.Token = tokenString
return writeJSON(w, user_session)
}

View file

@ -1,127 +0,0 @@
package api
import (
"testing"
"github.com/thermokarst/bactdb/models"
)
func newUser() *models.User {
user := models.NewUser()
user.Id = 1
return user
}
func TestUser_Get(t *testing.T) {
setup()
wantUser := newUser()
calledGet := false
store.Users.(*models.MockUsersService).Get_ = func(id int64) (*models.User, error) {
if id != wantUser.Id {
t.Errorf("wanted request for user %d but got %d", wantUser.Id, id)
}
calledGet = true
return wantUser, nil
}
gotUser, err := apiClient.Users.Get(wantUser.Id)
if err != nil {
t.Fatal(err)
}
if !calledGet {
t.Error("!calledGet")
}
if !normalizeDeepEqual(wantUser, gotUser) {
t.Errorf("got user %+v but wanted user %+v", wantUser, gotUser)
}
}
func TestUser_Create(t *testing.T) {
setup()
wantUser := newUser()
calledPost := false
store.Users.(*models.MockUsersService).Create_ = func(user *models.User) (bool, error) {
if !normalizeDeepEqual(wantUser, user) {
t.Errorf("wanted request for user %d but got %d", wantUser, user)
}
calledPost = true
return true, nil
}
success, err := apiClient.Users.Create(wantUser)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}
func TestUser_List(t *testing.T) {
setup()
wantUsers := []*models.User{newUser()}
wantOpt := &models.UserListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
calledList := false
store.Users.(*models.MockUsersService).List_ = func(opt *models.UserListOptions) ([]*models.User, error) {
if !normalizeDeepEqual(wantOpt, opt) {
t.Errorf("wanted options %d but got %d", wantOpt, opt)
}
calledList = true
return wantUsers, nil
}
users, err := apiClient.Users.List(wantOpt)
if err != nil {
t.Fatal(err)
}
if !calledList {
t.Error("!calledList")
}
if !normalizeDeepEqual(&wantUsers, &users) {
t.Errorf("got users %+v but wanted users %+v", users, wantUsers)
}
}
func TestUser_Authenticate(t *testing.T) {
setup()
test_user := newUser()
test_user.Username = "test_user"
var user_session_want models.UserSession
calledAuthenticate := false
store.Users.(*models.MockUsersService).Authenticate_ = func(username string, password string) (*models.UserSession, error) {
calledAuthenticate = true
user_session_want.AccessLevel = "read"
user_session_want.Genus = "hymenobacter"
return &user_session_want, nil
}
user_session, err := apiClient.Users.Authenticate(test_user.Username, "password")
if err != nil {
t.Fatal(err)
}
if !calledAuthenticate {
t.Error("!calledAuthenticate")
}
if !normalizeDeepEqual(user_session, &user_session_want) {
t.Errorf("got session %+v but wanted session %+v", user_session, user_session_want)
}
}