mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-22 03:02:35 +00:00
Auto-select hosted staging tenant
This commit is contained in:
parent
b73dab2b64
commit
5afffa17d3
3 changed files with 55 additions and 3 deletions
|
|
@ -254,7 +254,10 @@ repo-tracked operator command that composes the hosted signup/billing eval pack
|
|||
with the hosted mobile onboarding bootstrap helpers under
|
||||
`tests/integration/scripts/`, and those helpers must fail closed onto explicit
|
||||
target cloud host and control-plane URL input instead of silently defaulting to
|
||||
production infrastructure.
|
||||
production infrastructure. When the operator does not pin
|
||||
`PULSE_E2E_HOSTED_TENANT_ID`, that entrypoint may auto-select the newest active
|
||||
tenant exposed by the authenticated `/admin/tenants?state=active` control-plane
|
||||
view, but it must still fail closed when no active tenant is available.
|
||||
Those same governed release workflows also own the operator-facing wording for
|
||||
that promotion metadata. Human-visible workflow inputs, summaries, and error
|
||||
messages must describe the path as a prerelease or preview flow rather than
|
||||
|
|
|
|||
|
|
@ -33,6 +33,47 @@ require_env() {
|
|||
fi
|
||||
}
|
||||
|
||||
resolve_hosted_tenant_id() {
|
||||
if [[ -n "${PULSE_E2E_HOSTED_TENANT_ID}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local tenants_payload
|
||||
if ! tenants_payload="$(
|
||||
curl -fsS \
|
||||
-H "X-Admin-Key: ${PULSE_CP_ADMIN_KEY}" \
|
||||
-H 'Accept: application/json' \
|
||||
"${PULSE_CLOUD_BASE_URL%/}/admin/tenants?state=active"
|
||||
)"; then
|
||||
echo "Failed to list active hosted tenants from ${PULSE_CLOUD_BASE_URL}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! PULSE_E2E_HOSTED_TENANT_ID="$(
|
||||
printf '%s' "${tenants_payload}" | node -e '
|
||||
let input = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => {
|
||||
input += chunk;
|
||||
});
|
||||
process.stdin.on("end", () => {
|
||||
const parsed = JSON.parse(input);
|
||||
const tenants = Array.isArray(parsed?.tenants) ? parsed.tenants : [];
|
||||
const selected = tenants.find((entry) => typeof entry?.id === "string" && entry.id.trim() !== "");
|
||||
if (!selected) {
|
||||
process.exit(2);
|
||||
}
|
||||
process.stdout.write(selected.id.trim());
|
||||
});
|
||||
'
|
||||
)"; then
|
||||
echo "No active hosted tenant found; set PULSE_E2E_HOSTED_TENANT_ID explicitly." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Auto-selected active hosted tenant ${PULSE_E2E_HOSTED_TENANT_ID}"
|
||||
}
|
||||
|
||||
require_command curl
|
||||
require_command go
|
||||
require_command node
|
||||
|
|
@ -50,7 +91,6 @@ require_env "PULSE_CLOUD_SSH_TARGET" "${PULSE_CLOUD_SSH_TARGET}"
|
|||
require_env "PULSE_CP_ADMIN_KEY" "${PULSE_CP_ADMIN_KEY}"
|
||||
require_env "PULSE_E2E_STRIPE_API_KEY" "${PULSE_E2E_STRIPE_API_KEY}"
|
||||
require_env "PULSE_E2E_STRIPE_WEBHOOK_SECRET" "${PULSE_E2E_STRIPE_WEBHOOK_SECRET}"
|
||||
require_env "PULSE_E2E_HOSTED_TENANT_ID" "${PULSE_E2E_HOSTED_TENANT_ID}"
|
||||
|
||||
echo "[1/2] Running hosted signup and billing smoke against ${PULSE_CLOUD_BASE_URL}"
|
||||
(
|
||||
|
|
@ -64,6 +104,8 @@ echo "[1/2] Running hosted signup and billing smoke against ${PULSE_CLOUD_BASE_U
|
|||
node ./scripts/run-evals.mjs --mode deterministic --scenario "${HOSTED_SCENARIOS}"
|
||||
)
|
||||
|
||||
resolve_hosted_tenant_id
|
||||
|
||||
echo "[2/2] Running hosted mobile onboarding smoke against tenant ${PULSE_E2E_HOSTED_TENANT_ID}"
|
||||
bootstrap_args=(
|
||||
"${INTEGRATION_ROOT}/scripts/bootstrap-hosted-mobile-onboarding.mjs"
|
||||
|
|
|
|||
|
|
@ -79,8 +79,10 @@ async function listTenants(
|
|||
request: import('@playwright/test').APIRequestContext,
|
||||
baseURL: string,
|
||||
adminKey: string,
|
||||
state?: string,
|
||||
): Promise<Tenant[]> {
|
||||
const response = await request.get(`${baseURL}/admin/tenants`, {
|
||||
const suffix = state ? `?state=${encodeURIComponent(state)}` : '';
|
||||
const response = await request.get(`${baseURL}/admin/tenants${suffix}`, {
|
||||
headers: {
|
||||
'X-Admin-Key': adminKey,
|
||||
Accept: 'application/json',
|
||||
|
|
@ -174,6 +176,11 @@ test.describe.serial('Cloud billing lifecycle (post-checkout)', () => {
|
|||
}, { timeout: 60_000 }).toBe('active');
|
||||
expect(tenantID).toBeTruthy();
|
||||
|
||||
const activeTenants = await listTenants(page.request, baseURL, adminKey, 'active');
|
||||
const activeTenant = activeTenants.find((entry) => entry.id === tenantID);
|
||||
expect(activeTenant?.id).toBe(tenantID);
|
||||
expect(activeTenant?.state).toBe('active');
|
||||
|
||||
await stripeRequest<StripeSubscriptionResponse>(
|
||||
stripeSecretKey,
|
||||
`/v1/subscriptions/${encodeURIComponent(subscriptionID)}`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue