fix: use database for user creation to prevent flake (#10992)

This commit is contained in:
Garrett Delfosse
2023-12-04 11:05:17 -05:00
committed by GitHub
parent 2f54f769be
commit ccd5e1a749
+44 -29
View File
@@ -23,6 +23,7 @@ import (
"github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbgen"
"github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/coderd/util/slice"
@@ -1699,7 +1700,7 @@ func TestSuspendedPagination(t *testing.T) {
// them using different page sizes. // them using different page sizes.
func TestPaginatedUsers(t *testing.T) { func TestPaginatedUsers(t *testing.T) {
t.Parallel() t.Parallel()
client := coderdtest.New(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
coderdtest.CreateFirstUser(t, client) coderdtest.CreateFirstUser(t, client)
// This test takes longer than a long time. // This test takes longer than a long time.
@@ -1708,15 +1709,17 @@ func TestPaginatedUsers(t *testing.T) {
me, err := client.User(ctx, codersdk.Me) me, err := client.User(ctx, codersdk.Me)
require.NoError(t, err) require.NoError(t, err)
orgID := me.OrganizationIDs[0]
// When 50 users exist // When 50 users exist
total := 50 total := 50
allUsers := make([]codersdk.User, total+1) // +1 forme allUsers := make([]database.User, total+1)
allUsers[0] = me allUsers[0] = database.User{
specialUsers := make([]codersdk.User, total/2) Email: me.Email,
Username: me.Username,
}
specialUsers := make([]database.User, total/2)
eg, egCtx := errgroup.WithContext(ctx) eg, _ := errgroup.WithContext(ctx)
// Create users // Create users
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
i := i i := i
@@ -1730,21 +1733,14 @@ func TestPaginatedUsers(t *testing.T) {
if i%3 == 0 { if i%3 == 0 {
username = strings.ToUpper(username) username = strings.ToUpper(username)
} }
// One side effect of having to use the api vs the db calls directly, is you cannot
// mock time. Ideally I could pass in mocked times and space these users out. // We used to use the API to ceate users, but that is slow.
// // Instead, we create them directly in the database now
// But this also serves as a good test. Postgres has microsecond precision on its timestamps. // to prevent timeout flakes.
// If 2 users share the same created_at, that could cause an issue if you are strictly paginating via newUser := dbgen.User(t, db, database.User{
// timestamps. The pagination goes by timestamps and uuids. Email: email,
newUser, err := client.CreateUser(egCtx, codersdk.CreateUserRequest{ Username: username,
Email: email,
Username: username,
Password: "MySecurePassword!",
OrganizationID: orgID,
}) })
if err != nil {
return err
}
allUsers[i+1] = newUser allUsers[i+1] = newUser
if i%2 == 0 { if i%2 == 0 {
specialUsers[i/2] = newUser specialUsers[i/2] = newUser
@@ -1757,8 +1753,8 @@ func TestPaginatedUsers(t *testing.T) {
require.NoError(t, err, "create users failed") require.NoError(t, err, "create users failed")
// Sorting the users will sort by username. // Sorting the users will sort by username.
sortUsers(allUsers) sortDatabaseUsers(allUsers)
sortUsers(specialUsers) sortDatabaseUsers(specialUsers)
gmailSearch := func(request codersdk.UsersRequest) codersdk.UsersRequest { gmailSearch := func(request codersdk.UsersRequest) codersdk.UsersRequest {
request.Search = "gmail" request.Search = "gmail"
@@ -1772,7 +1768,7 @@ func TestPaginatedUsers(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
limit int limit int
allUsers []codersdk.User allUsers []database.User
opt func(request codersdk.UsersRequest) codersdk.UsersRequest opt func(request codersdk.UsersRequest) codersdk.UsersRequest
}{ }{
{name: "all users", limit: 10, allUsers: allUsers}, {name: "all users", limit: 10, allUsers: allUsers},
@@ -1800,7 +1796,7 @@ func TestPaginatedUsers(t *testing.T) {
// Assert pagination will page through the list of all users using the given // Assert pagination will page through the list of all users using the given
// limit for each page. The 'allUsers' is the expected full list to compare // limit for each page. The 'allUsers' is the expected full list to compare
// against. // against.
func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client, limit int, allUsers []codersdk.User, func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client, limit int, allUsers []database.User,
opt func(request codersdk.UsersRequest) codersdk.UsersRequest, opt func(request codersdk.UsersRequest) codersdk.UsersRequest,
) { ) {
var count int var count int
@@ -1817,7 +1813,7 @@ func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client
}, },
})) }))
require.NoError(t, err, "first page") require.NoError(t, err, "first page")
require.Equalf(t, page.Users, allUsers[:limit], "first page, limit=%d", limit) require.Equalf(t, onlyUsernames(page.Users), onlyUsernames(allUsers[:limit]), "first page, limit=%d", limit)
count += len(page.Users) count += len(page.Users)
for { for {
@@ -1846,14 +1842,14 @@ func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client
})) }))
require.NoError(t, err, "next offset page") require.NoError(t, err, "next offset page")
var expected []codersdk.User var expected []database.User
if count+limit > len(allUsers) { if count+limit > len(allUsers) {
expected = allUsers[count:] expected = allUsers[count:]
} else { } else {
expected = allUsers[count : count+limit] expected = allUsers[count : count+limit]
} }
require.Equalf(t, page.Users, expected, "next users, after=%s, limit=%d", afterCursor, limit) require.Equalf(t, onlyUsernames(page.Users), onlyUsernames(expected), "next users, after=%s, limit=%d", afterCursor, limit)
require.Equalf(t, offsetPage.Users, expected, "offset users, offset=%d, limit=%d", count, limit) require.Equalf(t, onlyUsernames(offsetPage.Users), onlyUsernames(expected), "offset users, offset=%d, limit=%d", count, limit)
// Also check the before // Also check the before
prevPage, err := client.Users(ctx, opt(codersdk.UsersRequest{ prevPage, err := client.Users(ctx, opt(codersdk.UsersRequest{
@@ -1863,7 +1859,7 @@ func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client
}, },
})) }))
require.NoError(t, err, "prev page") require.NoError(t, err, "prev page")
require.Equal(t, allUsers[count-limit:count], prevPage.Users, "prev users") require.Equal(t, onlyUsernames(allUsers[count-limit:count]), onlyUsernames(prevPage.Users), "prev users")
count += len(page.Users) count += len(page.Users)
} }
} }
@@ -1875,6 +1871,25 @@ func sortUsers(users []codersdk.User) {
}) })
} }
func sortDatabaseUsers(users []database.User) {
slices.SortFunc(users, func(a, b database.User) int {
return slice.Ascending(strings.ToLower(a.Username), strings.ToLower(b.Username))
})
}
func onlyUsernames[U codersdk.User | database.User](users []U) []string {
var out []string
for _, u := range users {
switch u := (any(u)).(type) {
case codersdk.User:
out = append(out, u.Username)
case database.User:
out = append(out, u.Username)
}
}
return out
}
func BenchmarkUsersMe(b *testing.B) { func BenchmarkUsersMe(b *testing.B) {
client := coderdtest.New(b, nil) client := coderdtest.New(b, nil)
_ = coderdtest.CreateFirstUser(b, client) _ = coderdtest.CreateFirstUser(b, client)