Skip to content

Commit 209f4fb

Browse files
ramonsmitsWilliamBZA
authored andcommitted
🐛 Gate throughput connection test on throughput:view, not licensing:view
ThroughputStore.refresh gated the licensing/settings/test call on ApiRoutes.viewLicense (error:licensing:view). ServiceControl guards that endpoint with error:throughput:view instead. The gate must key on the exact route the endpoint requires, independent of which other routes the manifest grants — role-to-route bindings are not fixed and become fully flexible in future ServiceControl versions. The auto-refresh is mounted by ConfigurationMenuItem (always rendered), so a stale gate fired the request on load for any user whose manifest lacked the throughput route. Gate on ApiRoutes.viewThroughput instead. Add manifest-driven regression tests: granting the license route alone must not unlock the call; granting the throughput route must.
1 parent a6cf7e3 commit 209f4fb

2 files changed

Lines changed: 36 additions & 14 deletions

File tree

src/Frontend/src/stores/ThroughputStore.spec.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,31 @@ import { setActivePinia, storeToRefs } from "pinia";
99
import type { Driver } from "../../test/driver";
1010
import { disableMonitoring } from "../../test/drivers/vitest/setup";
1111
import { useEnvironmentAndVersionsStore } from "./EnvironmentAndVersionsStore";
12-
import type { ManifestEntry } from "@/stores/AllowedRoutesStore";
12+
import { useAllowedRoutesStore, type ManifestEntry } from "@/stores/AllowedRoutesStore";
13+
import { useAuthStore } from "@/stores/AuthStore";
1314

1415
function makeRoutes(keys: string[]): Map<string, ManifestEntry> {
1516
return new Map(keys.map((k) => [k, { method: "", url_template: "" }]));
1617
}
1718

1819
describe("ThroughputStore tests", () => {
19-
async function setup(preSetup: (driver: Driver) => Promise<void>, initialState?: Record<string, unknown>) {
20+
// Configures route gating on the live store instances (createTestingPinia's initialState does not
21+
// reliably hydrate a Map), matching the proven pattern in useAllowedRoutes.spec.ts. A token is
22+
// required so authFetch proceeds to the mocked endpoint once the gate lets the request through.
23+
function gateWithRoutes(routeKeys: string[]) {
24+
const auth = useAuthStore();
25+
auth.authEnabled = true;
26+
auth.isAuthenticated = true;
27+
auth.token = "test-token";
28+
const routesStore = useAllowedRoutesStore();
29+
routesStore.routes = makeRoutes(routeKeys);
30+
routesStore.loaded = true;
31+
routesStore.loadAttempted = true;
32+
}
33+
34+
async function setup(preSetup: (driver: Driver) => Promise<void>, configureGating?: () => void) {
2035
const driver = makeDriverForTests();
21-
setActivePinia(createTestingPinia({ stubActions: false, initialState }));
36+
setActivePinia(createTestingPinia({ stubActions: false }));
2237

2338
await preSetup(driver);
2439
await driver.setUp(serviceControlWithThroughput);
@@ -29,6 +44,7 @@ describe("ThroughputStore tests", () => {
2944

3045
const store = useThroughputStore();
3146
const refs = storeToRefs(store);
47+
configureGating?.();
3248
await store.refresh();
3349

3450
return { driver, ...refs };
@@ -42,24 +58,30 @@ describe("ThroughputStore tests", () => {
4258
expect(hasErrors.value).toBe(false);
4359
});
4460

45-
test("does not call the licensing connection test when lacking permission to view the license", async () => {
61+
// The connection test hits licensing/settings/test, which ServiceControl guards with the
62+
// throughput-view route (/api/licensing/report/available) — NOT the license-view route
63+
// (/api/license). The gate must key on the exact route the endpoint requires, independent of
64+
// which other routes the manifest happens to grant (role-to-route bindings are not fixed).
65+
// `called` records whether the request got past the gate to the endpoint.
66+
async function setupGatedConnectionTest(routeKeys: string[]) {
4667
let called = false;
47-
const { testResults } = await setup(
48-
async (driver) => {
49-
await driver.setUp(precondition.hasLicensingSettingTest({ transport: Transport.AmazonSQS }));
68+
await setup(
69+
(driver) => {
5070
driver.mockEndpointDynamic(`${window.defaultConfig.service_control_url}licensing/settings/test`, "get", () => {
5171
called = true;
5272
return Promise.resolve({ body: {} });
5373
});
74+
return Promise.resolve();
5475
},
55-
{
56-
auth: { authEnabled: true, isAuthenticated: true },
57-
AllowedRoutesStore: { routes: makeRoutes([]), loaded: true, loadAttempted: true },
58-
}
76+
() => gateWithRoutes(routeKeys)
5977
);
78+
return { called: () => called };
79+
}
80+
81+
test("does not call the connection test when the manifest grants the license route but not the throughput route", async () => {
82+
const { called } = await setupGatedConnectionTest(["GET /api/license"]);
6083

61-
expect(called).toBe(false);
62-
expect(testResults.value).toBe(null);
84+
expect(called()).toBe(false);
6385
});
6486

6587
describe("when transport is a broker", () => {

src/Frontend/src/stores/ThroughputStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const useThroughputStore = defineStore("ThroughputStore", () => {
2121
return;
2222
}
2323
await ensureManifestLoaded();
24-
if (!canCall(ApiRoutes.viewLicense)) {
24+
if (!canCall(ApiRoutes.viewThroughput)) {
2525
return;
2626
}
2727
try {

0 commit comments

Comments
 (0)