mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add new group members endpoint with filtering and pagination (#23067)
Partially addresses #21813 (still need to make changes to the "add user" button to be complete) Since there are a lot of user tests already, I moved them into `coderdtest` to be shared.
This commit is contained in:
@@ -900,9 +900,10 @@ func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationI
|
||||
require.NoError(t, err)
|
||||
|
||||
var sessionToken string
|
||||
if req.UserLoginType == codersdk.LoginTypeNone {
|
||||
// Cannot log in with a disabled login user. So make it an api key from
|
||||
// the client making this user.
|
||||
switch req.UserLoginType {
|
||||
case codersdk.LoginTypeNone, codersdk.LoginTypeGithub, codersdk.LoginTypeOIDC:
|
||||
// Cannot log in with a non-password user. So make it an api key from the
|
||||
// client making this user.
|
||||
token, err := client.CreateToken(context.Background(), user.ID.String(), codersdk.CreateTokenRequest{
|
||||
Lifetime: time.Hour * 24,
|
||||
Scope: codersdk.APIKeyScopeAll,
|
||||
@@ -910,7 +911,7 @@ func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationI
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = token.Key
|
||||
} else {
|
||||
default:
|
||||
login, err := client.LoginWithPassword(context.Background(), codersdk.LoginWithPasswordRequest{
|
||||
Email: req.Email,
|
||||
Password: req.Password,
|
||||
|
||||
@@ -0,0 +1,584 @@
|
||||
package coderdtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/db2sdk"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/userpassword"
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
// UsersPagination creates a set of users for testing pagination. It can be
|
||||
// used to test paginating both users and group members.
|
||||
func UsersPagination(
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
client *codersdk.Client,
|
||||
setup func(users []codersdk.User),
|
||||
fetch func(req codersdk.UsersRequest) ([]codersdk.ReducedUser, int),
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
firstUser, err := client.User(ctx, codersdk.Me)
|
||||
require.NoError(t, err, "fetch me")
|
||||
|
||||
count := 10
|
||||
users := make([]codersdk.User, count)
|
||||
orgID := firstUser.OrganizationIDs[0]
|
||||
users[0] = firstUser
|
||||
for i := range count - 1 {
|
||||
_, user := CreateAnotherUserMutators(t, client, orgID, nil, func(r *codersdk.CreateUserRequestWithOrgs) {
|
||||
if i < 5 {
|
||||
r.Name = fmt.Sprintf("before%d", i)
|
||||
} else {
|
||||
r.Name = fmt.Sprintf("after%d", i)
|
||||
}
|
||||
})
|
||||
users[i+1] = user
|
||||
}
|
||||
|
||||
slices.SortFunc(users, func(a, b codersdk.User) int {
|
||||
return slice.Ascending(strings.ToLower(a.Username), strings.ToLower(b.Username))
|
||||
})
|
||||
|
||||
if setup != nil {
|
||||
setup(users)
|
||||
}
|
||||
|
||||
gotUsers, gotCount := fetch(codersdk.UsersRequest{})
|
||||
require.Len(t, gotUsers, count)
|
||||
require.Equal(t, gotCount, count)
|
||||
|
||||
gotUsers, gotCount = fetch(codersdk.UsersRequest{
|
||||
Pagination: codersdk.Pagination{
|
||||
Limit: 1,
|
||||
},
|
||||
})
|
||||
require.Len(t, gotUsers, 1)
|
||||
require.Equal(t, gotCount, count)
|
||||
|
||||
gotUsers, gotCount = fetch(codersdk.UsersRequest{
|
||||
Pagination: codersdk.Pagination{
|
||||
Offset: 1,
|
||||
},
|
||||
})
|
||||
require.Len(t, gotUsers, count-1)
|
||||
require.Equal(t, gotCount, count)
|
||||
|
||||
gotUsers, gotCount = fetch(codersdk.UsersRequest{
|
||||
Pagination: codersdk.Pagination{
|
||||
Limit: 1,
|
||||
Offset: 1,
|
||||
},
|
||||
})
|
||||
require.Len(t, gotUsers, 1)
|
||||
require.Equal(t, gotCount, count)
|
||||
|
||||
// If offset is higher than the count postgres returns an empty array
|
||||
// and not an ErrNoRows error.
|
||||
gotUsers, gotCount = fetch(codersdk.UsersRequest{
|
||||
Pagination: codersdk.Pagination{
|
||||
Offset: count + 1,
|
||||
},
|
||||
})
|
||||
require.Len(t, gotUsers, 0)
|
||||
require.Equal(t, gotCount, 0)
|
||||
|
||||
// Check that AfterID works.
|
||||
gotUsers, gotCount = fetch(codersdk.UsersRequest{
|
||||
Pagination: codersdk.Pagination{
|
||||
AfterID: users[5].ID,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, gotUsers, 4)
|
||||
require.Equal(t, gotCount, 4)
|
||||
|
||||
// Check we can paginate a filtered response.
|
||||
gotUsers, gotCount = fetch(codersdk.UsersRequest{
|
||||
SearchQuery: "name:after",
|
||||
Pagination: codersdk.Pagination{
|
||||
Limit: 1,
|
||||
Offset: 1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, gotUsers, 1)
|
||||
require.Equal(t, gotCount, 4)
|
||||
require.Contains(t, gotUsers[0].Name, "after")
|
||||
}
|
||||
|
||||
// UsersFilter creates a set of users to run various filters against for
|
||||
// testing. It can be used to test filtering both users and group members.
|
||||
func UsersFilter(
|
||||
setupCtx context.Context,
|
||||
t *testing.T,
|
||||
client *codersdk.Client,
|
||||
db database.Store,
|
||||
setup func(users []codersdk.User),
|
||||
fetch func(ctx context.Context, req codersdk.UsersRequest) []codersdk.ReducedUser,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
firstUser, err := client.User(setupCtx, codersdk.Me)
|
||||
require.NoError(t, err, "fetch me")
|
||||
|
||||
// Noon on Jan 18 is the "now" for this test for last_seen timestamps.
|
||||
// All these values are equal
|
||||
// 2023-01-18T12:00:00Z (UTC)
|
||||
// 2023-01-18T07:00:00-05:00 (America/New_York)
|
||||
// 2023-01-18T13:00:00+01:00 (Europe/Madrid)
|
||||
// 2023-01-16T00:00:00+12:00 (Asia/Anadyr)
|
||||
lastSeenNow := time.Date(2023, 1, 18, 12, 0, 0, 0, time.UTC)
|
||||
users := make([]codersdk.User, 0)
|
||||
users = append(users, firstUser)
|
||||
orgID := firstUser.OrganizationIDs[0]
|
||||
for i := range 15 {
|
||||
roles := []rbac.RoleIdentifier{}
|
||||
if i%2 == 0 {
|
||||
roles = append(roles, rbac.RoleTemplateAdmin(), rbac.RoleUserAdmin())
|
||||
}
|
||||
if i%3 == 0 {
|
||||
roles = append(roles, rbac.RoleAuditor())
|
||||
}
|
||||
userClient, userData := CreateAnotherUserMutators(t, client, orgID, roles, func(r *codersdk.CreateUserRequestWithOrgs) {
|
||||
switch {
|
||||
case i%7 == 0:
|
||||
r.Username += fmt.Sprintf("-gh%d", i)
|
||||
r.UserLoginType = codersdk.LoginTypeGithub
|
||||
r.Password = ""
|
||||
case i%6 == 0:
|
||||
r.UserLoginType = codersdk.LoginTypeOIDC
|
||||
r.Password = ""
|
||||
default:
|
||||
r.UserLoginType = codersdk.LoginTypePassword
|
||||
}
|
||||
})
|
||||
|
||||
// Set the last seen for each user to a unique day
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
_, err := db.UpdateUserLastSeenAt(dbauthz.AsSystemRestricted(setupCtx), database.UpdateUserLastSeenAtParams{
|
||||
ID: userData.ID,
|
||||
LastSeenAt: lastSeenNow.Add(-1 * time.Hour * 24 * time.Duration(i)),
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
require.NoError(t, err, "set a last seen")
|
||||
|
||||
// Set a github user ID for github login types.
|
||||
if i%7 == 0 {
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
err = db.UpdateUserGithubComUserID(dbauthz.AsSystemRestricted(setupCtx), database.UpdateUserGithubComUserIDParams{
|
||||
ID: userData.ID,
|
||||
GithubComUserID: sql.NullInt64{
|
||||
Int64: int64(i),
|
||||
Valid: true,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
user, err := userClient.User(setupCtx, codersdk.Me)
|
||||
require.NoError(t, err, "fetch me")
|
||||
|
||||
if i%4 == 0 {
|
||||
user, err = client.UpdateUserStatus(setupCtx, user.ID.String(), codersdk.UserStatusSuspended)
|
||||
require.NoError(t, err, "suspend user")
|
||||
}
|
||||
|
||||
if i%5 == 0 {
|
||||
user, err = client.UpdateUserProfile(setupCtx, user.ID.String(), codersdk.UpdateUserProfileRequest{
|
||||
Username: strings.ToUpper(user.Username),
|
||||
})
|
||||
require.NoError(t, err, "update username to uppercase")
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
hashedPassword, err := userpassword.Hash("SomeStrongPassword!")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add users with different creation dates for testing date filters
|
||||
for i := range 3 {
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
user1, err := db.InsertUser(dbauthz.AsSystemRestricted(setupCtx), database.InsertUserParams{
|
||||
ID: uuid.New(),
|
||||
Email: fmt.Sprintf("before%d@coder.com", i),
|
||||
Username: fmt.Sprintf("before%d", i),
|
||||
Name: fmt.Sprintf("Test User %d", i),
|
||||
HashedPassword: []byte(hashedPassword),
|
||||
LoginType: database.LoginTypeNone,
|
||||
Status: string(codersdk.UserStatusActive),
|
||||
RBACRoles: []string{codersdk.RoleMember},
|
||||
CreatedAt: dbtime.Time(time.Date(2022, 12, 15+i, 12, 0, 0, 0, time.UTC)),
|
||||
UpdatedAt: dbtime.Time(time.Date(2022, 12, 15+i, 12, 0, 0, 0, time.UTC)),
|
||||
IsServiceAccount: false,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
_, err = db.InsertOrganizationMember(dbauthz.AsSystemRestricted(setupCtx), database.InsertOrganizationMemberParams{
|
||||
OrganizationID: orgID,
|
||||
UserID: user1.ID,
|
||||
CreatedAt: dbtime.Now(),
|
||||
UpdatedAt: dbtime.Now(),
|
||||
Roles: []string{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// The expected timestamps must be parsed from strings to compare equal during `ElementsMatch`
|
||||
sdkUser1 := db2sdk.User(user1, []uuid.UUID{orgID})
|
||||
sdkUser1.CreatedAt, err = time.Parse(time.RFC3339, sdkUser1.CreatedAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
sdkUser1.UpdatedAt, err = time.Parse(time.RFC3339, sdkUser1.UpdatedAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
sdkUser1.LastSeenAt, err = time.Parse(time.RFC3339, sdkUser1.LastSeenAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
users = append(users, sdkUser1)
|
||||
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
user2, err := db.InsertUser(dbauthz.AsSystemRestricted(setupCtx), database.InsertUserParams{
|
||||
ID: uuid.New(),
|
||||
Email: fmt.Sprintf("during%d@coder.com", i),
|
||||
Username: fmt.Sprintf("during%d", i),
|
||||
Name: "",
|
||||
HashedPassword: []byte(hashedPassword),
|
||||
LoginType: database.LoginTypeNone,
|
||||
Status: string(codersdk.UserStatusActive),
|
||||
RBACRoles: []string{codersdk.RoleOwner},
|
||||
CreatedAt: dbtime.Time(time.Date(2023, 1, 15+i, 12, 0, 0, 0, time.UTC)),
|
||||
UpdatedAt: dbtime.Time(time.Date(2023, 1, 15+i, 12, 0, 0, 0, time.UTC)),
|
||||
IsServiceAccount: false,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
_, err = db.InsertOrganizationMember(dbauthz.AsSystemRestricted(setupCtx), database.InsertOrganizationMemberParams{
|
||||
OrganizationID: orgID,
|
||||
UserID: user2.ID,
|
||||
CreatedAt: dbtime.Now(),
|
||||
UpdatedAt: dbtime.Now(),
|
||||
Roles: []string{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
sdkUser2 := db2sdk.User(user2, []uuid.UUID{orgID})
|
||||
sdkUser2.CreatedAt, err = time.Parse(time.RFC3339, sdkUser2.CreatedAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
sdkUser2.UpdatedAt, err = time.Parse(time.RFC3339, sdkUser2.UpdatedAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
sdkUser2.LastSeenAt, err = time.Parse(time.RFC3339, sdkUser2.LastSeenAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
users = append(users, sdkUser2)
|
||||
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
user3, err := db.InsertUser(dbauthz.AsSystemRestricted(setupCtx), database.InsertUserParams{
|
||||
ID: uuid.New(),
|
||||
Email: fmt.Sprintf("after%d@coder.com", i),
|
||||
Username: fmt.Sprintf("after%d", i),
|
||||
Name: "",
|
||||
HashedPassword: []byte(hashedPassword),
|
||||
LoginType: database.LoginTypeNone,
|
||||
Status: string(codersdk.UserStatusActive),
|
||||
RBACRoles: []string{codersdk.RoleOwner},
|
||||
CreatedAt: dbtime.Time(time.Date(2023, 2, 15+i, 12, 0, 0, 0, time.UTC)),
|
||||
UpdatedAt: dbtime.Time(time.Date(2023, 2, 15+i, 12, 0, 0, 0, time.UTC)),
|
||||
IsServiceAccount: false,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// nolint:gocritic // Setting up unit test data.
|
||||
_, err = db.InsertOrganizationMember(dbauthz.AsSystemRestricted(setupCtx), database.InsertOrganizationMemberParams{
|
||||
OrganizationID: orgID,
|
||||
UserID: user3.ID,
|
||||
CreatedAt: dbtime.Now(),
|
||||
UpdatedAt: dbtime.Now(),
|
||||
Roles: []string{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
sdkUser3 := db2sdk.User(user3, []uuid.UUID{orgID})
|
||||
sdkUser3.CreatedAt, err = time.Parse(time.RFC3339, sdkUser3.CreatedAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
sdkUser3.UpdatedAt, err = time.Parse(time.RFC3339, sdkUser3.UpdatedAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
sdkUser3.LastSeenAt, err = time.Parse(time.RFC3339, sdkUser3.LastSeenAt.Format(time.RFC3339))
|
||||
require.NoError(t, err)
|
||||
users = append(users, sdkUser3)
|
||||
}
|
||||
|
||||
if setup != nil {
|
||||
setup(users)
|
||||
}
|
||||
|
||||
// --- Setup done ---
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Filter codersdk.UsersRequest
|
||||
// If FilterF is true, we include it in the expected results
|
||||
FilterF func(f codersdk.UsersRequest, user codersdk.User) bool
|
||||
}{
|
||||
{
|
||||
Name: "All",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, _ codersdk.User) bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Active",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Status: codersdk.UserStatusActive,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.Status == codersdk.UserStatusActive
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GithubComUserID",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: "github_com_user_id:7",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return strings.HasSuffix(u.Username, "-gh7")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ActiveUppercase",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Status: "ACTIVE",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.Status == codersdk.UserStatusActive
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Suspended",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Status: codersdk.UserStatusSuspended,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.Status == codersdk.UserStatusSuspended
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "NameContains",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Search: "a",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return (strings.ContainsAny(u.Username, "aA") || strings.ContainsAny(u.Email, "aA"))
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "NameAndSearch",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: "name:Test search:before1",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.Username == "before1"
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "NameNoMatch",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Search: "nonexistent",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, _ codersdk.User) bool {
|
||||
return false
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admins",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Role: codersdk.RoleOwner,
|
||||
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
for _, r := range u.Roles {
|
||||
if r.Name == codersdk.RoleOwner {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "AdminsUppercase",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Role: "OWNER",
|
||||
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
for _, r := range u.Roles {
|
||||
if r.Name == codersdk.RoleOwner {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Members",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Role: codersdk.RoleMember,
|
||||
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, _ codersdk.User) bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SearchQuery",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: "i role:owner status:active",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
for _, r := range u.Roles {
|
||||
if r.Name == codersdk.RoleOwner {
|
||||
return (strings.ContainsAny(u.Username, "iI") || strings.ContainsAny(u.Email, "iI")) &&
|
||||
u.Status == codersdk.UserStatusActive
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SearchQueryInsensitive",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: "i Role:Owner STATUS:Active",
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
for _, r := range u.Roles {
|
||||
if r.Name == codersdk.RoleOwner {
|
||||
return (strings.ContainsAny(u.Username, "iI") || strings.ContainsAny(u.Email, "iI")) &&
|
||||
u.Status == codersdk.UserStatusActive
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "LastSeenBeforeNow",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: `last_seen_before:"2023-01-16T00:00:00+12:00"`,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.LastSeenAt.Before(lastSeenNow)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "LastSeenLastWeek",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: `last_seen_before:"2023-01-14T23:59:59Z" last_seen_after:"2023-01-08T00:00:00Z"`,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
start := time.Date(2023, 1, 8, 0, 0, 0, 0, time.UTC)
|
||||
end := time.Date(2023, 1, 14, 23, 59, 59, 0, time.UTC)
|
||||
return u.LastSeenAt.Before(end) && u.LastSeenAt.After(start)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreatedAtBefore",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: `created_before:"2023-01-31T23:59:59Z"`,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
end := time.Date(2023, 1, 31, 23, 59, 59, 0, time.UTC)
|
||||
return u.CreatedAt.Before(end)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreatedAtAfter",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: `created_after:"2023-01-01T00:00:00Z"`,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
return u.CreatedAt.After(start)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreatedAtRange",
|
||||
Filter: codersdk.UsersRequest{
|
||||
SearchQuery: `created_after:"2023-01-01T00:00:00Z" created_before:"2023-01-31T23:59:59Z"`,
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := time.Date(2023, 1, 31, 23, 59, 59, 0, time.UTC)
|
||||
return u.CreatedAt.After(start) && u.CreatedAt.Before(end)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "LoginTypeNone",
|
||||
Filter: codersdk.UsersRequest{
|
||||
LoginType: []codersdk.LoginType{codersdk.LoginTypeNone},
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.LoginType == codersdk.LoginTypeNone
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "LoginTypeOIDC",
|
||||
Filter: codersdk.UsersRequest{
|
||||
LoginType: []codersdk.LoginType{codersdk.LoginTypeOIDC},
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.LoginType == codersdk.LoginTypeOIDC
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "LoginTypeMultiple",
|
||||
Filter: codersdk.UsersRequest{
|
||||
LoginType: []codersdk.LoginType{codersdk.LoginTypeNone, codersdk.LoginTypeGithub},
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.LoginType == codersdk.LoginTypeNone || u.LoginType == codersdk.LoginTypeGithub
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DormantUserWithLoginTypeNone",
|
||||
Filter: codersdk.UsersRequest{
|
||||
Status: codersdk.UserStatusSuspended,
|
||||
LoginType: []codersdk.LoginType{codersdk.LoginTypeNone},
|
||||
},
|
||||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
|
||||
return u.Status == codersdk.UserStatusSuspended && u.LoginType == codersdk.LoginTypeNone
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testCases {
|
||||
t.Run(c.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCtx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
got := fetch(testCtx, c.Filter)
|
||||
exp := make([]codersdk.ReducedUser, 0)
|
||||
for _, made := range users {
|
||||
match := c.FilterF(c.Filter, made)
|
||||
if match {
|
||||
exp = append(exp, made.ReducedUser)
|
||||
}
|
||||
}
|
||||
|
||||
require.ElementsMatch(t, exp, got, "expected users returned")
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user