fix(gateway): require log-aware release controller

This commit is contained in:
2026-08-10 23:58:02 +00:00
parent 9ad1de28dd
commit c9e1200745
9 changed files with 107 additions and 12 deletions
@@ -34,6 +34,7 @@ type FixtureState = {
runtimeRunning: boolean;
requestBodies: Array<{ operation: string; body: unknown }>;
gatewayLogPollCount?: number;
gatewayLogsEmpty?: boolean;
capabilities?: Array<{ permission: string; scope: 'GLOBAL' | 'PROFILE'; scopes: string[] }>;
profileListDelayMs?: number;
profileNavigationDelayMs?: number;
@@ -178,6 +179,9 @@ const installFixture = async (page: Page, state: FixtureState) => {
const releaseOperation = state.gatewayOperations[0];
if (!releaseOperation) throw new Error('Release operation fixture is missing');
state.gatewayLogPollCount = (state.gatewayLogPollCount ?? 0) + 1;
if (state.gatewayLogsEmpty) {
return response({ operation: releaseOperation, entries: [] });
}
const completed = state.gatewayLogPollCount > 1;
return response({
operation: { ...releaseOperation, status: completed ? 'SUCCEEDED' : 'RUNNING' },
@@ -640,6 +644,35 @@ test('controls gateway deployment and rollback through the external controller q
expect(state.requestBodies.some((entry) => entry.operation === 'admin.releases.requestGatewayRollback')).toBe(true);
});
test('explains terminal releases created before controller progress logging', async ({ page }) => {
const state: FixtureState = {
operations: [],
gatewayOperations: [
{
id: '99999999-9999-4999-8999-999999999999',
type: 'DEPLOY',
status: 'SUCCEEDED',
sourceMode: 'COMMIT',
sourceRef: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
payload: {},
requestedBy: 'admin',
createdAt: '2026-08-01T02:00:00.000Z',
updatedAt: '2026-08-01T02:02:00.000Z',
},
],
gatewayLogsEmpty: true,
runtimeRunning: true,
requestBodies: [],
};
await installFixture(page, state);
await page.goto('admin/releases');
await expect(page.getByTestId('gateway-release-log')).toContainText(
'로그 지원 controller 적용 전 작업일 수 있습니다.'
);
await expect(page.getByTestId('gateway-release-log')).not.toContainText('controller 로그를 기다리고 있습니다');
});
test('renders a failed reset, retries it as a new operation, and reaches success', async ({ page }, testInfo) => {
const longError =
'선택한 커밋의 프로필 프로세스를 시작하지 못했습니다. 실패 원인을 확인한 뒤 동일 generation으로 재시도해 주세요.';
@@ -135,6 +135,17 @@ const gatewayForm = reactive({
const selectedGatewayOperation = computed(
() => gatewayReleaseOperations.value.find((operation) => operation.id === selectedGatewayOperationId.value) ?? null
);
const gatewayReleaseLogEmptyMessage = computed(() => {
const operation = selectedGatewayOperation.value;
const status = gatewayReleaseLogStatus.value || operation?.status;
if (!operation || !status || ['QUEUED', 'RUNNING'].includes(status)) {
return 'controller 로그를 기다리고 있습니다…';
}
if (operation.error) {
return `이 작업에는 controller 로그가 기록되지 않았습니다. 작업 오류: ${operation.error}`;
}
return '이 작업에는 controller 로그가 기록되지 않았습니다. 로그 지원 controller 적용 전 작업일 수 있습니다.';
});
const hasCapability = (permission: string): boolean =>
capabilities.value.some((entry) => {
if (entry.permission !== permission && entry.permission !== 'admin.profiles.manage') return false;
@@ -993,7 +1004,7 @@ onBeforeUnmount(() => {
data-testid="gateway-release-log"
>
<div v-if="!gatewayReleaseLogs.length" class="text-zinc-500">
controller 로그를 기다리고 있습니다
{{ gatewayReleaseLogEmptyMessage }}
</div>
<div
v-for="entry in gatewayReleaseLogs"