Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pkg/connector/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,18 @@ func (c *GoogleWorkspace) updateUserStatus(ctx context.Context, args *structpb.S
return nil, nil, err
}

user, err := withRateLimitWaitValue(ctx, func() (*directoryAdmin.User, error) {
return client.GetUserForProvisioning(ctx, userId)
})
if err != nil {
return nil, nil, fmt.Errorf("google-workspace: failed to get user %s for status update: %w", userId, err)
}
if user.Suspended == isSuspended {
return &structpb.Struct{Fields: map[string]*structpb.Value{
fieldSuccess: {Kind: &structpb.Value_BoolValue{BoolValue: true}},
}}, nil, nil
}

// update user.isSuspended state
err = withRateLimitWait(ctx, func() error {
_, err := client.UpdateUser(ctx, userId, &directoryAdmin.User{
Expand Down
21 changes: 21 additions & 0 deletions pkg/connector/actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,27 @@ func TestDisableEnableUser_IdempotentAndPayload(t *testing.T) {
}
}

func TestUpdateUserStatus_IsIdempotentForSuspendedUser(t *testing.T) {
state := &testServerState{users: map[string]*testUser{"alice": {Suspended: true, PrimaryEmail: "alice@example.com"}}}
server := newTestServer(state)
defer server.Close()

dir := newTestDirectoryService(t, server.URL, server.Client())
c := newTestConnector()
primeServiceCache(c, dir, nil)

args := &structpb.Struct{Fields: map[string]*structpb.Value{
argResourceID: {Kind: &structpb.Value_StringValue{StringValue: "alice"}},
"is_suspended": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
}}
if _, _, err := c.updateUserStatus(context.Background(), args); err != nil {
t.Fatalf("updateUserStatus: %v", err)
}
if state.putCount != 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: This only covers the short-circuit path. A regression that made updateUserStatus always return early (e.g. the guard becoming unconditional) would still pass. Consider adding a case where the requested state differs from the current one and asserting putCount == 1 plus the resulting Suspended value, mirroring TestDisableEnableUser_IdempotentAndPayload.

t.Fatalf("expected no PUT for an already suspended user, got %d", state.putCount)
}
}

func TestChangePrimaryEmail(t *testing.T) {
state := &testServerState{users: map[string]*testUser{"bob": {Suspended: false, PrimaryEmail: "bob@old.example.com"}}}
server := newTestServer(state)
Expand Down
Loading