Relationships
#614 UAT: Release channel CLI and adversarial tests
Opened by stack72 · 6/10/2026
Context
PR swamp-club/swamp#1552 adds release channel support (beta, rc, stable) to the extension system. This issue specifies the CLI UAT and adversarial tests needed to cover the new feature in swamp-club/swamp-uat.
Test file locations
- CLI tests: tests/cli/extension/ (new files)
- Adversarial tests: tests/cli/adversarial/ (new file)
CLI UAT Tests
tests/cli/extension/lifecycle/channel_push_test.ts
Tests for pushing extensions with release channels.
TEST-001: push --channel beta stores version as beta
- Push a test extension with --channel beta
- Verify via extension info --json that latestBeta is populated with the pushed version
- Verify that latestVersion (stable) is unchanged
TEST-002: push --channel rc stores version as rc
- Push a test extension with --channel rc
- Verify via extension info --json that latestRc is populated
TEST-003: push without --channel stores as stable
- Push a test extension with no --channel flag
- Verify latestVersion reflects the new version
- Verify latestRc and latestBeta are unaffected
TEST-004: push --channel rejects invalid values
- Run push with --channel nightly
- Assert exit code is non-zero
- Assert error message contains "Invalid release channel"
- Verify the version was NOT published (extension info unchanged)
TEST-005: push --channel beta then --channel rc stores both
- Push v1 with --channel beta, push v2 with --channel rc
- Verify latestBeta = v1, latestRc = v2, latestVersion unchanged
tests/cli/extension/lifecycle/channel_pull_test.ts
Tests for pulling extensions from specific channels.
TEST-006: pull without --channel gets latest stable
- Push v1 as stable, v2 as beta, v3 as rc
- Pull without --channel flag
- Verify upstream_extensions.json records v1 (stable), not v2 or v3
- Verify no channel field in lockfile entry (or channel = undefined)
TEST-007: pull --channel beta gets latest beta
- Push v1 as stable, v2 as beta
- Pull with --channel beta
- Verify upstream_extensions.json records v2
- Verify lockfile entry has channel: "beta"
TEST-008: pull --channel rc gets latest rc
- Push v1 as stable, v2 as rc
- Pull with --channel rc
- Verify upstream_extensions.json records v2
- Verify lockfile entry has channel: "rc"
TEST-009: pull --channel beta fails when no beta versions exist
- Push only a stable version
- Pull with --channel beta
- Assert exit code is non-zero
- Assert error contains "has no published beta versions"
TEST-010: pull with explicit version ignores channel
- Push v1 as beta
- Pull @name@v1 without --channel flag
- Verify it installs v1 (the explicit version works regardless of channel)
TEST-011: pull --channel rejects invalid values
- Run pull with --channel nightly
- Assert exit code is non-zero
- Assert error contains "Invalid release channel"
TEST-012: lockfile records channel on pull
- Pull with --channel rc
- Parse upstream_extensions.json
- Assert the entry has "channel": "rc"
TEST-013: lockfile defaults missing channel to stable behavior
- Manually write an upstream_extensions.json entry without a channel field
- Run extension list --json
- Verify the extension is treated as stable (no channel shown or channel: undefined)
tests/cli/extension/registry/channel_search_test.ts
Tests for searching with channel filters.
TEST-014: search without --channel shows stable-only results
- Push stable + beta versions
- Run search without --channel
- Verify results show the stable latest version
TEST-015: search --channel rc shows rc results
- Push rc version
- Run search --channel rc
- Verify results include the extension with rc version
TEST-016: search --channel rc --channel beta shows both
- Push beta + rc versions
- Run search --channel rc --channel beta
- Verify results include extensions from both channels
TEST-017: search --channel rejects invalid values
- Run search --channel nightly
- Assert exit code is non-zero
- Assert error contains "Invalid channel"
tests/cli/extension/registry/channel_info_test.ts
Tests for extension info with channel data.
TEST-018: info shows per-channel latest versions
- Push stable, beta, and rc versions
- Run extension info --json
- Verify latestVersion is the stable version
- Verify latestBeta is the beta version
- Verify latestRc is the rc version
TEST-019: info omits channel fields when no prerelease versions exist
- Push only stable versions
- Run extension info --json
- Verify latestRc is null and latestBeta is null
tests/cli/extension/lifecycle/channel_promote_test.ts
Tests for the promote command.
TEST-020: promote beta to rc succeeds
- Push v1 as beta
- Run promote v1 --channel rc
- Verify output contains "promoted from beta to rc"
- Verify versions endpoint shows v1 as rc (not beta)
TEST-021: promote beta to stable succeeds (skip rc)
- Push v1 as beta
- Run promote v1 --channel stable
- Verify output contains "promoted from beta to stable"
- Verify latestVersion includes v1
TEST-022: promote rc to stable succeeds
- Push v1 as rc
- Run promote v1 --channel stable
- Verify output contains "promoted from rc to stable"
TEST-023: promote rejects backward transition (stable to rc)
- Push v1 as stable
- Run promote v1 --channel rc
- Assert exit code is non-zero
- Assert error contains "Cannot demote" or "Cannot promote"
TEST-024: promote rejects same channel
- Push v1 as rc
- Run promote v1 --channel rc
- Assert exit code is non-zero
TEST-025: promote rejects invalid target channel
- Run promote with --channel beta
- Assert exit code is non-zero
- Assert error contains "Invalid target channel"
TEST-026: promote requires authentication
- Run promote without SWAMP_API_KEY
- Assert exit code is non-zero
- Assert error contains "Not authenticated"
TEST-027: promote --json returns structured output
- Push v1 as beta, promote to rc with --json
- Parse JSON output
- Verify fields: name, version, previousChannel, channel, message
tests/cli/extension/lifecycle/channel_update_test.ts
Tests for update behavior with channels.
TEST-028: update checks within installed channel
- Pull v1 as beta, then push v2 as beta
- Run extension update --json or extension outdated --json
- Verify it detects v2 as an available update (within beta channel)
- Verify it does NOT suggest the stable latest
TEST-029: outdated shows channel in output
- Pull beta extension, push newer beta
- Run extension outdated
- Verify output indicates the extension's channel
tests/cli/extension/lifecycle/channel_list_test.ts
TEST-030: extension list shows channel for non-stable installs
- Pull with --channel beta
- Run extension list --json
- Verify the entry has channel: "beta"
TEST-031: extension list omits channel for stable installs
- Pull without --channel
- Run extension list --json
- Verify channel is absent or undefined in the entry
Adversarial Tests
tests/cli/adversarial/channel_adversarial_test.ts
TEST-ADV-001: push same version to two different channels fails
- Push v1 as beta
- Attempt to push v1 again as rc (same version, different channel)
- Assert 409 Conflict / version already exists error
- Verify version remains as beta
TEST-ADV-002: promote after yank fails gracefully
- Push v1 as beta, then yank v1
- Attempt to promote v1 --channel rc
- Assert error (yanked version cannot be promoted)
TEST-ADV-003: pull --channel with explicit version ignores channel mismatch
- Push v1 as beta
- Pull @name@v1 --channel rc (explicit version + mismatched channel)
- Verify it installs v1 (explicit version takes precedence)
TEST-ADV-004: concurrent push to different channels
- Simultaneously push v1 as beta and v2 as rc
- Verify both succeed
- Verify versions endpoint shows v1 as beta and v2 as rc
TEST-ADV-005: promote during concurrent pull
- Push v1 as beta
- Start pulling --channel beta, concurrently promote v1 to rc
- Verify pull completes (either gets beta v1 or errors gracefully)
- Verify no corrupted state
TEST-ADV-006: lockfile without channel field is backward compatible
- Manually create upstream_extensions.json with entries that have no channel field (simulating pre-channel lockfiles)
- Run extension list, extension update, extension install
- Verify all commands treat the entries as stable
- Verify no crashes or parse errors
TEST-ADV-007: rapid promote chain (beta to rc to stable in quick succession)
- Push v1 as beta
- Promote to rc, immediately promote to stable
- Verify final state: v1 is stable
- Verify latestVersion reflects v1
- Verify latestRc and latestBeta are cleared
TEST-ADV-008: auto-resolve never installs prerelease
- Set up a trusted collective with both stable and beta versions
- Reference an unknown type that exists in a beta extension
- Verify auto-resolve installs the stable version, NOT the beta
- If no stable version exists, verify auto-resolve fails (does not fall back to beta)
TEST-ADV-009: promote with invalid version number
- Run promote with a version that does not exist
- Assert 404 or clear error message
- Verify extension state unchanged
TEST-ADV-010: promote without auth returns clear error
- Run promote without SWAMP_API_KEY set and without swamp auth login
- Assert exit code non-zero
- Assert error mentions authentication
Test infrastructure notes
- All channel tests need a registry (dev server or mocked). Use the existing registry_helpers.ts pattern from the UAT repo.
- Extension fixtures: create a minimal model extension fixture under tests/cli/fixtures/extensions/models/test/ that passes catalog validation (must have a method with a description field).
- Push tests need SWAMP_API_KEY and a collective with push permissions. Use the same env var pattern as existing registry tests.
- Promote tests are new — no existing pattern. Follow the runExpectingFailure / runJsonCommand pattern.
- The --channel flag tests should use runExpectingFailure for failure paths and runJsonCommand for success paths with structured output validation.
- Consider adding Zod schemas for promote output and channel fields on extension info/list to schemas.ts.
Open
No activity in this phase yet.
Sign in to post a ripple.