Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ TEST_PASSWORD_1=your-password-here
TEST_EMAIL_2=test-user-2@example.com
TEST_PASSWORD_2=your-password-here

# User 3
TEST_EMAIL_3=test-user-3@example.com
TEST_PASSWORD_3=your-password-here

# Test Configuration
TEST_USER_INDEX=1

Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/run-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ on:
required: false
TEST_PASSWORD_2:
required: false
TEST_EMAIL_3:
required: false
TEST_PASSWORD_3:
required: false
# Required in practice by api-smoke, declared optional so the existing
# callers (DataSpaceBackend, DataSpaceFrontend) keep parsing until they
# pass it. api-smoke preflights it and fails with a readable message
Expand Down Expand Up @@ -165,7 +169,13 @@ jobs:

- name: Run consumer smoke tests
run: |
pytest "${{ steps.markers.outputs.path }}" -m "${{ steps.markers.outputs.value }}" -v --json-report
# -n 4: unlike api-smoke/provider-smoke, nothing here needs a real
# login (no test_credentials/auth_token usage in tests/consumer/),
# so this isn't bounded by account count the way those two are.
# Picked against file count (7 files under tests/consumer/smoke/
# today, --dist loadfile keeps each on one worker) and typical
# GH-hosted runner core counts -- not account availability.
pytest "${{ steps.markers.outputs.path }}" -m "${{ steps.markers.outputs.value }}" -v --json-report -n 4

- name: Upload screenshots
if: always()
Expand Down Expand Up @@ -212,6 +222,15 @@ jobs:
HOME_URL_DEV: ${{ secrets.HOME_URL_DEV }}
TEST_EMAIL_1: ${{ secrets.TEST_EMAIL_1 }}
TEST_PASSWORD_1: ${{ secrets.TEST_PASSWORD_1 }}
# TEST_EMAIL_2 was never forwarded here despite this job already running
# -n 2 -- gw1 has been silently falling back to TEST_EMAIL_1 this whole
# time (conftest.py's test_credentials does that when a worker's slot has
# no matching credentials, rather than failing). Adding _2 fixes that
# existing gap; adding _3 is for the new worker below.
TEST_EMAIL_2: ${{ secrets.TEST_EMAIL_2 }}
TEST_PASSWORD_2: ${{ secrets.TEST_PASSWORD_2 }}
TEST_EMAIL_3: ${{ secrets.TEST_EMAIL_3 }}
TEST_PASSWORD_3: ${{ secrets.TEST_PASSWORD_3 }}
# Falls back to the dev backend so push/PR runs actually exercise the
# API tests. Without a default, `inputs` is empty on a push event, every
# api-smoke test skipped, and the job reported success having asserted
Expand Down Expand Up @@ -349,7 +368,11 @@ jobs:

- name: Run API smoke tests
run: |
pytest "${{ steps.markers.outputs.path }}" -m "${{ steps.markers.outputs.value }}" -v --json-report -n 2
# -n 3: matches the 3 configured test accounts (test_credentials maps
# gw0/gw1/gw2 -> TEST_EMAIL_1/2/3). Don't raise this without adding a
# 4th account first -- an extra worker with no matching credentials
# falls back to TEST_EMAIL_1 silently, not an error.
pytest "${{ steps.markers.outputs.path }}" -m "${{ steps.markers.outputs.value }}" -v --json-report -n 3

- name: Enforce minimum passed count
# Now that API_BASE_URL always has a value, this runs on every event,
Expand Down Expand Up @@ -421,9 +444,11 @@ jobs:
TEST_PASSWORD_1: ${{ secrets.TEST_PASSWORD_1 }}
TEST_EMAIL_2: ${{ secrets.TEST_EMAIL_2 }}
TEST_PASSWORD_2: ${{ secrets.TEST_PASSWORD_2 }}
TEST_EMAIL_3: ${{ secrets.TEST_EMAIL_3 }}
TEST_PASSWORD_3: ${{ secrets.TEST_PASSWORD_3 }}
# org_add_permission (conftest) resolves which orgs this worker's account
# can create content in. Without these it skips every org-create test on
# both workers -- including the account that has canAdd.
# any of the three workers -- including accounts that have canAdd.
API_BASE_URL: ${{ inputs.api_base_url || vars.API_BASE_URL || 'https://dev.api.civicdataspace.in' }}
KEYCLOAK_URL: ${{ vars.KEYCLOAK_URL || 'https://auth.civicdatalab.in' }}
KEYCLOAK_REALM: ${{ vars.KEYCLOAK_REALM || 'DataSpace' }}
Expand Down Expand Up @@ -514,7 +539,11 @@ jobs:

- name: Run provider smoke tests
run: |
pytest "${{ steps.markers.outputs.path }}" -m "${{ steps.markers.outputs.value }}" -v --json-report -n 2
# -n 3: matches the 3 configured test accounts, same reasoning as
# api-smoke above. --dist loadfile (pytest.ini) keeps the numbered
# provider flows in file order per worker, so each of the 3 accounts
# runs its own files start to finish rather than interleaving.
pytest "${{ steps.markers.outputs.path }}" -m "${{ steps.markers.outputs.value }}" -v --json-report -n 3

- name: Upload screenshots
if: always()
Expand Down
25 changes: 22 additions & 3 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,33 @@ def org_add_permission(test_credentials):
The org-scoped provider flows (create dataset / prompt dataset / usecase /
collaborative under an org) all need `canAdd` on some organization. A
Keycloak account whose org role is `auditor` has canAdd=false and cannot pass
those flows no matter how the UI is driven — TEST_EMAIL_2 is exactly that: a
lone `auditor` on CivicDataLab, which is why every org-create test failed on
gw1 while the read-only ones passed.
those flows no matter how the UI is driven.

That is an account-provisioning gap, not a product defect and not a test bug,
so the flows skip with a precise reason instead of failing. Grant the account
an `admin` (or otherwise canAdd) role on an org and they run again with no
code change.

Current roles (verified live against dev 2026-09-17 via this exact query —
re-check here before trusting this comment, don't just read it; it already
went stale once when TEST_EMAIL_2's role changed and nothing here was
updated to match):

- TEST_EMAIL_1 — admin/canAdd=true on 11 orgs (CivicDataLab, Open Budgets
India, JusticeHub, "my test agency", "test org name", ASDMA, HPSDMA, The
Rockefeller Foundation, Patrick J. McGovern Foundation, BMA, Gates
Foundation). Broadest account by far.
- TEST_EMAIL_2 — admin/canAdd=true on "my test agency" only; still
auditor/canAdd=false on CivicDataLab. Org-create flows for gw1 now run
(they used to skip), but land in "my test agency" specifically.
- TEST_EMAIL_3 — admin/canAdd=true on "my test agency" only, same as
TEST_EMAIL_2. Added 2026-09-17 for a 3rd xdist worker; already
write-capable from creation, nothing further to grant.

None of this suite's code hardcodes an org name — `writable` is whatever
the live permissions query returns for the account, and provider tests
pick from it dynamically. Don't add an assertion that assumes a specific
worker always lands on a specific org; these roles will change again.
"""
api = os.getenv("API_BASE_URL")
kc, realm = os.getenv("KEYCLOAK_URL"), os.getenv("KEYCLOAK_REALM")
Expand Down
Loading