Skip to content

test: cover project users, organization users and teams - #237

Merged
pjcdawkins merged 11 commits into
mainfrom
cli-210-integration-tests-project-users-organization-users-and-teams
Oct 15, 2026
Merged

pjcdawkins merged 11 commits into
mainfrom
cli-210-integration-tests-project-users-organization-users-and-teams

Conversation

@pjcdawkins

Copy link
Copy Markdown
Contributor

Adds integration tests for the commands that grant or revoke access, and the mock API they need.

Mock API (pkg/mockapi), in new files to keep edits to shared files small:

  • user_access.go: project user-access GET/PATCH/DELETE (items now have self/update/delete links), project and organization invitations (409 when already invited, unless forced), organization members, and project environment types.
  • teams.go: teams, team members, team project access, and /projects/{id}/team-access.
  • Projects can have an owner.

None of these changes return activities: the CLI does not wait on them with centralized permissions, which the test config already enables.

Tests:

  • user:add, user:update, user:delete: invitations (including a repeated one), role merging and changes, the project owner guards, validation errors, and deletion with and without confirmation. user:get at the environment level, for an unknown user, and with the deprecated --role option.
  • organization:user:add/update/delete/get/list: invitation, adding an existing user, permission changes, "already set", the owner guard, and deletion with and without confirmation.
  • team:create (roles, --output-id, label uniqueness and conflicts), team:get/list/update/delete, team:project:add/delete/list, team:user:add/delete/list.

🤖 Generated with Claude Code

@upsun-dispatch upsun-dispatch Bot left a comment

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.

Note

Reviewed — No blocking findings · 🔵 2 minor points

🔍 Full review · 10 files reviewed

🔵 Minor points

  • pkg/mockapi/teams.go:358 — handleAddTeamProjects validates and appends inside the same loop. Take a body like [{"project_id":"betaprojectid"},{"project_id":"unknown"}]: the first item is appended to h.teamProjects[teamID] before the second fails, and the handler then returns 400. The request is reported as failed, but the team now has access to betaprojectid. A later team:projects call, or an assertion that a failed add changed nothing, sees that partial state. To fix it, validate every item before appending any.
  • pkg/mockapi/user_access.go:306 — handlePatchOrgMember writes h.orgMembers[orgID][i] = &patched straight into the backing array. That array is the slice the test passed to SetOrgMembers, so a PATCH changes the caller's slice. handlePatchProjectUserAccess (line 178) does the same with the SetUserGrants slice. The delete handlers in this file call slices.Clone first to avoid exactly this aliasing, so the two patch handlers break the convention and leak mutations into the test's own data.
Verification
  • handleDeleteTeam removes the team's members and project access too, so /projects/{id}/team-access never lists a deleted team.
  • lowercaseAlphanumericID and the /ref/users handler, which derives emails as <id>@example.com, exist in pkg/mockapi, so the expected user-id-2@example.com strings in the tests match what the mock serves.
  • The project and org invitation handlers return 409 only when force is false, so the repeated user:add (confirmed, then forced) records a second invitation, as TestUserAdd asserts.
  • All new handlers lock the embedded store: RLock for reads and Lock for writes, including initTeams, which documents that its caller holds the lock.

The change is test-only: new integration tests in integration-tests/ (org_user_test.go, team_test.go, user_access_test.go and the extended user_get_test.go) run against new mock API handlers. Nothing tests the mock handlers themselves beyond those integration tests, which run through the repository's make test-go target.

Review details
  • Commit: e8a740d
  • Model: claude-opus-5-5

Review 1 of 10 for this pull request · View the full run

pjcdawkins and others added 6 commits October 15, 2026 12:00
Add project user-access updates and deletion, project and organization
invitations, organization members, environment types, and teams with
their members and project access. Project owners are now served.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover invitations (including a repeated one), role merging and changes,
the project owner guards, deletion with and without confirmation, and
user:get at the environment level, for an unknown user, and with the
deprecated --role option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover org:user:list and org:user:get, inviting a user, adding an
existing user, permission changes (including "already set" and the
owner guard), and deletion with and without confirmation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover team:create (roles, --output-id, label uniqueness and conflicts),
team:get, team:list (in an organization and on a project), team:update,
team:delete, team:project:add/delete/list and team:user:add/delete/list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Validate all projects before adding any to a team, and copy the user
grants and organization members slices before patching them, so that
tests' own slices are not modified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pjcdawkins
pjcdawkins force-pushed the cli-210-integration-tests-project-users-organization-users-and-teams branch from 81a9aca to 218b38b Compare October 15, 2026 11:02

@upsun-dispatch upsun-dispatch Bot left a comment

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.

Note

Reviewed — No blocking findings · 🔵 1 minor point

🔍 Full review · 10 files reviewed

🔵 Minor point

  • pkg/mockapi/teams.go:137 — handleListTeams always sorts by Label and only checks whether sort starts with -. The field name is never read. TeamListCommand sends sort=&lt;field> from its --sort option, so a request like teams --sort created_at (or updated_at) still comes back in label order. A test that relies on any sort field other than label would get the wrong order with no warning.
Verification
  • handleAddTeamProjects validates every project ID (it must exist and belong to the team's organization) before appending any access.
  • handlePatchOrgMember and handlePatchProjectUserAccess both clone the slice before replacing the element, so the slices tests pass to SetOrgMembers/SetUserGrants are left unchanged.
  • SetTeams resets the member and project maps, and setupTeams calls SetTeamMembers/SetTeamProjects after it, so the seeded data survives.
  • handleProjectUserAccess now returns items built by newProjectUserAccess, which embeds *ProjectUserGrant, so the JSON keeps the same fields and adds self/update/delete links.

The new integration tests (TestUserAdd/Update/Delete, TestOrgUser, TestTeam*, plus the extra TestUserGet cases) exercise the new mock API routes. They run under the repository's Go integration test job. Apart from what those tests call, nothing covers the mock handlers.

Review details
  • Commit: 218b38b
  • Model: claude-opus-5-5

Review 3 of 10 for this pull request · View the full run

pjcdawkins and others added 3 commits October 15, 2026 12:03
Support sorting teams by label, created_at or updated_at (reversed with a
"-" prefix), and reject other fields. Cover team:list --sort and
--reverse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Align the new mocks with the API instead of the CLI's assumptions:

- Teams: PATCH returns the team, labels need not be unique, the list
  sorts by created_at by default and has reference links, and members
  must belong to the organization. Adding a project the team already
  has is a conflict, and removing one it lacks succeeds.
- Organization members: the owner cannot be updated or deleted (403),
  "admin" replaces other permissions, and the list has a count.
- Project user access: permissions are validated, deleting a missing
  grant succeeds, items include the project title, and the list only
  references users.
- Invitations: a project invitation's role is optional, environment type
  permissions are returned as "environments", forcing cancels the
  pending invitation, and organization invitations require permissions.
- Environment types have attributes, and errors use the API's formats.

The team:create test now expects a duplicate label to be accepted with
--no-check-unique.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pjcdawkins
pjcdawkins enabled auto-merge (squash) October 15, 2026 12:06

@upsun-dispatch upsun-dispatch Bot left a comment

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.

Note

Reviewed — No blocking findings · 🔵 1 minor point

🔍 Full review · 10 files reviewed

🔵 Minor point

  • pkg/mockapi/teams.go:414 — handleAddTeamProjects checks each item only against the team's existing h.teamProjects[teamID]. It never checks items against each other in the same request body. A body like [{"project_id":"betaprojectid"},{"project_id":"betaprojectid"}] passes validation, and the second loop then appends two TeamProjectAccess entries for the same project. team:projects then lists the project twice and project_count counts it twice. Calling the same endpoint twice gives 409 instead, so the duplicate is accepted only when it arrives in a single request.
Verification
  • handleAddTeamProjects now runs every validation check before it appends anything, so a failed request leaves teamProjects unchanged.
  • handlePatchProjectUserAccess and handlePatchOrgMember call slices.Clone on the stored slice before they write to an index, so tests' slices are not mutated.
  • handleListTeams handles the sort fields label, created_at and updated_at, and returns 400 for any other field; TeamListCommand sends sort=label by default, which the label-order assertions rely on.
  • The helpers the new files use (timeCompare, lowercaseAlphanumericID, writeProblem, uniqueMap) exist in the base package.

The change is test-only: new integration tests in integration-tests/{org_user,team,user_access}_test.go and new cases in user_get_test.go, all run against the extended mock API. The repository's Go test target (make test-go) runs them. Nothing tests the mock handlers directly.

Review details
  • Commit: 94dd22a
  • Model: claude-opus-5-5

Review 6 of 10 for this pull request · View the full run

pjcdawkins and others added 2 commits October 15, 2026 13:07
…quest

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-users-organization-users-and-teams' into cli-210-integration-tests-project-users-organization-users-and-teams
@pjcdawkins
pjcdawkins merged commit b9373e4 into main Oct 15, 2026
7 checks passed
@pjcdawkins
pjcdawkins deleted the cli-210-integration-tests-project-users-organization-users-and-teams branch October 15, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant