Improve local rules persistence and dirty-state handling
This commit is contained in:
@@ -172,6 +172,7 @@ setInterval(() => {}, 60_000);
|
||||
assert.deepEqual(initial.route.localRules, [
|
||||
{ type: 'domain_suffix', value: 'ru', enabled: true },
|
||||
]);
|
||||
assert.equal(initial.route.localRulesPendingRestart, false);
|
||||
assert.equal(JSON.stringify(initial).includes(subscriptionUrl), false);
|
||||
const stateKeys = Object.keys(initial).sort();
|
||||
let revision = initial.revision;
|
||||
@@ -238,7 +239,7 @@ setInterval(() => {}, 60_000);
|
||||
assert.equal((await mutation('/api/singbox/restart')).state.connection.desired, 'running');
|
||||
|
||||
const rulesRevision = revision;
|
||||
const routed = await mutation('/api/route-rules', 'PUT', {
|
||||
let routed = await mutation('/api/route-rules', 'PUT', {
|
||||
expectedRevision: rulesRevision,
|
||||
rules: [
|
||||
{ type: 'domain_suffix', value: 'ru', enabled: false },
|
||||
@@ -251,12 +252,26 @@ setInterval(() => {}, 60_000);
|
||||
{ type: 'domain', value: 'example.com', enabled: true },
|
||||
{ type: 'domain_suffix', value: 'example.org', enabled: true },
|
||||
]);
|
||||
assert.equal(routed.state.route.localRulesPendingRestart, false);
|
||||
assert.deepEqual(JSON.parse(fs.readFileSync(path.join(dir, 'sing-box-config.json'))).route.rules.slice(0, 3), [
|
||||
{ domain: ['example.com'], outbound: 'direct' },
|
||||
{ domain_suffix: ['example.org'], outbound: 'direct' },
|
||||
{ inbound: ['mixed-in'], outbound: 'test-vpn' },
|
||||
]);
|
||||
|
||||
await mutation('/api/singbox/stop');
|
||||
routed = await mutation('/api/route-rules', 'PUT', {
|
||||
expectedRevision: revision,
|
||||
rules: [
|
||||
...routed.state.route.localRules,
|
||||
{ type: 'domain_keyword', value: 'media', enabled: true },
|
||||
],
|
||||
});
|
||||
assert.equal(routed.state.connection.process, 'stopped');
|
||||
assert.equal(routed.state.route.localRulesPendingRestart, true);
|
||||
const restartedRules = await mutation('/api/singbox/restart');
|
||||
assert.equal(restartedRules.state.route.localRulesPendingRestart, false);
|
||||
|
||||
const invalidRules = await rawRequest(port, '/api/route-rules', 'PUT', {
|
||||
expectedRevision: revision,
|
||||
rules: [{ type: 'domain_regex', value: '.*' }],
|
||||
|
||||
16
test/web/rule-editor-contract.test.js
Normal file
16
test/web/rule-editor-contract.test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
const root = path.resolve(import.meta.dirname, '../..');
|
||||
const component = fs.readFileSync(path.join(root, 'src/web/components/ClientOverviewPage.jsx'), 'utf8');
|
||||
const styles = fs.readFileSync(path.join(root, 'src/web/styles.css'), 'utf8');
|
||||
|
||||
test('rule editor add latency stays constant and dirty exits are guarded', () => {
|
||||
const rowRule = /\.client-local-rule \{([\s\S]*?)\n\}/.exec(styles)?.[1] || '';
|
||||
assert.doesNotMatch(rowRule, /--rule-index|calc\(/);
|
||||
assert.match(component, /addEventListener\('beforeunload', warnBeforeUnload\)/);
|
||||
assert.match(component, /requestCloseLocalRules\(\)/);
|
||||
assert.match(component, /localRulesPendingRestart/);
|
||||
});
|
||||
Reference in New Issue
Block a user