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

View File

@ -23,6 +23,7 @@ import (
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"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/rbac"
"github.com/coder/coder/v2/coderd/util/slice"
@ -1699,7 +1700,7 @@ func TestSuspendedPagination(t *testing.T) {
// them using different page sizes.
func TestPaginatedUsers(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
client, db := coderdtest.NewWithDatabase(t, nil)
coderdtest.CreateFirstUser(t, client)
// This test takes longer than a long time.
@ -1708,15 +1709,17 @@ func TestPaginatedUsers(t *testing.T) {
me, err := client.User(ctx, codersdk.Me)
require.NoError(t, err)
orgID := me.OrganizationIDs[0]
// When 50 users exist
total := 50
allUsers := make([]codersdk.User, total+1) // +1 forme
allUsers[0] = me
specialUsers := make([]codersdk.User, total/2)
allUsers := make([]database.User, total+1)
allUsers[0] = database.User{
Email: me.Email,
Username: me.Username,
}
specialUsers := make([]database.User, total/2)
eg, egCtx := errgroup.WithContext(ctx)
eg, _ := errgroup.WithContext(ctx)
// Create users
for i := 0; i < total; i++ {
i := i
@ -1730,21 +1733,14 @@ func TestPaginatedUsers(t *testing.T) {
if i%3 == 0 {
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.
//
// But this also serves as a good test. Postgres has microsecond precision on its timestamps.
// If 2 users share the same created_at, that could cause an issue if you are strictly paginating via
// timestamps. The pagination goes by timestamps and uuids.
newUser, err := client.CreateUser(egCtx, codersdk.CreateUserRequest{
Email: email,
Username: username,
Password: "MySecurePassword!",
OrganizationID: orgID,
// We used to use the API to ceate users, but that is slow.
// Instead, we create them directly in the database now
// to prevent timeout flakes.
newUser := dbgen.User(t, db, database.User{
Email: email,
Username: username,
})
if err != nil {
return err
}
allUsers[i+1] = newUser
if i%2 == 0 {
specialUsers[i/2] = newUser
@ -1757,8 +1753,8 @@ func TestPaginatedUsers(t *testing.T) {
require.NoError(t, err, "create users failed")
// Sorting the users will sort by username.
sortUsers(allUsers)
sortUsers(specialUsers)
sortDatabaseUsers(allUsers)
sortDatabaseUsers(specialUsers)
gmailSearch := func(request codersdk.UsersRequest) codersdk.UsersRequest {
request.Search = "gmail"
@ -1772,7 +1768,7 @@ func TestPaginatedUsers(t *testing.T) {
tests := []struct {
name string
limit int
allUsers []codersdk.User
allUsers []database.User
opt func(request codersdk.UsersRequest) codersdk.UsersRequest
}{
{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
// limit for each page. The 'allUsers' is the expected full list to compare
// 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,
) {
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.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)
for {
@ -1846,14 +1842,14 @@ func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client
}))
require.NoError(t, err, "next offset page")
var expected []codersdk.User
var expected []database.User
if count+limit > len(allUsers) {
expected = allUsers[count:]
} else {
expected = allUsers[count : count+limit]
}
require.Equalf(t, page.Users, 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(page.Users), onlyUsernames(expected), "next users, after=%s, limit=%d", afterCursor, limit)
require.Equalf(t, onlyUsernames(offsetPage.Users), onlyUsernames(expected), "offset users, offset=%d, limit=%d", count, limit)
// Also check the before
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.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)
}
}
@ -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) {
client := coderdtest.New(b, nil)
_ = coderdtest.CreateFirstUser(b, client)