1
0
forked from baron/baron-sso

feat: update worksmobile sync and restore planning

This commit is contained in:
2026-06-01 17:01:53 +09:00
parent 6574fb54b9
commit 5c8a338085
36 changed files with 3922 additions and 243 deletions

View File

@@ -9,6 +9,7 @@ import (
"io"
"log/slog"
"net/http/httptest"
"strings"
"testing"
"github.com/gofiber/fiber/v2"
@@ -51,7 +52,13 @@ func TestWorksmobileHandlerReturnsOverviewForHanmacTenant(t *testing.T) {
func TestWorksmobileHandlerDownloadsInitialPasswordCSV(t *testing.T) {
h := NewWorksmobileHandler(&fakeWorksmobileAdminService{
credentials: []service.WorksmobileInitialPasswordCredential{
{Email: "user@hanmaceng.co.kr", InitialPassword: "Aa1!Aa1!Aa1!Aa1!", Status: "processed"},
{
Email: "user@hanmaceng.co.kr",
Name: "홍길동",
PrimaryLeafOrgName: "인재성장",
InitialPassword: "Aa1!Aa1!Aa1!Aa1!",
Status: "processed",
},
},
})
app := fiber.New()
@@ -63,8 +70,87 @@ func TestWorksmobileHandlerDownloadsInitialPasswordCSV(t *testing.T) {
require.Contains(t, resp.Header.Get("Content-Disposition"), "worksmobile_initial_passwords.csv")
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), "email,initialPassword,status,lastError")
require.Contains(t, string(body), "user@hanmaceng.co.kr,Aa1!Aa1!Aa1!Aa1!,processed,")
require.Contains(t, string(body), "email,name,primaryLeafOrgName,initialPassword,status,lastError")
require.Contains(t, string(body), "user@hanmaceng.co.kr,홍길동,인재성장,Aa1!Aa1!Aa1!Aa1!,processed,")
}
func TestWorksmobileHandlerPassesInitialPasswordBatchID(t *testing.T) {
fakeService := &fakeWorksmobileAdminService{
credentials: []service.WorksmobileInitialPasswordCredential{
{Email: "batch-user@hanmaceng.co.kr", InitialPassword: "BatchPass1!", Status: "pending"},
},
}
h := NewWorksmobileHandler(fakeService)
app := fiber.New()
app.Get("/tenants/:tenantId/worksmobile/initial-passwords.csv", h.DownloadInitialPasswordsCSV)
resp, err := app.Test(httptest.NewRequest("GET", "/tenants/hanmac-id/worksmobile/initial-passwords.csv?batchId=batch-1", nil))
require.NoError(t, err)
require.Equal(t, fiber.StatusOK, resp.StatusCode)
require.Equal(t, "batch-1", fakeService.downloadCredentialBatchID)
}
func TestWorksmobileHandlerPassesSyncUserCredentialBatchID(t *testing.T) {
fakeService := &fakeWorksmobileAdminService{}
h := NewWorksmobileHandler(fakeService)
app := fiber.New()
app.Post("/tenants/:tenantId/worksmobile/users/:userId/sync", h.SyncUser)
req := httptest.NewRequest("POST", "/tenants/hanmac-id/worksmobile/users/user-1/sync", strings.NewReader(`{"credentialBatchId":"batch-1"}`))
req.Header.Set("Content-Type", "application/json")
resp, err := app.Test(req)
require.NoError(t, err)
require.Equal(t, fiber.StatusAccepted, resp.StatusCode)
require.Equal(t, "batch-1", fakeService.syncUserCredentialBatchID)
}
func TestWorksmobileHandlerPassesPasswordResetCredentialBatchID(t *testing.T) {
fakeService := &fakeWorksmobileAdminService{}
h := NewWorksmobileHandler(fakeService)
app := fiber.New()
app.Post("/tenants/:tenantId/worksmobile/users/:userId/password/reset", h.ResetUserPassword)
req := httptest.NewRequest("POST", "/tenants/hanmac-id/worksmobile/users/user-1/password/reset", strings.NewReader(`{"credentialBatchId":"batch-1"}`))
req.Header.Set("Content-Type", "application/json")
resp, err := app.Test(req)
require.NoError(t, err)
require.Equal(t, fiber.StatusAccepted, resp.StatusCode)
require.Equal(t, "batch-1", fakeService.resetPasswordCredentialBatchID)
}
func TestWorksmobileHandlerReturnsCredentialBatchHistory(t *testing.T) {
h := NewWorksmobileHandler(&fakeWorksmobileAdminService{
credentialBatches: []service.WorksmobileCredentialBatch{
{BatchID: "batch-1", UserCount: 2, HasPasswords: true},
},
})
app := fiber.New()
app.Get("/tenants/:tenantId/worksmobile/credential-batches", h.ListCredentialBatches)
resp, err := app.Test(httptest.NewRequest("GET", "/tenants/hanmac-id/worksmobile/credential-batches", nil))
require.NoError(t, err)
require.Equal(t, fiber.StatusOK, resp.StatusCode)
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), `"batchId":"batch-1"`)
require.Contains(t, string(body), `"userCount":2`)
}
func TestWorksmobileHandlerDeletesCredentialBatchPasswords(t *testing.T) {
fakeService := &fakeWorksmobileAdminService{}
h := NewWorksmobileHandler(fakeService)
app := fiber.New()
app.Delete("/tenants/:tenantId/worksmobile/credential-batches/:batchId/passwords", h.DeleteCredentialBatchPasswords)
resp, err := app.Test(httptest.NewRequest("DELETE", "/tenants/hanmac-id/worksmobile/credential-batches/batch-1/passwords", nil))
require.NoError(t, err)
require.Equal(t, fiber.StatusOK, resp.StatusCode)
require.Equal(t, "batch-1", fakeService.deletedCredentialBatchID)
}
func TestWorksmobileHandlerLogsActionFailures(t *testing.T) {
@@ -91,9 +177,14 @@ func TestWorksmobileHandlerLogsActionFailures(t *testing.T) {
}
type fakeWorksmobileAdminService struct {
overview service.WorksmobileTenantOverview
credentials []service.WorksmobileInitialPasswordCredential
syncUserErr error
overview service.WorksmobileTenantOverview
credentials []service.WorksmobileInitialPasswordCredential
syncUserErr error
syncUserCredentialBatchID string
resetPasswordCredentialBatchID string
downloadCredentialBatchID string
deletedCredentialBatchID string
credentialBatches []service.WorksmobileCredentialBatch
}
func (f *fakeWorksmobileAdminService) GetTenantOverview(ctx context.Context, tenantID string) (service.WorksmobileTenantOverview, error) {
@@ -116,17 +207,33 @@ func (f *fakeWorksmobileAdminService) EnqueueOrgUnitDelete(ctx context.Context,
return &domain.WorksmobileOutbox{ID: "job-orgunit-delete", ResourceID: orgUnitID, Action: domain.WorksmobileActionDelete}, nil
}
func (f *fakeWorksmobileAdminService) EnqueueUserSync(ctx context.Context, tenantID, userID string) (*domain.WorksmobileOutbox, error) {
func (f *fakeWorksmobileAdminService) EnqueueUserSync(ctx context.Context, tenantID, userID, credentialBatchID string) (*domain.WorksmobileOutbox, error) {
f.syncUserCredentialBatchID = credentialBatchID
if f.syncUserErr != nil {
return nil, f.syncUserErr
}
return &domain.WorksmobileOutbox{ID: "job-user", ResourceID: userID}, nil
}
func (f *fakeWorksmobileAdminService) EnqueueUserPasswordReset(ctx context.Context, tenantID, userID, credentialBatchID string) (*domain.WorksmobileOutbox, error) {
f.resetPasswordCredentialBatchID = credentialBatchID
return &domain.WorksmobileOutbox{ID: "job-user-password-reset", ResourceID: userID}, nil
}
func (f *fakeWorksmobileAdminService) RetryJob(ctx context.Context, tenantID, jobID string) (*domain.WorksmobileOutbox, error) {
return &domain.WorksmobileOutbox{ID: jobID}, nil
}
func (f *fakeWorksmobileAdminService) ListInitialPasswordCredentials(ctx context.Context, tenantID string) ([]service.WorksmobileInitialPasswordCredential, error) {
func (f *fakeWorksmobileAdminService) ListInitialPasswordCredentials(ctx context.Context, tenantID, credentialBatchID string) ([]service.WorksmobileInitialPasswordCredential, error) {
f.downloadCredentialBatchID = credentialBatchID
return f.credentials, nil
}
func (f *fakeWorksmobileAdminService) ListCredentialBatches(ctx context.Context, tenantID string) ([]service.WorksmobileCredentialBatch, error) {
return f.credentialBatches, nil
}
func (f *fakeWorksmobileAdminService) DeleteCredentialBatchPasswords(ctx context.Context, tenantID, credentialBatchID string) (service.WorksmobileCredentialBatch, error) {
f.deletedCredentialBatchID = credentialBatchID
return service.WorksmobileCredentialBatch{BatchID: credentialBatchID}, nil
}