Skip to content

test: end-to-end RP+OAuth integration tests#1327

Merged
SalimKayal merged 3 commits into
salimkayal-feat-resource-pools-access-through-integrationfrom
salimkayal-feat-rp-hpc-integration-tests
Jun 10, 2026
Merged

test: end-to-end RP+OAuth integration tests#1327
SalimKayal merged 3 commits into
salimkayal-feat-resource-pools-access-through-integrationfrom
salimkayal-feat-rp-hpc-integration-tests

Conversation

@SalimKayal

@SalimKayal SalimKayal commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

This chunk adds HTTP-level end-to-end tests that exercise the full integration between resource pools and OAuth2 providers through the Sanic test client. The tests verify that the auto-grant/revoke logic implemented in #1314 and #1317 works correctly from the API surface: users gain and lose resource pool visibility by connecting to and disconnecting from OAuth providers, and admins can swap provider linkages with immediate access changes.

Motivation & Context

While #1314 and #1317 (OAuth connect/disconnect hooks) were tested at the repository layer, we need confidence that the wiring between crc, connected_services, and Authz/SpiceDB holds up through the actual HTTP API. These tests simulate real user journeys:

  1. A regular user completes an OAuth2 authorization flow.
  2. A resource pool linked to that provider becomes visible to them.
  3. Disconnecting removes that visibility.
  4. Admin patch operations swap access between user populations correctly.

Design Decisions & Rationale

1. Test Through the Real HTTP Surface

Rather than calling repository methods directly, these tests use SanicASGITestClient to hit the actual endpoints (POST /api/data/resource_pools, GET /api/data/oauth2/providers/{id}/authorize, GET /api/data/oauth2/callback, etc.). This validates:

  • Blueprint wiring (e.g., ConnectedServicesRepository._on_oauth2_connected is actually invoked from the callback handler).
  • Authz propagation to the visibility layer (GET /api/data/resource_pools filters based on SpiceDB relations).
  • Request/response serialization and validation.

2. Reuse the Dummy OAuth Client

Tests in test_resource_pools.py patch app_manager_instance.oauth_http_client_factory.create_client = create_dummy_oauth_client to avoid real external OAuth exchanges. This is the same pattern already used in test_connected_services.py and keeps the tests fast, deterministic, and offline.

3. Shared Helper for OAuth Flow Completion

A local helper _complete_oauth_flow(test_client, provider_id, user_headers) was added in test_resource_pools.py to avoid duplication across the three new tests. It performs the authorize → extract state → callback dance that the dummy OAuth client requires.

4. Isolation via xdist_group("sessions")

Resource pool API tests are marked with @pytest.mark.xdist_group("sessions") to prevent parallel test interference on shared database/cluster state. This follows the existing convention in the test file.

5. Explicit Migration Call

test_connected_services.py tests call run_migrations_for_app("common") at the start because they rely on the full application stack (including Authz/SpiceDB consistency) and the app_manager_instance fixture. This matches patterns from earlier diffs.

Changes

  • test/bases/renku_data_services/data_api/test_resource_pools.py

    • Added _complete_oauth_flow helper.
    • Added test_post_resource_pool_with_remote_grants_connected_users:
      • Admin creates provider, regular user connects, admin creates linked RP, user sees it in GET /resource_pools.
    • Added test_delete_resource_pool_removes_access:
      • Same setup, admin deletes RP, user no longer sees it.
    • Added test_patch_resource_pool_remote_change_swaps_access:
      • Two providers (P1, P2), two users, RP linked to P1. User1 sees it, User2 does not. Admin patches RP to P2. User1 loses access, User2 gains it.
  • test/bases/renku_data_services/data_api/test_connected_services.py

    • Added imports: run_migrations_for_app, KindCluster.
    • Added test_oauth_callback_adds_user_to_rp:
      • Admin creates provider and linked private RP. Regular user cannot see RP. User completes OAuth callback. User can now see RP.
    • Added test_delete_oauth_connection_removes_rp_access:
      • Same setup, user completes OAuth callback and can see RP. User deletes their OAuth connection. User can no longer see RP.

Behavioral Changes (Verified by Tests)

This PR contains no new production code; it only adds tests. However, it verifies the following behavioral changes introduced by #1314 and #1317:

Observable Behavior: OAuth Connection Drives RP Visibility

  • Before the feature: A regular user could only see a private resource pool if an admin explicitly added them as a member.
  • After the feature: A regular user automatically sees private resource pools whose remote.provider_id matches an OAuth provider they are connected to. This is visible at the API level via GET /api/data/resource_pools.

Observable Behavior: Disconnect Immediately Revokes Visibility

  • Before the feature: Revoking access required an admin to manually remove the user from the resource pool.
  • After the feature: A user who deletes their OAuth2 connection (DELETE /api/data/oauth2/connections/{id}) immediately loses visibility of all resource pools tied to that provider.

Observable Behavior: Provider Swap Atomically Exchanges Populations

  • Before the feature: Changing a resource pool's provider had no membership side effects.
  • After the feature: Patching remote.provider_id from P1 to P2 causes all connected P1 users to lose access and all connected P2 users to gain access in a single operation.

PR Stack

@SalimKayal SalimKayal changed the title Salimkayal feat rp hpc integration tests test: resource pool HPC integrations integration tests May 21, 2026
@SalimKayal SalimKayal force-pushed the salimkayal-feat-rp-hpc-integration-tests branch from 1564a19 to 898df74 Compare May 29, 2026 15:00
@SalimKayal SalimKayal force-pushed the salimkayal-feat-resource-pools-access-through-integration branch from 52fa3bd to 2ac8da5 Compare May 29, 2026 15:01
@SalimKayal SalimKayal changed the title test: resource pool HPC integrations integration tests test: end-to-end RP+OAuth integration tests May 29, 2026
@SalimKayal SalimKayal force-pushed the salimkayal-feat-rp-hpc-integration-tests branch from 898df74 to d6cc1d4 Compare June 10, 2026 06:56
@SalimKayal SalimKayal marked this pull request as ready for review June 10, 2026 06:56
@SalimKayal SalimKayal requested review from a team and sgaist as code owners June 10, 2026 06:56
@SalimKayal SalimKayal requested review from leafty, olevski and sambuc June 10, 2026 06:56
Comment on lines +3058 to +3060
@pytest.mark.asyncio
@pytest.mark.xdist_group("sessions")
async def test_delete_resource_pool_removes_access(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test feels unnecessary. The OAuth 2.0 automation is not playing a role since deleting a resource pool deletes said resource pool.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removed.

@coveralls

coveralls commented Jun 10, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 27261227871

Warning

No base build found for commit 09ef102 on salimkayal-feat-resource-pools-access-through-integration.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 86.311%

Details

  • Patch coverage: No coverable lines changed in this PR.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 31179
Covered Lines: 26911
Line Coverage: 86.31%
Coverage Strength: 1.5 hits per line

💛 - Coveralls

@SalimKayal SalimKayal merged commit c98413c into salimkayal-feat-resource-pools-access-through-integration Jun 10, 2026
18 checks passed
@SalimKayal SalimKayal deleted the salimkayal-feat-rp-hpc-integration-tests branch June 10, 2026 09:24
SalimKayal added a commit that referenced this pull request Jun 10, 2026
* test: add RP remote provider end-to-end tests

* test: add OAuth callback RP access end-to-end tests

* chore: remove useless test
SalimKayal added a commit that referenced this pull request Jun 10, 2026
* test: add RP remote provider end-to-end tests

* test: add OAuth callback RP access end-to-end tests

* chore: remove useless test
SalimKayal added a commit that referenced this pull request Jun 10, 2026
* test: add RP remote provider end-to-end tests

* test: add OAuth callback RP access end-to-end tests

* chore: remove useless test
SalimKayal added a commit that referenced this pull request Jun 11, 2026
…ge (#1315)

* feat: sync resource pool viewer access on OAuth2 connect and disconnect (#1317)

* feat: sync RP access on OAuth connect/disconnect

Add _on_oauth2_connected and _on_oauth2_disconnected helpers
that auto-grant/revoke viewer access to resource pools linked
to the provider. Wire member_repo through constructors.

5 new tests cover: connect grant, disconnect revoke, no-match
no-op, multi-user grant, isolated disconnect.

* feat: trigger RP sync in OAuth flows

Call _on_oauth2_connected after successful fetch_token in authorize
callback. Call _on_oauth2_disconnected before deleting connection row.
Add test verifying delete_oauth2_connection revokes RP access.

* fix: wire member_repo and fix types

- Fix forward reference in dependencies.py by initializing
  connected_services_repo without member_repo and setting it later
- Add user_id/client_id to OAuth2Connection model for type safety
- Guard blueprint callback against None values
- Remove debug logging from _on_oauth2_connected

* chore: logging

* fix: ensure session deletion, remove repetition

* chore: public naming for on_oauth2*

* refactor: remove need for `| None` annotation

* refactor: apply changes in rp memberships in one go

* feat: transmit sessions

* fix: one session per authz op

* fix: remove useless session

* feat: auto-grant/revoke resource pool viewer access on CRUD based on OAuth2 provider linkage (#1314)

* chore: feature branch

* feat: inject MemberRepository into ResourcePoolRepository + add failing tests for RP remote provider sync

- Add member_repo parameter to ResourcePoolRepository constructor
- Wire member_repo in dependencies.py and test/utils.py
- Add TDD tests for auto-grant/revoke on RP CRUD operations

* feat: add helper to query connected users by provider_id

Adds _get_connected_user_ids to ResourcePoolRepository for fetching
users with a connected OAuth2 link to a given provider.

* feat: auto-sync viewers on RP remote provider update

When updating a resource pool's remote provider:
- Capture old provider_id before the transaction
- After the transaction, revoke connected users of the old provider
- Grant connected users of the new provider
- Log warnings on soft failure

* test: fix RP update tests by adding required default class

* test: fix sentinel value error by inserting connections in separate sessions

* style: format and sort imports in test_sqlalchemy_pool_repo.py

* fix: validate provider on RP update and handle stale users in sync

- Add OAuth2ClientORM existence check when updating resource pool remote
  provider_id, matching the validation already done on insert.
- Remove pre-transaction query for old_provider_id to eliminate race
  condition; capture it from the already-loaded ORM inside the tx.
- Grant/revoke auto-synced memberships individually instead of bulk,
  so one missing Keycloak user does not abort the whole operation.

* test: add regression tests for RP remote provider edge cases

- Test that updating a resource pool to a non-existent provider_id fails.
- Test that insert/update auto-grants skip users missing from Keycloak
  instead of failing the entire batch.
- Test that swapping remote providers skips stale connected users.

* squashme: formatting

* fix: use authz in tests after rebase

* refactor: batch authz ops

* refactor: remove duplicate session

* fix: allow missing for grant members on resource pools

* feat: sync resource pool viewer access on OAuth2 connect and disconnect (#1317)

* feat: sync RP access on OAuth connect/disconnect

Add _on_oauth2_connected and _on_oauth2_disconnected helpers
that auto-grant/revoke viewer access to resource pools linked
to the provider. Wire member_repo through constructors.

5 new tests cover: connect grant, disconnect revoke, no-match
no-op, multi-user grant, isolated disconnect.

* feat: trigger RP sync in OAuth flows

Call _on_oauth2_connected after successful fetch_token in authorize
callback. Call _on_oauth2_disconnected before deleting connection row.
Add test verifying delete_oauth2_connection revokes RP access.

* fix: wire member_repo and fix types

- Fix forward reference in dependencies.py by initializing
  connected_services_repo without member_repo and setting it later
- Add user_id/client_id to OAuth2Connection model for type safety
- Guard blueprint callback against None values
- Remove debug logging from _on_oauth2_connected

* chore: logging

* fix: ensure session deletion, remove repetition

* chore: public naming for on_oauth2*

* refactor: remove need for `| None` annotation

* refactor: apply changes in rp memberships in one go

* feat: transmit sessions

* fix: one session per authz op

* fix: remove useless session

* chore: feature branch

* refactor: use update_membership for clarity

* chore: raise ValidationError instead of MissingResourceError

* fix: reuse sessions when possible

* chore: add TODO for session reuse in AUTHZ

* test: end-to-end RP+OAuth integration tests (#1327)

* test: add RP remote provider end-to-end tests

* test: add OAuth callback RP access end-to-end tests

* chore: remove useless test
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.

3 participants