forked from baron/baron-sso
chore: consolidate local integration changes
This commit is contained in:
@@ -64,6 +64,28 @@ func TestWorksmobileHTTPClientCreateUserPostsDirectoryAdminPasswordPayload(t *te
|
||||
require.Len(t, passwordConfig["password"], 16)
|
||||
}
|
||||
|
||||
func TestNewWorksmobileUserPatchPayloadNormalizesMalformedKoreanCellPhone(t *testing.T) {
|
||||
payload := NewWorksmobileUserPatchPayload(WorksmobileUserPayload{
|
||||
DomainID: 1001,
|
||||
Email: "phone-canonical@samaneng.com",
|
||||
CellPhone: "+82+821062836786",
|
||||
UserName: WorksmobileUserName{LastName: "Phone Canonical User"},
|
||||
})
|
||||
|
||||
require.Equal(t, "+821062836786", payload.CellPhone)
|
||||
}
|
||||
|
||||
func TestNewWorksmobileSCIMUserPayloadNormalizesMalformedKoreanCellPhone(t *testing.T) {
|
||||
payload := NewWorksmobileSCIMUserPayload(WorksmobileUserPayload{
|
||||
Email: "phone-canonical@samaneng.com",
|
||||
CellPhone: "+82+821062836786",
|
||||
UserName: WorksmobileUserName{LastName: "Phone Canonical User"},
|
||||
})
|
||||
|
||||
require.Len(t, payload.PhoneNumbers, 1)
|
||||
require.Equal(t, "+821062836786", payload.PhoneNumbers[0].Value)
|
||||
}
|
||||
|
||||
func TestWorksmobileHTTPClientUpsertUserPatchesOnCreateConflictWithoutPasswordOrPrivateEmail(t *testing.T) {
|
||||
transport := &captureRoundTripper{
|
||||
responses: []captureResponse{
|
||||
@@ -155,6 +177,7 @@ func TestWorksmobileHTTPClientResetUserPasswordPatchesPasswordConfig(t *testing.
|
||||
passwordConfig := payload["passwordConfig"].(map[string]any)
|
||||
require.Equal(t, "ADMIN", passwordConfig["passwordCreationType"])
|
||||
require.Equal(t, "Aa1!Aa1!Aa1!Aa1!", passwordConfig["password"])
|
||||
require.Equal(t, true, passwordConfig["changePasswordAtNextLogin"])
|
||||
}
|
||||
|
||||
func TestWorksmobileHTTPClientCreateUserRequiresDirectoryToken(t *testing.T) {
|
||||
@@ -225,6 +248,84 @@ func TestWorksmobileHTTPClientRequestsJWTBearerAccessToken(t *testing.T) {
|
||||
require.Equal(t, float64(1710003600), payload["exp"])
|
||||
}
|
||||
|
||||
func TestWorksmobileHTTPClientAppliesRateLimitBeforeDirectoryAPICalls(t *testing.T) {
|
||||
transport := &captureRoundTripper{
|
||||
statusCode: http.StatusCreated,
|
||||
body: `{}`,
|
||||
}
|
||||
limiter := &captureWorksmobileRateLimiter{}
|
||||
client := &WorksmobileHTTPClient{
|
||||
BaseURL: "https://works.example.test",
|
||||
DirectoryToken: "directory-token-1",
|
||||
HTTPClient: &http.Client{Transport: transport},
|
||||
RateLimiter: limiter,
|
||||
}
|
||||
|
||||
err := client.CreateUser(context.Background(), WorksmobileUserPayload{
|
||||
Email: "tester@samaneng.com",
|
||||
PasswordConfig: WorksmobilePasswordConfig{PasswordCreationType: "ADMIN", Password: "Aa1!Aa1!Aa1!Aa1!"},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"POST /v1.0/users"}, limiter.keys)
|
||||
require.Len(t, transport.requests, 1)
|
||||
}
|
||||
|
||||
func TestWorksmobileHTTPClientAppliesRateLimitBeforeOAuthTokenCalls(t *testing.T) {
|
||||
privateKey := testRSAPrivateKeyPEM(t)
|
||||
transport := &captureRoundTripper{
|
||||
statusCode: http.StatusOK,
|
||||
body: `{"access_token":"directory-token-from-jwt","token_type":"Bearer","expires_in":3600}`,
|
||||
}
|
||||
limiter := &captureWorksmobileRateLimiter{}
|
||||
client := &WorksmobileHTTPClient{
|
||||
HTTPClient: &http.Client{Transport: transport},
|
||||
RateLimiter: limiter,
|
||||
now: func() time.Time { return time.Unix(1710000000, 0) },
|
||||
OAuthConfig: WorksmobileOAuthConfig{
|
||||
ClientID: "client-id-1",
|
||||
ClientSecret: "client-secret-1",
|
||||
ServiceAccount: "service-account-1",
|
||||
PrivateKey: privateKey,
|
||||
Scope: "directory",
|
||||
TokenURL: "https://auth.example.test/oauth2/v2.0/token",
|
||||
},
|
||||
}
|
||||
|
||||
_, _, err := client.requestDirectoryAccessToken(context.Background(), time.Unix(1710000000, 0))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"POST /oauth2/v2.0/token"}, limiter.keys)
|
||||
require.Len(t, transport.requests, 1)
|
||||
}
|
||||
|
||||
func TestWorksmobileHTTPClientRateLimitKeyNormalizesResourceIDsAndDropsQuery(t *testing.T) {
|
||||
parsedURL, err := url.Parse("https://works.example.test/v1.0/users/user%40example.com/alias-emails/alias%40example.com?domainId=1")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(
|
||||
t,
|
||||
"POST /v1.0/users/{id}/alias-emails/{id}",
|
||||
worksmobileRateLimitKey(http.MethodPost, parsedURL),
|
||||
)
|
||||
|
||||
parsedURL, err = url.Parse("https://works.example.test/scim/v2/Users/works-user-1")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "PATCH /scim/v2/Users/{id}", worksmobileRateLimitKey(http.MethodPatch, parsedURL))
|
||||
}
|
||||
|
||||
func TestNewWorksmobileHTTPClientDoesNotInstallRateLimiterByDefault(t *testing.T) {
|
||||
client := NewWorksmobileHTTPClientWithAuth("directory-token", "scim-token", WorksmobileOAuthConfig{})
|
||||
|
||||
require.Nil(t, client.RateLimiter)
|
||||
}
|
||||
|
||||
func TestNewWorksmobileAPIRateLimiterCreatesLimiterForWorkerUse(t *testing.T) {
|
||||
limiter := NewWorksmobileAPIRateLimiter(240, time.Minute)
|
||||
|
||||
require.NotNil(t, limiter)
|
||||
}
|
||||
|
||||
func TestWorksmobileHTTPClientRequiresConfiguredAPIBaseURL(t *testing.T) {
|
||||
client := &WorksmobileHTTPClient{
|
||||
DirectoryToken: "directory-token-1",
|
||||
@@ -608,6 +709,18 @@ func TestWorksmobileRelayWorkerProcessesUserSuspendAndMarksProcessed(t *testing.
|
||||
require.Equal(t, []string{"tester@samaneng.com"}, client.suspendedUsers)
|
||||
}
|
||||
|
||||
func TestWorksmobileRelayWorkerProcessOnceRecoversPanic(t *testing.T) {
|
||||
repo := &fakeWorksmobileOutboxRepo{listReadyPanic: "list ready crashed"}
|
||||
client := &fakeWorksmobileDirectoryClient{}
|
||||
worker := NewWorksmobileRelayWorker(repo, client)
|
||||
|
||||
err := worker.ProcessOnce(context.Background())
|
||||
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "worksmobile relay panic")
|
||||
require.Contains(t, err.Error(), "list ready crashed")
|
||||
}
|
||||
|
||||
func TestWorksmobileRelayWorkerProcessesActiveUserUpsertAndReactivates(t *testing.T) {
|
||||
repo := &fakeWorksmobileOutboxRepo{
|
||||
ready: []domain.WorksmobileOutbox{
|
||||
@@ -736,6 +849,65 @@ func TestWorksmobileRelayWorkerSkipsDispatchWhenJobClaimFails(t *testing.T) {
|
||||
require.Empty(t, client.createdOrgUnits)
|
||||
}
|
||||
|
||||
func TestWorksmobileRelayWorkerSkipsProcessingWhenLeaderLockIsNotHeld(t *testing.T) {
|
||||
repo := &fakeWorksmobileOutboxRepo{
|
||||
ready: []domain.WorksmobileOutbox{
|
||||
{
|
||||
ID: "job-1",
|
||||
ResourceType: domain.WorksmobileResourceUser,
|
||||
ResourceID: "user-1",
|
||||
Action: domain.WorksmobileActionUpsert,
|
||||
Status: domain.WorksmobileOutboxStatusPending,
|
||||
Payload: worksmobileUserOutboxPayload("root-1", WorksmobileUserPayload{
|
||||
Email: "tester@samaneng.com",
|
||||
UserExternalKey: "user-1",
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
client := &fakeWorksmobileDirectoryClient{}
|
||||
worker := NewWorksmobileRelayWorker(repo, client)
|
||||
worker.SetLeaderLock(&fakeWorksmobileRelayLeaderLock{held: false})
|
||||
|
||||
err := worker.ProcessOnce(context.Background())
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, repo.listReadyCalls)
|
||||
require.Empty(t, repo.processingIDs)
|
||||
require.Empty(t, repo.processedIDs)
|
||||
require.Empty(t, client.createdUsers)
|
||||
}
|
||||
|
||||
func TestWorksmobileRelayWorkerProcessesWhenLeaderLockIsHeld(t *testing.T) {
|
||||
repo := &fakeWorksmobileOutboxRepo{
|
||||
ready: []domain.WorksmobileOutbox{
|
||||
{
|
||||
ID: "job-1",
|
||||
ResourceType: domain.WorksmobileResourceUser,
|
||||
ResourceID: "user-1",
|
||||
Action: domain.WorksmobileActionUpsert,
|
||||
Status: domain.WorksmobileOutboxStatusPending,
|
||||
Payload: worksmobileUserOutboxPayload("root-1", WorksmobileUserPayload{
|
||||
Email: "tester@samaneng.com",
|
||||
UserExternalKey: "user-1",
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
client := &fakeWorksmobileDirectoryClient{}
|
||||
lock := &fakeWorksmobileRelayLeaderLock{held: true}
|
||||
worker := NewWorksmobileRelayWorker(repo, client)
|
||||
worker.SetLeaderLock(lock)
|
||||
|
||||
err := worker.ProcessOnce(context.Background())
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, lock.ensureCalls)
|
||||
require.Equal(t, 1, repo.listReadyCalls)
|
||||
require.Equal(t, []string{"job-1"}, repo.processedIDs)
|
||||
require.Equal(t, "tester@samaneng.com", client.createdUsers[0].Email)
|
||||
}
|
||||
|
||||
func TestRedactWorksmobileOutboxPayloadsRemovesInitialPasswordFromOverview(t *testing.T) {
|
||||
jobs := []domain.WorksmobileOutbox{
|
||||
{
|
||||
@@ -1179,6 +1351,8 @@ type fakeWorksmobileOutboxRepo struct {
|
||||
payloadUpdates []domain.JSONMap
|
||||
deletedPendingTenantRootID string
|
||||
deletedPendingCount int
|
||||
listReadyCalls int
|
||||
listReadyPanic any
|
||||
markProcessingClaims map[string]bool
|
||||
processingIDs []string
|
||||
processedIDs []string
|
||||
@@ -1224,6 +1398,10 @@ func (f *fakeWorksmobileOutboxRepo) DeletePendingByTenantRoot(ctx context.Contex
|
||||
}
|
||||
|
||||
func (f *fakeWorksmobileOutboxRepo) ListReady(ctx context.Context, limit int) ([]domain.WorksmobileOutbox, error) {
|
||||
f.listReadyCalls++
|
||||
if f.listReadyPanic != nil {
|
||||
panic(f.listReadyPanic)
|
||||
}
|
||||
return f.ready, nil
|
||||
}
|
||||
|
||||
@@ -1282,6 +1460,25 @@ type captureResponse struct {
|
||||
body string
|
||||
}
|
||||
|
||||
type captureWorksmobileRateLimiter struct {
|
||||
keys []string
|
||||
}
|
||||
|
||||
func (l *captureWorksmobileRateLimiter) Wait(ctx context.Context, key string) error {
|
||||
l.keys = append(l.keys, key)
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
type fakeWorksmobileRelayLeaderLock struct {
|
||||
held bool
|
||||
ensureCalls int
|
||||
}
|
||||
|
||||
func (l *fakeWorksmobileRelayLeaderLock) EnsureLeadership(ctx context.Context) (bool, error) {
|
||||
l.ensureCalls++
|
||||
return l.held, ctx.Err()
|
||||
}
|
||||
|
||||
func (t *captureRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
t.request = req
|
||||
t.requests = append(t.requests, req)
|
||||
|
||||
Reference in New Issue
Block a user