Skip to content

Commit

Permalink
Replace gorm with pop for db access
Browse files Browse the repository at this point in the history
Change model IDs to UUIDs
Remove `deleted_at` from instances model
  • Loading branch information
brycekahle committed Jan 8, 2018
1 parent 1031987 commit 47cc9ce
Show file tree
Hide file tree
Showing 45 changed files with 589 additions and 491 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.env
gorm.db
vendor/
gotrue

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ migrate_test: ## Run database migrations for test.
hack/migrate.sh test

test: ## Run tests.
go test -v $(CHECK_FILES)
go test -p 1 -v $(CHECK_FILES)

vet: # Vet the code
go vet $(CHECK_FILES)
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,16 @@ DATABASE_URL=root@localhost/gotrue

`DB_DRIVER` - `string` **required**

Chooses what dialect of database you want. Choose from `mysql` or `postgres`.
Chooses what dialect of database you want. Must be `mysql`.

`DATABASE_URL` (no prefix) / `DB_DATABASE_URL` - `string` **required**

Connection string for the database. See the [gorm examples](https://github.com/jinzhu/gorm/blob/gh-pages/documents/database.md) for more details.
Connection string for the database.

`DB_NAMESPACE` - `string`

Adds a prefix to all table names.

`DB_AUTOMIGRATE` - `bool`

If enabled, creates missing tables and columns upon startup.

### Logging

```
Expand Down
7 changes: 6 additions & 1 deletion api/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/go-chi/chi"
"github.com/netlify/gotrue/models"
uuid "github.com/satori/go.uuid"
)

type adminUserParams struct {
Expand All @@ -20,7 +21,11 @@ type adminUserParams struct {
}

func (a *API) loadUser(w http.ResponseWriter, r *http.Request) (context.Context, error) {
userID := chi.URLParam(r, "user_id")
userID, err := uuid.FromString(chi.URLParam(r, "user_id"))
if err != nil {
return nil, badRequestError("user_id must be an UUID")
}

logEntrySetField(r, "user_id", userID)
instanceID := getInstanceID(r.Context())

Expand Down
19 changes: 14 additions & 5 deletions api/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
jwt "github.com/dgrijalva/jwt-go"
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/netlify/gotrue/storage/test"
uuid "github.com/satori/go.uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
Expand All @@ -25,7 +25,7 @@ type AdminTestSuite struct {
Config *conf.Configuration

token string
instanceID string
instanceID uuid.UUID
}

func TestAdmin(t *testing.T) {
Expand All @@ -37,12 +37,14 @@ func TestAdmin(t *testing.T) {
Config: config,
instanceID: instanceID,
}
defer api.db.Close()
//defer api.db.DropDB()

suite.Run(t, ts)
}

func (ts *AdminTestSuite) SetupTest() {
test.CleanupTables()
ts.API.db.TruncateAll()
ts.token = ts.makeSuperAdmin("[email protected]")
}

Expand Down Expand Up @@ -70,7 +72,7 @@ func (ts *AdminTestSuite) makeSuperAdmin(email string) string {
}

func (ts *AdminTestSuite) makeSystemUser() string {
u := models.NewSystemUser("", ts.Config.JWT.Aud)
u := models.NewSystemUser(uuid.Nil, ts.Config.JWT.Aud)

token, err := generateAccessToken(u, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
require.NoError(ts.T(), err, "Error generating access token")
Expand Down Expand Up @@ -107,6 +109,7 @@ func (ts *AdminTestSuite) TestAdminUsers() {
assert.Equal(ts.T(), "</admin/users?page=1>; rel=\"last\"", w.HeaderMap.Get("Link"))
assert.Equal(ts.T(), "1", w.HeaderMap.Get("X-Total-Count"))

fmt.Println(w.Body)
data := struct {
Users []*models.User `json:"users"`
Aud string `json:"aud"`
Expand Down Expand Up @@ -153,6 +156,8 @@ func (ts *AdminTestSuite) TestAdminUsers_SortAsc() {
u, err := models.NewUser(ts.instanceID, "[email protected]", "test", ts.Config.JWT.Aud, nil)
require.NoError(ts.T(), err, "Error making new user")

// if the created_at times are the same, then the sort order is not guaranteed
time.Sleep(1 * time.Second)
require.NoError(ts.T(), ts.API.db.CreateUser(u), "Error creating user")

// Setup request
Expand Down Expand Up @@ -182,6 +187,8 @@ func (ts *AdminTestSuite) TestAdminUsers_SortAsc() {
func (ts *AdminTestSuite) TestAdminUsers_SortDesc() {
u, err := models.NewUser(ts.instanceID, "[email protected]", "test", ts.Config.JWT.Aud, nil)
require.NoError(ts.T(), err, "Error making new user")
// if the created_at times are the same, then the sort order is not guaranteed
time.Sleep(1 * time.Second)
require.NoError(ts.T(), ts.API.db.CreateUser(u), "Error creating user")

// Setup request
Expand Down Expand Up @@ -279,7 +286,7 @@ func (ts *AdminTestSuite) TestAdminUserCreate() {

// TestAdminUserGet tests API /admin/user route (GET)
func (ts *AdminTestSuite) TestAdminUserGet() {
u, err := models.NewUser(ts.instanceID, "[email protected]", "test", ts.Config.JWT.Aud, nil)
u, err := models.NewUser(ts.instanceID, "[email protected]", "test", ts.Config.JWT.Aud, map[string]interface{}{"full_name": "Test Get User"})
require.NoError(ts.T(), err, "Error making new user")
require.NoError(ts.T(), ts.API.db.CreateUser(u), "Error creating user")

Expand All @@ -298,6 +305,8 @@ func (ts *AdminTestSuite) TestAdminUserGet() {
assert.Equal(ts.T(), data["email"], "[email protected]")
assert.NotNil(ts.T(), data["app_metadata"])
assert.NotNil(ts.T(), data["user_metadata"])
md := data["user_metadata"].(map[string]interface{})
assert.Equal(ts.T(), "Test Get User", md["full_name"])
}

// TestAdminUserUpdate tests API /admin/user route (UPDATE)
Expand Down
5 changes: 3 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/netlify/gotrue/storage/dial"
"github.com/netlify/netlify-commons/graceful"
"github.com/rs/cors"
uuid "github.com/satori/go.uuid"
"github.com/sebest/xff"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -155,7 +156,7 @@ func NewAPIFromConfigFile(filename string, version string) (*API, *conf.Configur
return nil, nil, err
}

ctx, err := WithInstanceConfig(context.Background(), globalConfig.SMTP, config, "")
ctx, err := WithInstanceConfig(context.Background(), globalConfig.SMTP, config, uuid.Nil)
if err != nil {
logrus.Fatalf("Error loading instance config: %+v", err)
}
Expand All @@ -176,7 +177,7 @@ func (a *API) HealthCheck(w http.ResponseWriter, r *http.Request) error {
})
}

func WithInstanceConfig(ctx context.Context, smtp conf.SMTPConfiguration, config *conf.Configuration, instanceID string) (context.Context, error) {
func WithInstanceConfig(ctx context.Context, smtp conf.SMTPConfiguration, config *conf.Configuration, instanceID uuid.UUID) (context.Context, error) {
ctx = withConfig(ctx, config)

mailer := mailer.NewMailer(smtp, config)
Expand Down
57 changes: 47 additions & 10 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ package api

import (
"context"
"math/rand"
"time"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/netlify/gotrue/storage"
"github.com/netlify/gotrue/storage/test"
"github.com/pborman/uuid"
"github.com/satori/go.uuid"
)

const (
apiTestVersion = "1"
apiTestConfig = "../hack/test.env"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

// setupAPIForTest creates a new API to run tests with.
// Using this function allows us to keep track of the database connection
// and cleaning up data between tests.
Expand All @@ -23,17 +29,17 @@ func setupAPIForTest() (*API, *conf.Configuration, error) {
}

func setupAPIForMultiinstanceTest() (*API, *conf.Configuration, error) {
cb := func(gc *conf.GlobalConfiguration, c *conf.Configuration, conn storage.Connection) (string, error) {
cb := func(gc *conf.GlobalConfiguration, c *conf.Configuration, conn storage.Connection) (uuid.UUID, error) {
gc.MultiInstanceMode = true
return "", nil
return uuid.Nil, nil
}

return setupAPIForTestWithCallback(cb)
}

func setupAPIForTestForInstance() (*API, *conf.Configuration, string, error) {
instanceID := uuid.NewRandom().String()
cb := func(gc *conf.GlobalConfiguration, c *conf.Configuration, conn storage.Connection) (string, error) {
func setupAPIForTestForInstance() (*API, *conf.Configuration, uuid.UUID, error) {
instanceID := uuid.Must(uuid.NewV4())
cb := func(gc *conf.GlobalConfiguration, c *conf.Configuration, conn storage.Connection) (uuid.UUID, error) {
err := conn.CreateInstance(&models.Instance{
ID: instanceID,
UUID: testUUID,
Expand All @@ -44,34 +50,65 @@ func setupAPIForTestForInstance() (*API, *conf.Configuration, string, error) {

api, conf, err := setupAPIForTestWithCallback(cb)
if err != nil {
return nil, nil, "", err
return nil, nil, uuid.Nil, err
}
return api, conf, instanceID, nil
}

func setupAPIForTestWithCallback(cb func(*conf.GlobalConfiguration, *conf.Configuration, storage.Connection) (string, error)) (*API, *conf.Configuration, error) {
globalConfig, conn, err := test.SetupDBConnection()
func setupAPIForTestWithCallback(cb func(*conf.GlobalConfiguration, *conf.Configuration, storage.Connection) (uuid.UUID, error)) (*API, *conf.Configuration, error) {
globalConfig, err := conf.LoadGlobal(apiTestConfig)
if err != nil {
return nil, nil, err
}

// TODO disable serial tests and re-enable automigrate and uncomment
// this code once `pop` migrations are fixed
//
// dbname := fmt.Sprintf("gotrue_test_%s", randStringBytes(10))
// globalConfig.DB.URL, err = test.CreateTestDB(dbname, globalConfig)
// if err != nil {
// return nil, nil, err
// }

conn, err := test.SetupDBConnection(globalConfig)
if err != nil {
//test.DeleteTestDB(globalConfig)
return nil, nil, err
}

config, err := conf.LoadConfig(apiTestConfig)
if err != nil {
conn.Close()
//test.DeleteTestDB(globalConfig)
return nil, nil, err
}

instanceID := ""
instanceID := uuid.Nil
if cb != nil {
instanceID, err = cb(globalConfig, config, conn)
if err != nil {
conn.Close()
//test.DeleteTestDB(globalConfig)
return nil, nil, err
}
}

ctx, err := WithInstanceConfig(context.Background(), globalConfig.SMTP, config, instanceID)
if err != nil {
conn.Close()
//test.DeleteTestDB(globalConfig)
return nil, nil, err
}

return NewAPIWithVersion(ctx, globalConfig, conn, apiTestVersion), config, nil
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
}
return string(b)
}
2 changes: 1 addition & 1 deletion api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (a *API) requireAdmin(ctx context.Context, w http.ResponseWriter, r *http.R
// Find the administrative user
adminUser, err := getUserFromClaims(ctx, a.db)
if err != nil {
return nil, unauthorizedError("Invalid admin user")
return nil, unauthorizedError("Invalid admin user").WithInternalError(err)
}

aud := a.requestAud(ctx, r)
Expand Down
9 changes: 5 additions & 4 deletions api/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/mailer"
"github.com/netlify/gotrue/models"
uuid "github.com/satori/go.uuid"
)

type contextKey string
Expand Down Expand Up @@ -96,17 +97,17 @@ func getMailer(ctx context.Context) mailer.Mailer {
}

// withInstanceID adds the instance id to the context.
func withInstanceID(ctx context.Context, id string) context.Context {
func withInstanceID(ctx context.Context, id uuid.UUID) context.Context {
return context.WithValue(ctx, instanceIDKey, id)
}

// getInstanceID reads the instance id from the context.
func getInstanceID(ctx context.Context) string {
func getInstanceID(ctx context.Context) uuid.UUID {
obj := ctx.Value(instanceIDKey)
if obj == nil {
return ""
return uuid.Nil
}
return obj.(string)
return obj.(uuid.UUID)
}

// withInstance adds the instance id to the context.
Expand Down
2 changes: 1 addition & 1 deletion api/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (a *API) ExternalProviderRedirect(w http.ResponseWriter, r *http.Request) e
ExpiresAt: time.Now().Add(5 * time.Minute).Unix(),
},
SiteURL: config.SiteURL,
InstanceID: getInstanceID(ctx),
InstanceID: getInstanceID(ctx).String(),
NetlifyID: getNetlifyID(ctx),
},
Provider: providerType,
Expand Down
8 changes: 5 additions & 3 deletions api/external_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

jwt "github.com/dgrijalva/jwt-go"
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/storage/test"
uuid "github.com/satori/go.uuid"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)
Expand All @@ -18,7 +18,7 @@ type ExternalTestSuite struct {
suite.Suite
API *API
Config *conf.Configuration
instanceID string
instanceID uuid.UUID
}

func TestExternal(t *testing.T) {
Expand All @@ -30,12 +30,14 @@ func TestExternal(t *testing.T) {
Config: config,
instanceID: instanceID,
}
defer api.db.Close()
//defer api.db.DropDB()

suite.Run(t, ts)
}

func (ts *ExternalTestSuite) SetupTest() {
test.CleanupTables()
ts.API.db.TruncateAll()
}

// TestSignupExternalUnsupported tests API /authorize for an unsupported external provider
Expand Down
Loading

0 comments on commit 47cc9ce

Please sign in to comment.