Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions .github/workflows/server-parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,8 @@ jobs:
# Each database runs in six parts on separate runners: the native
# database suites and TLS checks, the shared corpus, its profiles and
# restart cases, the published-SDK direction profiles, the corrected
# marker cohort, and the other cohorts. The two MySQL 8 labels add a
# seventh, native-tests-b, for half their execution tests. Every part
# marker cohort, and the other cohorts. Each label adds a seventh,
# native-tests-b, for half its execution tests. Every part
# bootstraps the same database and native build; no part depends on
# another.
matrix:
Expand All @@ -496,9 +496,8 @@ jobs:
image: mirror.gcr.io/library/mysql@sha256:62fb722c78b24245ddff1796a0fcee4a49cc5b87e0aaaf20c92d1da9e0a2497b
# The expanded original was OOM-killed at 1 GiB during native pressure.
memory: 2g
# The two MySQL 8 labels' native suites were the slowest parts
# (about 21 min each, most of it the execution tests), so their
# execution tests run in two halves: native-tests runs the first
# The native execution suites run in two halves to keep one
# database label from holding the result: native-tests runs the first
# and native-tests-b the second. The bytewise-sorted test list is
# dealt round-robin, so each listed test runs in exactly one half
# and a new test joins one.
Expand All @@ -522,6 +521,12 @@ jobs:
image: mirror.gcr.io/library/mariadb@sha256:7db29378d4fdab73f8123bbc2b48905c90d1a4b00cf848b028f1e81e623257f2
# Both expanded originals exhausted the 512 MiB DB fixture ceiling.
memory: 1g
execution_shards: 2
- label: mariadb-10.11
part: native-tests-b
image: mirror.gcr.io/library/mariadb@sha256:7db29378d4fdab73f8123bbc2b48905c90d1a4b00cf848b028f1e81e623257f2
memory: 1g
execution_shards: 2
env:
DW_PARITY_PART: ${{ matrix.part }}
DW_EXECUTION_SHARDS: ${{ matrix.execution_shards || 1 }}
Expand Down Expand Up @@ -707,7 +712,7 @@ jobs:
-v "$PWD:/source:ro" -v "$PWD/cargo-home:/cargo" -v "$PWD/rust-target:/target" \
-v "$PWD/parity-evidence:/evidence" -w /source/rust --entrypoint bash \
"${NATIVE_RUST_IMAGE}" -c \
'case "$DW_PARITY_PART" in native-tests) shard=1 suffix= ;; native-tests-b) shard=2 suffix=-b ;; *) shard= ;; esac; if [ "$DW_PARITY_PART" = native-tests ]; then cargo test --locked --offline --lib runtime::mysql:: -- --ignored --skip runtime::mysql::tests::bootstrap_child --nocapture --test-threads=2 > /evidence/mysql-tests.txt || exit 1; fi; if [ -n "$shard" ]; then cargo test --locked --offline --test execution -- --list --format terse | sed -n "s/: test\$//p" | LC_ALL=C sort | awk -v count="$DW_EXECUTION_SHARDS" -v shard="$shard" "(NR - 1) % count == shard - 1" > /evidence/execution-shard$suffix.txt && test -s /evidence/execution-shard$suffix.txt && cargo test --locked --offline --test execution -- --exact --nocapture --test-threads=2 $(cat /evidence/execution-shard$suffix.txt) > /evidence/mysql-execution-tests$suffix.txt || exit 1; fi; case "$DW_PARITY_PART" in native-tests|native-tests-b) cargo build --locked --offline ;; *) test -x /target/debug/durable-workflow-server ;; esac'
'case "$DW_PARITY_PART" in native-tests) shard=1 suffix= ;; native-tests-b) shard=2 suffix=-b ;; *) shard= ;; esac; set -o pipefail; if [ "$DW_PARITY_PART" = native-tests ]; then cargo test --locked --offline --lib runtime::mysql:: -- --ignored --skip runtime::mysql::tests::bootstrap_child --nocapture --test-threads=2 > /evidence/mysql-tests.txt || exit 1; fi; if [ -n "$shard" ]; then cargo test --locked --offline --test execution -- --list --format terse | sed -n "s/: test\$//p" | LC_ALL=C sort | tee /evidence/execution-listed-tests.txt | awk -v count="$DW_EXECUTION_SHARDS" -v shard="$shard" "(NR - 1) % count == shard - 1" > /evidence/execution-shard$suffix.txt && test -s /evidence/execution-shard$suffix.txt && cargo test --locked --offline --test execution -- --exact --nocapture --test-threads=2 $(cat /evidence/execution-shard$suffix.txt) > /evidence/mysql-execution-tests$suffix.txt || exit 1; fi; case "$DW_PARITY_PART" in native-tests|native-tests-b) cargo build --locked --offline ;; *) test -x /target/debug/durable-workflow-server ;; esac'
docker run --rm --user="$(id -u):$(id -g)" --network "$RESOURCE_SCOPE" \
-e DW_RUST_EXPERIMENTAL=1 -e DB_CONNECTION=mysql -e DB_HOST=parity-mysql -e DB_DATABASE=native_ref \
-e DB_USERNAME=root -e DB_PASSWORD=parity-disposable-password \
Expand Down
1 change: 1 addition & 0 deletions scripts/conformance/server-parity/artifact-summary.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function priority(path, failed) {
if (failed && (/\.stderr$/.test(name) || /(?:stderr|error|failure|bootstrap|install|build).*(?:\.log|\.txt)$/.test(name)
|| /^(?:php|rust|native)(?:[-.].*)?\.log$/.test(name) || /server\.log$/.test(name))) return 2;
if (/^(identity|build|database-state|database-memory-limit)\.json$/.test(name)) return 3;
if (/^execution-(listed-tests|shard(?:-b)?)\.txt$/.test(name)) return 4;
if (/(?:-status|-integrity|-version|-revision|-controls|-contract)\.txt$/.test(name) || /\.status$/.test(name)
|| /^(SHA256SUMS|source-hashes\.sha256)$/.test(name)) return 4;
return null;
Expand Down
23 changes: 19 additions & 4 deletions tests/Unit/NativeDebugArtifactTest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ function databaseCommand(id) {
return line.trim().slice(1, -1);
}

function runDatabaseCommand(t, id, part, binary = true) {
function runDatabaseCommand(t, id, part, binary = true, listExit = 0) {
const root = mkdtempSync(join(tmpdir(), 'native-debug-cargo-'));
t.after(() => rmSync(root, {recursive: true, force: true}));
mkdirSync(join(root, 'bin'));
Expand All @@ -292,13 +292,20 @@ function runDatabaseCommand(t, id, part, binary = true) {
const fs = require('node:fs');
const args = process.argv.slice(2);
fs.appendFileSync(process.env.CARGO_CALL_LOG, JSON.stringify(args) + '\\n');
if(args.includes('--list')) console.log('case_a: test\\ncase_b: test');
if(args.includes('--list')) {
console.log('case_a: test\\ncase_b: test');
process.exit(Number(process.env.CARGO_LIST_EXIT || 0));
}
`, {mode: 0o755});
const script = databaseCommand(id).replaceAll('/evidence/', `${root}/evidence/`).replaceAll('/target/', `${root}/target/`);
const run = spawnSync('bash', ['-c', script], {encoding: 'utf8', env: {...process.env,
PATH: `${root}/bin:${process.env.PATH}`, CARGO_CALL_LOG: log, DW_PARITY_PART: part, DW_EXECUTION_SHARDS: '2'}});
PATH: `${root}/bin:${process.env.PATH}`, CARGO_CALL_LOG: log, CARGO_LIST_EXIT: String(listExit),
DW_PARITY_PART: part, DW_EXECUTION_SHARDS: '2'}});
const calls = readFileSync(log, 'utf8').trim().split('\n').filter(Boolean).map(JSON.parse);
return {...run, calls};
const listed = join(root, 'evidence/execution-listed-tests.txt');
const selected = join(root, `evidence/execution-shard${part === 'native-tests-b' ? '-b' : ''}.txt`);
return {...run, calls, listed: existsSync(listed) ? readFileSync(listed, 'utf8') : null,
selected: existsSync(selected) ? readFileSync(selected, 'utf8') : null};
}

for (const part of ['native-tests', 'native-tests-b']) {
Expand All @@ -314,6 +321,14 @@ for (const part of ['native-tests', 'native-tests-b']) {
['test', ...flags, '--test', 'execution', '--', '--exact', '--nocapture', '--test-threads=2',
part === 'native-tests' ? 'case_a' : 'case_b'], ['build', ...flags]);
assert.deepEqual(run.calls, expected);
assert.equal(run.listed, 'case_a\ncase_b\n');
assert.equal(run.selected, part === 'native-tests' ? 'case_a\n' : 'case_b\n');
});
test(`MySQL ${part} refuses a failing test-list command even with partial output`, t => {
const run = runDatabaseCommand(t, 'mysql-execution', part, true, 7);
assert.notEqual(run.status, 0);
assert.equal(run.calls.some(args => args.includes('--exact')), false);
assert.equal(run.calls.some(args => args[0] === 'build'), false);
});
}

Expand Down
19 changes: 19 additions & 0 deletions tests/Unit/ServerParityArtifactSummaryTest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,25 @@ test('successful summaries preserve exact reports and omit journals, DBs, payloa
assert.throws(() => summarizeEvidence(source, output), /fresh empty directory/);
});

test('execution inventories retain exact bytes with explicit truncation and omit unrelated lists', t => {
const {source, output} = fixture(t);
const inventories = {'execution-listed-tests.txt': 'case_a\ncase_b\n',
'execution-shard.txt': 'case_a\n', 'execution-shard-b.txt': 'case_b\n'};
for (const [name, content] of Object.entries(inventories)) writeFileSync(join(source, name), content);
writeFileSync(join(source, 'execution-unrelated.txt'), 'not a selected-test inventory');
const summary = summarizeEvidence(source, output, {outcome: 'success'});
for (const [name, content] of Object.entries(inventories)) {
assert.equal(readFileSync(join(output, name), 'utf8'), content);
assert.equal(summary.retained.find(entry => entry.path === name).tail_only, false);
}
assert.equal(existsSync(join(output, 'execution-unrelated.txt')), false);
const other = fixture(t);
writeFileSync(join(other.source, 'execution-listed-tests.txt'), 'x'.repeat(64 * 1024 + 1));
const truncated = summarizeEvidence(other.source, other.output, {outcome: 'success'}).retained[0];
assert.equal(truncated.retained_bytes, 64 * 1024);
assert.equal(truncated.tail_only, true);
});

test('failed summaries keep bounded diagnostic tails without truncating JSON into a false report', t => {
const {source, output} = fixture(t);
const diagnostic = `${'x'.repeat(128 * 1024)}\nHTTP 500 while installing pinned dependency\n`;
Expand Down
8 changes: 4 additions & 4 deletions tests/Unit/ServerParityPartsTest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,18 @@ test('the database bootstraps run the native suites only in the native-tests par
assert.match(mysql.text, /-e DW_PARITY_PART -e DW_EXECUTION_SHARDS \\\n/);
// native-tests runs the database suite and the first half of the execution
// tests; native-tests-b, where a label has it, runs the second half.
assert.match(mysql.text, /'case "\$DW_PARITY_PART" in native-tests\) shard=1 suffix= ;; native-tests-b\) shard=2 suffix=-b ;; \*\) shard= ;; esac; if \[ "\$DW_PARITY_PART" = native-tests \]; then cargo test [^']*runtime::mysql::[^']* > \/evidence\/mysql-tests\.txt \|\| exit 1; fi; if \[ -n "\$shard" \]; then [^']*cargo test --locked --offline --test execution -- --exact --nocapture --test-threads=2 \$\(cat \/evidence\/execution-shard\$suffix\.txt\) > \/evidence\/mysql-execution-tests\$suffix\.txt \|\| exit 1; fi; case "\$DW_PARITY_PART" in native-tests\|native-tests-b\) cargo build --locked --offline ;; \*\) test -x \/target\/debug\/durable-workflow-server ;; esac'/);
assert.match(mysql.text, /'case "\$DW_PARITY_PART" in native-tests\) shard=1 suffix= ;; native-tests-b\) shard=2 suffix=-b ;; \*\) shard= ;; esac; set -o pipefail; if \[ "\$DW_PARITY_PART" = native-tests \]; then cargo test [^']*runtime::mysql::[^']* > \/evidence\/mysql-tests\.txt \|\| exit 1; fi; if \[ -n "\$shard" \]; then [^']*cargo test --locked --offline --test execution -- --exact --nocapture --test-threads=2 \$\(cat \/evidence\/execution-shard\$suffix\.txt\) > \/evidence\/mysql-execution-tests\$suffix\.txt \|\| exit 1; fi; case "\$DW_PARITY_PART" in native-tests\|native-tests-b\) cargo build --locked --offline ;; \*\) test -x \/target\/debug\/durable-workflow-server ;; esac'/);
});

test('the MySQL 8 labels split their execution tests into two parts, every test in exactly one', () => {
test('all MySQL and MariaDB labels split execution tests into two parts, every test in exactly one', () => {
const block = job('mysql-execution');
assert.match(block, /^ {6}DW_EXECUTION_SHARDS: \$\{\{ matrix\.execution_shards \|\| 1 \}\}$/m);
// Matrix values come from the label's include entry; the added
// native-tests-b combination names its own, the same ones.
const include = block.slice(block.indexOf('\n include:\n'), block.indexOf('\n env:\n'));
const entries = include.split(/\n {10}- /).slice(1).map(text => Object.fromEntries(
[...('label: ' + text.replace(/^label: /, '')).matchAll(/^\s*([a-z_]+): (\S+)$/gm)].map(match => match.slice(1))));
const sharded = ['mysql-8.0', 'existing-php-mysql-matrix'];
const sharded = ['mysql-8.0', 'existing-php-mysql-matrix', 'mariadb-10.11'];
for (const name of sharded) {
const pair = entries.filter(entry => entry.label === name);
assert.equal(pair.length, 2, JSON.stringify(entries));
Expand All @@ -164,7 +164,7 @@ test('the MySQL 8 labels split their execution tests into two parts, every test
assert.ok(entries.filter(entry => !sharded.includes(entry.label)).every(entry => !entry.execution_shards && !entry.part));
// The selection the bootstrap runs: list, sort bytewise, deal round-robin.
const bootstrap = steps(block).find(step => step.name.startsWith('Bootstrap published ')).text;
const selection = /cargo test --locked --offline --test execution -- --list --format terse \| sed -n "s\/: test\\\$\/\/p" \| LC_ALL=C sort \| awk -v count="\$DW_EXECUTION_SHARDS" -v shard="\$shard" "([^"]+)" > \/evidence\/execution-shard\$suffix\.txt && test -s \/evidence\/execution-shard\$suffix\.txt && /.exec(bootstrap);
const selection = /cargo test --locked --offline --test execution -- --list --format terse \| sed -n "s\/: test\\\$\/\/p" \| LC_ALL=C sort \| tee \/evidence\/execution-listed-tests\.txt \| awk -v count="\$DW_EXECUTION_SHARDS" -v shard="\$shard" "([^"]+)" > \/evidence\/execution-shard\$suffix\.txt && test -s \/evidence\/execution-shard\$suffix\.txt && /.exec(bootstrap);
assert.ok(selection, 'the execution tests are selected by the listed round-robin');
const names = Array.from({length: 489}, (_, index) => `suite::test_${String(index).padStart(3, '0')}`);
const deal = (shard, count) => {
Expand Down
Loading