Skip to content

Commit

Permalink
Add instance tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brycekahle committed Aug 24, 2017
1 parent a74fd80 commit aa670fd
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 16 deletions.
2 changes: 1 addition & 1 deletion api/api.go
Expand Up @@ -69,11 +69,11 @@ func NewAPIWithVersion(ctx context.Context, globalConfig *conf.GlobalConfigurati
r.Use(withRequestID)
r.UseBypass(newStructuredLogger(logrus.StandardLogger()))
r.Use(recoverer)
r.Use(withToken)

r.Get("/health", api.HealthCheck)

r.Route("/", func(r *router) {
r.Use(withToken)
if globalConfig.MultiInstanceMode {
r.Use(api.loadInstanceConfig)
}
Expand Down
139 changes: 139 additions & 0 deletions api/instance_test.go
@@ -0,0 +1,139 @@
package api

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/pborman/uuid"

"github.com/netlify/gocommerce/conf"
"github.com/netlify/gocommerce/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)

const testUUID = "11111111-1111-1111-1111-111111111111"
const operatorToken = "operatorToken"

type InstanceTestSuite struct {
suite.Suite
API *API
}

func (ts *InstanceTestSuite) SetupTest() {
globalConfig, err := conf.LoadGlobal("test.env")
require.NoError(ts.T(), err)
globalConfig.OperatorToken = operatorToken
globalConfig.MultiInstanceMode = true
db, err := models.Connect(globalConfig)
require.NoError(ts.T(), err)

api := NewAPI(globalConfig, db)
ts.API = api

// Cleanup existing instance
i, err := models.GetInstanceByUUID(db, testUUID)
if err == nil {
require.NoError(ts.T(), models.DeleteInstance(db, i))
}
}

func (ts *InstanceTestSuite) TestCreate() {
// Request body
var buffer bytes.Buffer
require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(map[string]interface{}{
"uuid": testUUID,
"site_url": "https://example.netlify.com",
"config": map[string]interface{}{
"jwt": map[string]interface{}{
"secret": "testsecret",
},
},
}))

// Setup request
req := httptest.NewRequest(http.MethodPost, "http://localhost/instances", &buffer)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+operatorToken)

// Setup response recorder
w := httptest.NewRecorder()

ts.API.handler.ServeHTTP(w, req)
require.Equal(ts.T(), http.StatusCreated, w.Code)
resp := models.Instance{}
require.NoError(ts.T(), json.NewDecoder(w.Body).Decode(&resp))
assert.NotNil(ts.T(), resp.BaseConfig)

i, err := models.GetInstanceByUUID(ts.API.db, testUUID)
require.NoError(ts.T(), err)
assert.NotNil(ts.T(), i.BaseConfig)
}

func (ts *InstanceTestSuite) TestGet() {
instanceID := uuid.NewRandom().String()
err := models.CreateInstance(ts.API.db, &models.Instance{
ID: instanceID,
UUID: testUUID,
BaseConfig: &conf.Configuration{
JWT: conf.JWTConfiguration{
Secret: "testsecret",
},
},
})
require.NoError(ts.T(), err)

req := httptest.NewRequest(http.MethodGet, "http://localhost/instances/"+instanceID, nil)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+operatorToken)

w := httptest.NewRecorder()
ts.API.handler.ServeHTTP(w, req)
require.Equal(ts.T(), http.StatusOK, w.Code)
resp := models.Instance{}
require.NoError(ts.T(), json.NewDecoder(w.Body).Decode(&resp))

assert.Equal(ts.T(), "testsecret", resp.BaseConfig.JWT.Secret)
}

func (ts *InstanceTestSuite) TestUpdate() {
instanceID := uuid.NewRandom().String()
err := models.CreateInstance(ts.API.db, &models.Instance{
ID: instanceID,
UUID: testUUID,
BaseConfig: &conf.Configuration{
JWT: conf.JWTConfiguration{
Secret: "testsecret",
},
},
})
require.NoError(ts.T(), err)

var buffer bytes.Buffer
require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(map[string]interface{}{
"config": &conf.Configuration{
SiteURL: "https://test.mysite.com",
},
}))

req := httptest.NewRequest(http.MethodPut, "http://localhost/instances/"+instanceID, &buffer)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+operatorToken)

w := httptest.NewRecorder()
ts.API.handler.ServeHTTP(w, req)
require.Equal(ts.T(), http.StatusOK, w.Code)

i, err := models.GetInstanceByUUID(ts.API.db, testUUID)
require.NoError(ts.T(), err)
require.Equal(ts.T(), "testsecret", i.BaseConfig.JWT.Secret)
require.Equal(ts.T(), "https://test.mysite.com", i.BaseConfig.SiteURL)
}

func TestInstance(t *testing.T) {
suite.Run(t, new(InstanceTestSuite))
}
11 changes: 11 additions & 0 deletions api/test.env
@@ -0,0 +1,11 @@
GOCOMMERCE_JWT_SECRET=testsecret
GOCOMMERCE_JWT_EXP=3600
GOCOMMERCE_JWT_AUD=api.netlify.com
GOCOMMERCE_DB_DRIVER=sqlite3
GOCOMMERCE_DB_AUTOMIGRATE=true
GOCOMMERCE_DB_DATABASE_URL=test.db
GOCOMMERCE_API_HOST=localhost
PORT=9999
GOCOMMERCE_LOG_LEVEL=error
GOCOMMERCE_SITE_URL=https://example.netlify.com
GOCOMMERCE_OPERATOR_TOKEN=foobar
16 changes: 9 additions & 7 deletions conf/configuration.go
Expand Up @@ -17,6 +17,12 @@ type DBConfiguration struct {
Automigrate bool
}

// JWTConfiguration holds all the JWT related configuration.
type JWTConfiguration struct {
Secret string `json:"secret"`
AdminGroupName string `json:"admin_group_name" split_words:"true"`
}

// GlobalConfiguration holds all the global configuration for gocommerce
type GlobalConfiguration struct {
API struct {
Expand All @@ -38,12 +44,8 @@ type EmailContentConfiguration struct {

// Configuration holds all the per-tenant configuration for gocommerce
type Configuration struct {
SiteURL string `json:"site_url" split_words:"true"`

JWT struct {
Secret string `json:"secret"`
AdminGroupName string `json:"admin_group_name" split_words:"true"`
} `json:"jwt"`
SiteURL string `json:"site_url" split_words:"true"`
JWT JWTConfiguration `json:"jwt"`

Mailer struct {
Host string `json:"host"`
Expand Down Expand Up @@ -103,7 +105,7 @@ func loadEnvironment(filename string) error {
return err
}

// LoadGlobal will construct the core config from the file `config.json`
// LoadGlobal will construct the core config from the file
func LoadGlobal(filename string) (*GlobalConfiguration, error) {
if err := loadEnvironment(filename); err != nil {
return nil, err
Expand Down
5 changes: 3 additions & 2 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions glide.yaml
Expand Up @@ -49,3 +49,4 @@ testImport:
subpackages:
- assert
- require
- suite
9 changes: 3 additions & 6 deletions models/instance.go
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/json"
"time"

"github.com/imdario/mergo"
"github.com/jinzhu/gorm"
"github.com/netlify/gocommerce/conf"
"github.com/pkg/errors"
Expand Down Expand Up @@ -59,13 +58,11 @@ func (i *Instance) Config() (*conf.Configuration, error) {
return nil, errors.New("no configuration data available")
}

baseConf := conf.Configuration{}
if err := mergo.MergeWithOverwrite(&baseConf, i.BaseConfig); err != nil {
return nil, err
}
baseConf := &conf.Configuration{}
*baseConf = *i.BaseConfig
baseConf.ApplyDefaults()

return &baseConf, nil
return baseConf, nil
}

// GetInstance finds an instance by ID
Expand Down

0 comments on commit aa670fd

Please sign in to comment.