mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
fix: use database for user creation to prevent flake (#10992)
This commit is contained in:
@ -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)
|
||||
|
Reference in New Issue
Block a user