test(backend): add Layer 1+2 tests for backend plugins and auth resolvers (RHIDP-13233)#4863
Conversation
…n pilot Implements RHIDP-13233 (Test Layer Infrastructure epic, RHIDP-13496). Layer 1 (unit/router): - licensed-users-info: cover /users/quantity (200 + 403), /users (200, CSV, 403), and add direct unit tests for rowToResponse (SQL/ISO/invalid dates) and permissionCheck (ALLOW/DENY). router.ts coverage 0 -> 94.6%. - licensed-users-info: new readBackstageTokenExpiration unit tests (default, in-range, min/max clamp). 100% covered. - dynamic-plugins-info: assert installer stripping, empty list, and auth enforcement on /loaded-plugins; refactor to a shared buildApp helper. Layer 2 (integration): - licensed-users-info: new startTestBackend pilot that boots the real plugin against SQLite and hits /health. plugin.ts coverage 0 -> 100%, runs in ~3s. Overall licensed-users-info coverage ~17% -> 86%. No cluster required. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Skipping CI for Draft Pull Request. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4863 +/- ##
===========================================
+ Coverage 41.03% 72.71% +31.67%
===========================================
Files 121 120 -1
Lines 2220 4914 +2694
Branches 562 558 -4
===========================================
+ Hits 911 3573 +2662
- Misses 1304 1340 +36
+ Partials 5 1 -4
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
Address review feedback on the Layer 1+2 backend tests: - licensed-users-info: cover the SQLite in-memory auto-disable path (empty router + warn), the CSV conversion failure (500), and the no-catalog-match enrichment branch. Add Layer 1 unit tests for CatalogEntityStore (ref mapping/filtering) and DatabaseUserInfoStore (count + "no user info found" error). Add clamp boundary cases. - dynamic-plugins-info: replace the DynamicPluginManager private-field hack with a stub against the public plugins() contract, cover the front-end plugin branch, and add a Layer 2 integration test that boots the real plugin via a mocked dynamicPluginsServiceRef. - Dedup the permissionCheck setup with a small helper. Both plugins now report 100% statement/branch/function/line coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The container image build workflow finished with status: |
Expand Layer 1+2 coverage to the remaining backend code: - scalprum-backend: add a Layer 2 integration test (boots the real plugin via a mocked dynamicPluginsServiceRef) and a unit test for the "no matching package" warn branch. Plugin now at 100% coverage. - packages/backend auth resolvers (previously 0%): unit tests for resolverUtils (createOidcSubClaimResolver sub/id-token/mismatch paths, trySignInResolvers fallthrough) and rhdhSignInResolvers (preferred username, oauth2-proxy header precedence, LDAP uuid matching, Keycloak and Ping Identity sub-claim wiring, dangerous fallback options). resolverUtils.ts, rhdhSignInResolvers.ts and scalprum router/plugin all report 100% coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address review feedback on the sign-in resolver tests: - oauth2-proxy: split the fallback test into an explicit precedence case (preferred-username wins when both headers are present) and the x-forwarded-user fallback, so the header ordering is actually pinned. - trySignInResolvers: assert each resolver is attempted exactly once for both the skip-then-succeed and all-fail paths, locking the iteration contract against short-circuit regressions. - createOidcSubClaimResolver: cover an id token that carries no sub claim. - Use `as unknown as` for the empty context/info doubles. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The container image build workflow finished with status: |
A single startTestBackend smoke per plugin underused Layer 2. Add a distinct end-to-end scenario to each so the real wiring (HTTP routing, auth, config-driven init, static serving) is actually exercised: - scalprum: boot a web plugin from a mock dist-scalprum directory and assert both the /plugins listing and the statically served manifest. - dynamic-plugins-info: assert installer details are stripped over the real backend, and that service principals (not just users) are authorized to read the plugin list. - licensed-users-info: assert the plugin disables all routes (404) when configured with a pure in-memory SQLite database, through real init. All three plugins remain at 100% coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The container image build workflow finished with status: |
pluginIDProviderService derives RBAC plugin ids from dynamic backend packages via a regex that strips scope/plugin prefixes and the -backend-dynamic suffix — previously untested. Add Layer 1 tests (via ServiceFactoryTester) covering the core ids, name normalization across @scope/plugin-, backstage-plugin- and bare prefix styles, and exclusion of non-backend packages. The factory logic is now 100% branch-covered. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The container image build workflow finished with status: |
The comment layout already renders a `components` section but no components were defined, so the dashboard and PR comment showed none. Define path-based components for the main source areas (backend plugins, backend app, frontend app, plugin-utils, dynamic-plugins utils) so coverage is visible per area. Components are views over existing uploads, so no CI changes are needed; statuses are informational while coverage matures, matching the project/patch approach. Validated via codecov.io/validate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The container image build workflow finished with status: |
|
/review |
PR Reviewer Guide 🔍Warning
Here are some key observations to aid the review process:
|
- scalprum integration test: create the mock directory at describe scope so its afterAll cleanup is registered and the temp dir does not leak across tests (Qodo: test isolation). - databaseUserInfoStore: expose the query spies from the Knex mock and assert the store calls the user_info table and the count query with the expected alias, so failures are clearer and less sensitive to the thenable/chainable interop (Qodo: mock robustness). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The container image build workflow finished with status: |
|
|
This PR is stale because it has been open 7 days with no activity. Remove stale label or comment or this will be closed in 21 days. |



Description
Implements RHIDP-13233 — Layer 1 + Layer 2 backend tests, the first story of the RHIDP-11861 / RHIDP-13496 Test Layer Infrastructure work.
Establishes fast (<10 min), cluster-free unit/integration tests for RHDH-owned backend code so PR feedback can gate merges without provisioning a cluster.
4-Layer model (scope of this story)
mockServices+ supertest (no DB, no cluster)startTestBackend+ in-memory wiring (real plugin boot, no cluster)Changes (test-only — no production code touched)
Backend plugins — all 3 RHDH-owned plugins, now 100% covered
licensed-users-info-backend(5 suites) —router.test.ts:/health,/users/quantity,/users(JSON, CSV, no-catalog-match, conversion-error, 403), and the SQLite in-memory auto-disable branch. NewreadBackstageTokenExpiration.test.ts(default / clamp / boundaries),catalogStore.test.ts(ref mapping + filtering + on-behalf-of token),databaseUserInfoStore.test.ts(count + error). Newrouter.integration.test.ts(Layer 2).dynamic-plugins-info-backend(2 suites) —router.test.tsrefactored to a stub against the publicplugins()contract; installer-stripping, empty-list, front-end-plugin and auth-enforcement tests. Newrouter.integration.test.ts(Layer 2 via mockeddynamicPluginsServiceRef).scalprum-backend(2 suites) — "no matching package" warn-branch unit test and newrouter.integration.test.ts(Layer 2, unauthenticated policy).Backend app auth sign-in resolvers (
packages/backend, previously 0% coverage)resolverUtils.test.ts—createOidcSubClaimResolver(sub / id-token / mismatch / no-sub-in-token / fallback) andtrySignInResolvers(first-success, skip-then-succeed, all-fail, with per-resolver call-count assertions).rhdhSignInResolvers.test.ts— preferred-username, oauth2-proxy header precedence (OAUTH_USER_HEADER→x-forwarded-preferred-username→x-forwarded-user), LDAP uuid matching (custom key, missing/mismatch), Keycloak and Ping Identity sub-claim wiring, dangerous fallback options.Coverage
Every touched backend source file reports 100% statements/branches/functions/lines:
licensed-users-info-backendrouter.ts,plugin.ts,catalogStore.ts,databaseUserInfoStore.ts,readBackstageTokenExpiration.tsdynamic-plugins-info-backendrouter.ts,plugin.tsscalprum-backendrouter.ts,plugin.tspackages/backendresolverUtils.ts,rhdhSignInResolvers.tsNotes
licensed-users-infoauto-disables under pure in-memory SQLite. Providingbackend.database.connection.directory: ':memory:'keeps it enabled while staying cluster-free (documented inline in the integration test).backstage-cli package test/ turbo setup — no new tooling or CI changes required.Testing
yarn tscpasses for all affected packagesTest with Node.js(required check) green — turbo--affectedruns the touched packagesCodecov configuration
Also adds a
component_managementsection tocodecov.yml(the comment layoutalready referenced
componentsbut none were defined). This gives a per-areacoverage breakdown — backend plugins, backend app, frontend app, plugin-utils,
dynamic-plugins utils — in the dashboard and PR comment. Components are
path-based views over existing uploads (no CI changes); statuses are
informational while coverage matures. Validated via
codecov.io/validate.