diff --git a/coderd/database/dbfake/databasefake.go b/coderd/database/dbfake/databasefake.go index 5590f498e3283..567705c1ec42c 100644 --- a/coderd/database/dbfake/databasefake.go +++ b/coderd/database/dbfake/databasefake.go @@ -2922,6 +2922,21 @@ func (q *fakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParam return database.User{}, err } + // There is a common bug when using dbfake that 2 inserted users have the + // same created_at time. This causes user order to not be deterministic, + // which breaks some unit tests. + // To fix this, we make sure that the created_at time is always greater + // than the last user's created_at time. + allUsers, _ := q.GetUsers(context.Background(), database.GetUsersParams{}) + if len(allUsers) > 0 { + lastUser := allUsers[len(allUsers)-1] + if arg.CreatedAt.Before(lastUser.CreatedAt) || + arg.CreatedAt.Equal(lastUser.CreatedAt) { + // 1 ms is a good enough buffer. + arg.CreatedAt = lastUser.CreatedAt.Add(time.Millisecond) + } + } + q.mutex.Lock() defer q.mutex.Unlock() diff --git a/coderd/database/dbfake/databasefake_test.go b/coderd/database/dbfake/databasefake_test.go index 923b404cf768d..daf1757b0a3fa 100644 --- a/coderd/database/dbfake/databasefake_test.go +++ b/coderd/database/dbfake/databasefake_test.go @@ -9,10 +9,11 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/coder/coder/coderd/database" - "github.com/coder/coder/coderd/database/dbfake" + "github.com/coder/coder/coderd/database/dbgen" ) // test that transactions don't deadlock, and that we don't see intermediate state. @@ -105,6 +106,29 @@ func TestExactMethods(t *testing.T) { } } +// TestUserOrder ensures that the fake database returns users in the order they +// were created. +func TestUserOrder(t *testing.T) { + t.Parallel() + + db := dbfake.New() + now := database.Now() + count := 10 + for i := 0; i < count; i++ { + dbgen.User(t, db, database.User{ + Username: fmt.Sprintf("user%d", i), + CreatedAt: now, + }) + } + + users, err := db.GetUsers(context.Background(), database.GetUsersParams{}) + require.NoError(t, err) + require.Lenf(t, users, count, "expected %d users", count) + for i, user := range users { + require.Equal(t, fmt.Sprintf("user%d", i), user.Username) + } +} + func methods(rt reflect.Type) map[string]bool { methods := make(map[string]bool) for i := 0; i < rt.NumMethod(); i++ {