2026-07-12 23:42:54 +05:30
|
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
|
import { login, resetToAmsterdam } from './utils/auth';
|
|
|
|
|
|
|
|
|
|
const ZT_PAGE = '/cgi-bin/luci/admin/services/zt-gateway';
|
|
|
|
|
|
|
|
|
|
test.describe('drain UI', () => {
|
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
|
|
|
await login(page);
|
|
|
|
|
await resetToAmsterdam(page);
|
|
|
|
|
await page.goto(ZT_PAGE);
|
|
|
|
|
await page.waitForSelector('.zt-mode-select');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test.afterEach(async ({ page }) => {
|
|
|
|
|
await resetToAmsterdam(page);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('selecting graceful mode shows drain timeout', async ({ page }) => {
|
|
|
|
|
await page.locator('.zt-mode-select').selectOption('graceful');
|
|
|
|
|
|
|
|
|
|
const timeoutRow = page.locator('.zt-drain-timeout-row');
|
|
|
|
|
await expect(timeoutRow).toBeVisible();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('switching with graceful mode shows drain panel', async ({ page }) => {
|
|
|
|
|
// Select tirunelveli radio
|
|
|
|
|
await page.locator('input[name="zt_gateway_region"][value="tirunelveli"]').check();
|
|
|
|
|
|
|
|
|
|
// Change mode to graceful
|
|
|
|
|
await page.locator('.zt-mode-select').selectOption('graceful');
|
|
|
|
|
|
2026-07-13 08:48:53 +05:30
|
|
|
// Stub status responses to report an active drain with remaining connections.
|
|
|
|
|
// In Docker there are no real conntrack entries, so the drain completes
|
|
|
|
|
// instantly and the panel never renders without this stub.
|
|
|
|
|
//
|
|
|
|
|
// LuCI sends ubus calls as JSON-RPC batches: [{method:"call", params:[..., "status", {}]}]
|
|
|
|
|
// and receives: [{result: [0, {gateways:[], drain:{...}}]}]
|
|
|
|
|
await page.route(/\/ubus/, async (route) => {
|
|
|
|
|
const postData = route.request().postData() || '';
|
|
|
|
|
if (!postData.includes('"status"')) {
|
|
|
|
|
return route.fallback();
|
|
|
|
|
}
|
2026-07-12 23:42:54 +05:30
|
|
|
|
2026-07-13 08:48:53 +05:30
|
|
|
// Fabricate a status response with an active drain state.
|
|
|
|
|
// We avoid route.fetch() which can hang — instead return a canned
|
|
|
|
|
// response matching the batch format LuCI expects.
|
|
|
|
|
const gateways = [
|
|
|
|
|
{ region: 'amsterdam', label: 'Amsterdam (ocirosea641)', ip: '10.99.12.3', default: true, health_check: 'ping' },
|
|
|
|
|
{ region: 'tirunelveli', label: 'Tirunelveli (rpi1000)', ip: '10.99.12.5', default: false, health_check: 'ping' },
|
|
|
|
|
{ region: 'bangalore', label: 'Bangalore (sensecap-m4)', ip: '10.99.12.4', default: false, health_check: 'ping' }
|
|
|
|
|
];
|
|
|
|
|
const body = [{
|
|
|
|
|
jsonrpc: '2.0',
|
|
|
|
|
id: 1,
|
|
|
|
|
result: [0, {
|
|
|
|
|
active_gateway: 'amsterdam',
|
|
|
|
|
active_ip: '10.99.12.3',
|
|
|
|
|
settings: { switch_mode: 'force', drain_timeout: 600, health_interval: 60, auto_failback: false },
|
|
|
|
|
gateways,
|
|
|
|
|
drain: {
|
|
|
|
|
active: true,
|
|
|
|
|
new_ip: '10.99.12.5',
|
|
|
|
|
old_ip: '10.99.12.3',
|
|
|
|
|
remaining_connections: 42
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
}];
|
2026-07-12 23:42:54 +05:30
|
|
|
|
2026-07-13 08:48:53 +05:30
|
|
|
await route.fulfill({
|
|
|
|
|
status: 200,
|
|
|
|
|
contentType: 'application/json',
|
|
|
|
|
body: JSON.stringify(body)
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Click "Switch to selected"
|
|
|
|
|
await page.locator('.cbi-button-positive').click();
|
|
|
|
|
|
|
|
|
|
// The next status poll (triggered by onSwitchClick's finally block)
|
|
|
|
|
// will return the stubbed drain state, causing the panel to render.
|
|
|
|
|
const drainPanel = page.locator('.zt-drain-panel');
|
|
|
|
|
await expect(drainPanel).toBeVisible({ timeout: 15_000 });
|
|
|
|
|
await expect(drainPanel).toContainText('Graceful drain progress');
|
|
|
|
|
|
|
|
|
|
// Panel references old and new IP addresses
|
|
|
|
|
await expect(drainPanel).toContainText(/\d+\.\d+\.\d+\.\d+/);
|
|
|
|
|
} finally {
|
|
|
|
|
await page.unroute(/\/ubus/);
|
|
|
|
|
}
|
2026-07-12 23:42:54 +05:30
|
|
|
});
|
|
|
|
|
});
|