Repository: supabase/gotrue
Pull request #564 (2022-07-25 13:09:25)

Speed up tests
## What kind of change does this PR introduce?
Improve speed of tests

## What is the current behavior?
Full test run ~90 seconds on my laptop

## What is the new behavior?
< 10 seconds

## Additional context
The user's `hashPassword` function uses a global variable for the bcrypt cost, rather than `bcrypt.DefaultCost` directly. This allows tests to change the value. All other changes are isolated to test code:

1 - using delete from instead of truncate

2 - using MinCost for hashing

3 - shortening the wait time for TestHookTimeout

Commit has more details on each change.

kangmingtay: > I played around with using jwt.SigningMethodNone for signing. While I
think it's worth it, it requires touching quite a few files. If it's
worth doing, it should probably go in a separate PR.

i think it's fine, the tests are already running really fast - but if you make a PR for it, we'll merge it in 

Patch:
diff --git a/models/connection.go b/models/connection.go
index 7c01a1de..94696a79 100644
--- a/models/connection.go
+++ b/models/connection.go
@@ -32,15 +32,15 @@ type SortField struct {
 
 func TruncateAll(conn *storage.Connection) error {
 	return conn.Transaction(func(tx *storage.Connection) error {
-		if err := tx.RawQuery("TRUNCATE " + (&pop.Model{Value: User{}}).TableName() + " CASCADE").Exec(); err != nil {
+		if err := tx.RawQuery("delete from " + (&pop.Model{Value: User{}}).TableName()).Exec(); err != nil {
 			return err
 		}
-		if err := tx.RawQuery("TRUNCATE " + (&pop.Model{Value: RefreshToken{}}).TableName() + " CASCADE").Exec(); err != nil {
+		if err := tx.RawQuery("delete from " + (&pop.Model{Value: RefreshToken{}}).TableName()).Exec(); err != nil {
 			return err
 		}
-		if err := tx.RawQuery("TRUNCATE " + (&pop.Model{Value: AuditLogEntry{}}).TableName() + " CASCADE").Exec(); err != nil {
+		if err := tx.RawQuery("delete from " + (&pop.Model{Value: AuditLogEntry{}}).TableName()).Exec(); err != nil {
 			return err
 		}
-		return tx.RawQuery("TRUNCATE " + (&pop.Model{Value: Instance{}}).TableName() + " CASCADE").Exec()
+		return tx.RawQuery("delete from " + (&pop.Model{Value: Instance{}}).TableName()).Exec()
 	})
 }
diff --git a/models/user.go b/models/user.go
index 9d7efdef..d288751a 100644
--- a/models/user.go
+++ b/models/user.go
@@ -16,6 +16,7 @@ import (
 const SystemUserID = "0"
 
 var SystemUserUUID = uuid.Nil
+var PasswordHashCost = bcrypt.DefaultCost
 
 // User respresents a registered user with email/password authentication
 type User struct {
@@ -253,7 +254,7 @@ func (u *User) SetPhone(tx *storage.Connection, phone string) error {
 
 // hashPassword generates a hashed password from a plaintext string
 func hashPassword(password string) (string, error) {
-	pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
+	pw, err := bcrypt.GenerateFromPassword([]byte(password), PasswordHashCost)
 	if err != nil {
 		return "", err
 	}


Test patch:
diff --git a/api/api_test.go b/api/api_test.go
index a5522f60..bfa78fec 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -12,6 +12,7 @@ import (
 	"github.com/netlify/gotrue/storage"
 	"github.com/netlify/gotrue/storage/test"
 	"github.com/stretchr/testify/require"
+	"golang.org/x/crypto/bcrypt"
 )
 
 const (
@@ -21,6 +22,8 @@ const (
 
 func init() {
 	rand.Seed(time.Now().UnixNano())
+	models.PasswordHashCost = bcrypt.MinCost
+
 }
 
 // setupAPIForTest creates a new API to run tests with.
diff --git a/api/hook_test.go b/api/hook_test.go
index fb6a3593..32c2e3f5 100644
--- a/api/hook_test.go
+++ b/api/hook_test.go
@@ -142,10 +142,16 @@ func TestHookRetry(t *testing.T) {
 }
 
 func TestHookTimeout(t *testing.T) {
+	realTimeout := defaultTimeout
+	defer func() {
+		defaultTimeout = realTimeout
+	}()
+	defaultTimeout = time.Millisecond * 10
+
 	var callCount int
 	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		callCount++
-		<-time.After(2 * time.Second)
+		time.Sleep(20 * time.Millisecond)
 	}))
 	defer svr.Close()
 
@@ -154,9 +160,8 @@ func TestHookTimeout(t *testing.T) {
 	defer unshiftPrivateIPBlock(localhost)
 
 	config := &conf.WebhookConfig{
-		URL:        svr.URL,
-		Retries:    3,
-		TimeoutSec: 1,
+		URL:     svr.URL,
+		Retries: 3,
 	}
 	w := Webhook{
 		WebhookConfig: config,
diff --git a/hack/test.env b/hack/test.env
index b1dcd884..ceebc2ad 100644
--- a/hack/test.env
+++ b/hack/test.env
@@ -86,7 +86,8 @@ GOTRUE_EXTERNAL_SAML_ENABLED=true
 GOTRUE_EXTERNAL_SAML_METADATA_URL=
 GOTRUE_EXTERNAL_SAML_API_BASE=http://localhost
 GOTRUE_EXTERNAL_SAML_NAME=TestSamlName
-GOTRUE_RATE_LIMIT_VERIFY="1000"
+GOTRUE_RATE_LIMIT_VERIFY="100000"
+GOTRUE_RATE_LIMIT_TOKEN_REFRESH="100000"
 GOTRUE_TRACING_ENABLED=false
 GOTRUE_TRACING_HOST=127.0.0.1
 GOTRUE_TRACING_PORT=8126
diff --git a/models/user_test.go b/models/user_test.go
index f87d55fe..3d013fc0 100644
--- a/models/user_test.go
+++ b/models/user_test.go
@@ -10,10 +10,15 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
+	"golang.org/x/crypto/bcrypt"
 )
 
 const modelsTestConfig = "../hack/test.env"
 
+func init() {
+	PasswordHashCost = bcrypt.MinCost
+}
+
 type UserTestSuite struct {
 	suite.Suite
 	db *storage.Connection