test: start migrating dbauthz tests to mocked db (#19257)

This PR adds a framework to move to a mocked db. And therefore massively speed up these tests.
This commit is contained in:
Steven Masley
2025-08-08 13:46:24 -05:00
committed by GitHub
parent 155c7bbc65
commit ce935657f6
6 changed files with 186 additions and 17 deletions
+67
View File
@@ -0,0 +1,67 @@
package testutil
import (
"reflect"
"testing"
"github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/require"
)
// Fake will populate any zero fields in the provided struct with fake data.
// Non-zero fields will remain unchanged.
// Usage:
//
// key := Fake(t, faker, database.APIKey{
// TokenName: "keep-my-name",
// })
func Fake[T any](t *testing.T, faker *gofakeit.Faker, seed T) T {
t.Helper()
var tmp T
err := faker.Struct(&tmp)
require.NoError(t, err, "failed to generate fake data for type %T", tmp)
mergeZero(&seed, tmp)
return seed
}
// mergeZero merges the fields of src into dst, but only if the field in dst is
// currently the zero value.
// Make sure `dst` is a pointer to a struct, otherwise the fields are not assignable.
func mergeZero(dst any, src any) {
srcv := reflect.ValueOf(src)
if srcv.Kind() == reflect.Ptr {
srcv = srcv.Elem()
}
remain := [][2]reflect.Value{
{reflect.ValueOf(dst).Elem(), srcv},
}
// Traverse the struct fields and set them only if they are currently zero.
// This is a breadth-first traversal of the struct fields. Struct definitions
// Should not be that deep, so we should not hit any stack overflow issues.
for {
if len(remain) == 0 {
return
}
dv, sv := remain[0][0], remain[0][1]
remain = remain[1:] //
for i := 0; i < dv.NumField(); i++ {
df := dv.Field(i)
sf := sv.Field(i)
if !df.CanSet() {
continue
}
if df.IsZero() { // only write if currently zero
df.Set(sf)
continue
}
if dv.Field(i).Kind() == reflect.Struct {
// If the field is a struct, we need to traverse it as well.
remain = append(remain, [2]reflect.Value{df, sf})
}
}
}
}
+71
View File
@@ -0,0 +1,71 @@
package testutil_test
import (
"testing"
"github.com/brianvoe/gofakeit/v7"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/testutil"
)
type simpleStruct struct {
ID uuid.UUID
Name string
Description string
Age int `fake:"{number:18,60}"`
}
type nestedStruct struct {
Person simpleStruct
Address string
}
func TestFake(t *testing.T) {
t.Parallel()
t.Run("Simple", func(t *testing.T) {
t.Parallel()
faker := gofakeit.New(0)
person := testutil.Fake(t, faker, simpleStruct{
Name: "alice",
})
require.Equal(t, "alice", person.Name)
require.NotEqual(t, uuid.Nil, person.ID)
require.NotEmpty(t, person.Description)
require.Greater(t, person.Age, 17, "Age should be greater than 17")
require.Less(t, person.Age, 61, "Age should be less than 61")
})
t.Run("Nested", func(t *testing.T) {
t.Parallel()
faker := gofakeit.New(0)
person := testutil.Fake(t, faker, nestedStruct{
Person: simpleStruct{
Name: "alice",
},
})
require.Equal(t, "alice", person.Person.Name)
require.NotEqual(t, uuid.Nil, person.Person.ID)
require.NotEmpty(t, person.Person.Description)
require.Greater(t, person.Person.Age, 17, "Age should be greater than 17")
require.NotEmpty(t, person.Address)
})
t.Run("DatabaseType", func(t *testing.T) {
t.Parallel()
faker := gofakeit.New(0)
id := uuid.New()
key := testutil.Fake(t, faker, database.APIKey{
UserID: id,
TokenName: "keep-my-name",
})
require.Equal(t, id, key.UserID)
require.NotEmpty(t, key.TokenName)
})
}