Allow device routing without pinning
This commit is contained in:
@@ -360,7 +360,7 @@ test('a proxy regression rejects every device in that proxy sample atomically',
|
||||
assert.equal(snapshot.devices.find(({ mac }) => mac === macs[0]).uploadBytes, '11');
|
||||
});
|
||||
|
||||
test('pinned device policy persists, reconciles the full set, and keeps the last applied mode on failure', async (t) => {
|
||||
test('device policy is independent from pinning, persists, and keeps the last applied mode on failure', async (t) => {
|
||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'harbor-device-policy-'));
|
||||
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
||||
const store = createJsonStore({
|
||||
@@ -412,7 +412,6 @@ test('pinned device policy persists, reconciles the full set, and keeps the last
|
||||
assert.equal(snapshot.devices[0].desiredPolicy, 'vpn');
|
||||
assert.equal(snapshot.devices[0].appliedPolicy, 'vpn');
|
||||
|
||||
snapshot = service.update(id, { pinned: true }, snapshot.revision);
|
||||
snapshot = await service.setPolicy(id, 'direct', snapshot.revision);
|
||||
assert.deepEqual(appliedSets.at(-1), [{ id, ip: '192.168.50.7', mac, interface: 'eth0' }]);
|
||||
assert.equal(snapshot.devices[0].desiredPolicy, 'direct');
|
||||
@@ -424,10 +423,9 @@ test('pinned device policy persists, reconciles the full set, and keeps the last
|
||||
service = createService();
|
||||
snapshot = await service.reconcilePolicies();
|
||||
assert.equal(snapshot.devices[0].appliedPolicy, 'direct');
|
||||
assert.throws(
|
||||
() => service.update(id, { pinned: false }, snapshot.revision),
|
||||
(error) => error.code === 'REQUEST_INVALID',
|
||||
);
|
||||
snapshot = service.update(id, { pinned: true }, snapshot.revision);
|
||||
snapshot = service.update(id, { pinned: false }, snapshot.revision);
|
||||
assert.equal(snapshot.devices[0].appliedPolicy, 'direct');
|
||||
|
||||
policyEpoch = 'policy-epoch-b';
|
||||
activeDevices = [];
|
||||
@@ -467,7 +465,6 @@ test('pinned device policy persists, reconciles the full set, and keeps the last
|
||||
});
|
||||
snapshot = await service.refresh();
|
||||
const secondId = snapshot.devices.find((device) => device.mac === secondMac).id;
|
||||
snapshot = service.update(secondId, { pinned: true }, snapshot.revision);
|
||||
failApply = true;
|
||||
await assert.rejects(
|
||||
service.setPolicy(secondId, 'direct', snapshot.revision),
|
||||
|
||||
@@ -49,7 +49,7 @@ test('Gateway device inventory uses the existing accessible responsive drawer',
|
||||
assert.match(panel, /gatewayTotal > 0n && <span>Gateway/);
|
||||
assert.match(panel, /proxyTotal > 0n && <span className="is-proxy">Прокси/);
|
||||
assert.match(panel, /source\?\.traffic\?\.proxy\?\.error/);
|
||||
assert.match(panel, /client-device-traffic-slot[\s\S]*client-device-pin-wrap/);
|
||||
assert.match(panel, /client-device-pin-wrap[\s\S]*client-device-heading/);
|
||||
assert.doesNotMatch(panel, /client-device-details/);
|
||||
assert.match(panel, /api\.devices\.setPolicy\(device\.id, mode, snapshot\.revision\)/);
|
||||
assert.match(panel, /requestError\.code !== 'STATE_CONFLICT'[\s\S]*latestDevice\.desiredPolicy !== device\.desiredPolicy[\s\S]*api\.devices\.setPolicy\(device\.id, mode, latest\.revision\)/);
|
||||
@@ -58,16 +58,21 @@ test('Gateway device inventory uses the existing accessible responsive drawer',
|
||||
assert.match(panel, /client-drawer client-instructions client-devices/);
|
||||
assert.doesNotMatch(panel, /точная MAC|частная MAC|<dt>Источник<\/dt>/);
|
||||
assert.match(panel, /aria-pressed=\{device\.pinned\}/);
|
||||
assert.doesNotMatch(panel, /Закрепите устройство, чтобы изменить маршрут|Сначала верните маршрут через Gateway/);
|
||||
assert.match(panel, /maxLength="64"[\s\S]*autoFocus/);
|
||||
assert.match(styles, /\.client-devices \{\s*width: min\(560px, 100vw\)/);
|
||||
assert.match(styles, /\.client-device \{[\s\S]*gap: 3px;[\s\S]*padding: 10px 8px/);
|
||||
assert.match(styles, /\.client-device-heading \{[\s\S]*grid-template-columns: minmax\(0, 1fr\) auto 32px/);
|
||||
assert.match(styles, /\.client-device \{[\s\S]*grid-template-columns: 32px minmax\(0, 1fr\);[\s\S]*padding: 10px 8px/);
|
||||
assert.match(styles, /\.client-device-heading \{[\s\S]*grid-column: 2;[\s\S]*grid-template-columns: minmax\(0, 1fr\) auto/);
|
||||
assert.match(styles, /\.client-device-meta \{[\s\S]*grid-template-columns: minmax\(0, 1fr\) 72px auto/);
|
||||
assert.doesNotMatch(styles, /\.client-device-meta \{[^}]*margin-left/);
|
||||
assert.match(styles, /\.client-device-last-seen\.is-online \{[\s\S]*color: var\(--client-accent\)/);
|
||||
assert.match(styles, /\.client-text-morph-value \{[\s\S]*transition: opacity 360ms[\s\S]*filter 480ms/);
|
||||
assert.match(styles, /\.client-device-last-seen:hover \.client-text-morph-value\.is-relative[\s\S]*opacity: 1/);
|
||||
assert.match(styles, /\.client-device-pin-wrap\.client-tooltip-anchor:hover > \.client-tooltip[\s\S]*translate\(0, 0\)/);
|
||||
assert.match(styles, /\.client-device-pin:hover:not\(:disabled\) svg[\s\S]*translateY\(-2px\) rotate\(-12deg\)/);
|
||||
assert.match(styles, /\.client-device-pin\[aria-pressed="true"\] svg/);
|
||||
assert.match(styles, /\.client-device-edit:hover svg[\s\S]*translate\(1px, -1px\) rotate\(-4deg\)/);
|
||||
assert.match(styles, /\.client-devices-sort:hover \.client-devices-sort-icon[\s\S]*rotate\(360deg\)/);
|
||||
assert.match(styles, /\.client-devices-refresh-ring circle[\s\S]*client-devices-refresh-progress 15s/);
|
||||
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[\s\S]*\.client-device-policy[\s\S]*\.client-text-morph-value/);
|
||||
assert.match(styles, /\.client-drawer \{[\s\S]*z-index: 50;[\s\S]*box-shadow:/);
|
||||
@@ -97,7 +102,8 @@ test('device traffic formatting and sorting preserve uint64 precision and canoni
|
||||
{ id: 'b', uploadBytes: '9007199254740992', downloadBytes: '2' },
|
||||
{ id: 'c', uploadBytes: '10', downloadBytes: '10', proxyDownloadBytes: '100' },
|
||||
{ id: 'd', uploadBytes: '15', downloadBytes: '5', proxyUploadBytes: '100' },
|
||||
{ id: 'e', pinned: true, uploadBytes: '0', downloadBytes: '0' },
|
||||
];
|
||||
assert.deepEqual(sortDevicesByTraffic(devices, 'desc').map(({ id }) => id), ['b', 'a', 'c', 'd']);
|
||||
assert.deepEqual(sortDevicesByTraffic(devices, 'asc').map(({ id }) => id), ['c', 'd', 'a', 'b']);
|
||||
assert.deepEqual(sortDevicesByTraffic(devices, 'desc').map(({ id }) => id), ['e', 'b', 'a', 'c', 'd']);
|
||||
assert.deepEqual(sortDevicesByTraffic(devices, 'asc').map(({ id }) => id), ['e', 'c', 'd', 'a', 'b']);
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ test('server picker checks health only on manual refresh and bounds the result w
|
||||
assert.doesNotMatch(picker, /checkVisible\(\);/);
|
||||
assert.match(picker, /onClick={checkVisible}/);
|
||||
assert.match(picker, /\{ \.\.\.current\[id\], checking: true \}/);
|
||||
assert.match(picker, /700 - \(performance\.now\(\) - startedAt\)/);
|
||||
assert.match(picker, /900 - \(performance\.now\(\) - startedAt\)/);
|
||||
assert.match(picker, /\{ \.\.\.current\[id\], checking: false \}/);
|
||||
assert.match(picker, /\.slice\(page \* SERVER_RESULT_WINDOW, \(page \+ 1\) \* SERVER_RESULT_WINDOW\)/);
|
||||
assert.match(picker, /\.slice\(0, 30\)/);
|
||||
@@ -66,7 +66,9 @@ test('manual ping uses plain language and keeps results beside server names', ()
|
||||
assert.match(styles, /\.client-server-row \.client-server \{[\s\S]*?width: 120px;/);
|
||||
assert.match(styles, /\.client-server-health \{[\s\S]*?font-size: 9px;[\s\S]*?font-variant-numeric: tabular-nums;/);
|
||||
assert.match(styles, /\.client-server-meta \.client-server-health \{[\s\S]*?place-items: end start;[\s\S]*?padding-bottom: 7px;/);
|
||||
assert.match(styles, /\.client-server-health\.is-checking \.client-server-health-checking \{[\s\S]*?animation: client-server-check-spin 700ms linear infinite;/);
|
||||
assert.match(styles, /\.client-server-health\.is-checking \.client-server-health-checking \{[\s\S]*?animation: client-spin 900ms linear infinite;/);
|
||||
assert.match(styles, /\.client-server-check\.is-checking svg \{[\s\S]*?animation: client-spin 900ms linear infinite;/);
|
||||
assert.match(styles, /\.client-server-check:hover:not\(:disabled\) svg[\s\S]*?transform: rotate\(90deg\);/);
|
||||
assert.match(styles, /\.client-server-meta \{[\s\S]*?width: 42px;[\s\S]*?margin-left: 4px;/);
|
||||
assert.match(styles, /\.client-server-favorite \{[\s\S]*?position: absolute;[\s\S]*?width: 44px;/);
|
||||
assert.match(picker, /server={servers\[0\]}[\s\S]*?ping={pings\[servers\[0\]\.id\]}/);
|
||||
|
||||
Reference in New Issue
Block a user