79 lines
5.2 KiB
JavaScript
79 lines
5.2 KiB
JavaScript
// Source contract tests only: no Rust compilation, live H3 peer or UI browser.
|
|
// Keep these checks aligned with Rust unit tests in src/http3/tests.rs and
|
|
// src/runtime/tests.rs; do not interpret source checks as wire acceptance.
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import vm from 'node:vm';
|
|
|
|
const read = path => fs.readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8');
|
|
const h3 = read('src/http3.rs');
|
|
const identity = read('src/http3/identity.rs');
|
|
const body = read('src/http3/body.rs');
|
|
const h3Tests = read('src/http3/tests.rs');
|
|
const cache = read('src/runtime/types.rs');
|
|
const cacheTests = read('src/runtime/tests.rs');
|
|
const css = read('src/admin/web/style.css');
|
|
const html = read('src/admin/web/index.html');
|
|
const logs = read('src/admin/web/file-logs.js');
|
|
const en = JSON.parse(read('langs/en_US.json')).translations;
|
|
const pl = JSON.parse(read('langs/pl_pl.json')).translations;
|
|
|
|
// A peer-initiated RESET_STREAM or STOP_SENDING must not be logged as a
|
|
// fabricated HTTP 400 when the browser aborts a prior navigation on F5.
|
|
assert.match(identity, /fn client_cancelled_code\(code: Code\)/);
|
|
assert.match(identity, /code == Code::H3_REQUEST_CANCELLED \|\| code == Code::H3_NO_ERROR/);
|
|
assert.match(identity, /StreamError::RemoteTerminate \{ code, \.\. \} if client_cancelled_code\(\*code\)/);
|
|
assert.match(h3, /Ok\(Err\(error\)\)\s*=>\s*\{\s*if client_cancelled_request\(&error\)/);
|
|
assert.match(h3, /\} else \{\s*log_protocol_error\(\s*&state, "http3_request_error", error, peer, local, 400/);
|
|
assert.match(h3, /"http3_invalid_headers"[^\n]*\n\s*peer, local, 400/);
|
|
assert.match(h3, /error\.downcast_ref::<h3::error::StreamError>\(\)\s*\.is_some_and\(client_cancelled_request\)/);
|
|
assert.match(h3, /if !cancelled \{[\s\S]*?send\.stop_stream\(Code::H3_INTERNAL_ERROR\)/);
|
|
const bodyDrop = body.slice(body.indexOf('impl Drop for ReceiveBody'));
|
|
assert.ok(!bodyDrop.includes('stop_sending('), 'Do not reintroduce a receive-stream Drop panic');
|
|
assert.match(h3Tests, /client_cancelled_code\(Code::H3_MESSAGE_ERROR\)/);
|
|
|
|
// H2/H3 client transport selection is not a cached representation property.
|
|
const revision = cache.slice(cache.indexOf('fn cache_revision('), cache.indexOf('fn cache_invalidation('));
|
|
assert.match(revision, /for vhost in &mut vhosts/);
|
|
assert.match(revision, /vhost\.http2_enabled = true;/);
|
|
assert.match(revision, /vhost\.http3_enabled = true;/);
|
|
assert.ok(revision.indexOf('vhost.http3_enabled = true;') < revision.indexOf('serde_json::to_vec('));
|
|
assert.match(cacheTests, /cache_invalidation\(&base, &protocol_only\), CacheInvalidation::None/);
|
|
assert.match(cacheTests, /cache_invalidation\(&protocol_only, &base\), CacheInvalidation::None/);
|
|
assert.match(cacheTests, /cache_revision\(&both_protocols\), identity/);
|
|
assert.match(cacheTests, /CacheInvalidation::All\(value\) if value == cache_identity/);
|
|
|
|
// Every row is still keyboard-expandable and all selected columns are
|
|
// represented on the mobile card rather than removed by display:none.
|
|
assert.match(html, /id="panel-filelogs"/);
|
|
assert.match(logs, /row\.tabIndex = 0/);
|
|
assert.match(logs, /row\.setAttribute\("aria-expanded"/);
|
|
assert.match(logs, /event\.key === "Enter" \|\| event\.key === " "/);
|
|
assert.match(logs, /cell\.dataset\.mobileColumn = id/);
|
|
assert.match(logs, /cell\.dataset\.mobileLabel = label/);
|
|
assert.match(logs, /if \(selectedIndex === index\) nodes\.push\(detailRow\(entry\)\)/);
|
|
assert.match(css, /@media \(max-width: 700px\)/);
|
|
assert.match(css, /#panel-filelogs \.file-logs-table tbody tr:not\(\.file-log-detail-row\) \{\s*display: grid/);
|
|
assert.match(css, /#panel-filelogs \.file-logs-table tbody tr:not\(\.file-log-detail-row\) > td \{\s*display: block/);
|
|
assert.match(css, /overflow-wrap: anywhere/);
|
|
assert.match(css, /#panel-filelogs \.file-logs-table,\s*#panel-filelogs \.file-log-aggregate-table \{[^}]*overflow-x: auto/s);
|
|
assert.match(css, /#panel-filelogs \.file-log-inline-detail pre \{ max-width: 100%; overflow-x: auto; \}/);
|
|
|
|
// Exercise the actual browser code's entry-summary function with a logged
|
|
// H3 cancellation and a normal access event; this is a JS unit simulation.
|
|
const start = logs.indexOf(' function entrySummary(entry) {');
|
|
const end = logs.indexOf(' function nestedValue(', start);
|
|
assert.ok(start >= 0 && end > start, 'entrySummary function exists');
|
|
const context = vm.createContext({});
|
|
vm.runInContext(logs.slice(start, end), context);
|
|
assert.equal(vm.runInContext('entrySummary({reason:"http3_request_error",error:"Remote reset: H3_REQUEST_CANCELLED"})', context), 'http3_request_error');
|
|
assert.equal(vm.runInContext('entrySummary({method:"GET",host:"rp.example.test",path:"/admin"})', context), 'GET rp.example.test/admin');
|
|
|
|
for (const [language, pack] of [['en_US', en], ['pl_pl', pl]]) {
|
|
assert.match(pack.administrationPublicOriginHelp, /HTTPS/i, `${language}: origin scheme`);
|
|
assert.match(pack.administrationPublicOriginHelp, /Origin\/CSRF/i, `${language}: security purpose`);
|
|
assert.ok(pack.administrationHostsAdvanced.length > 10, `${language}: advanced DNS hosts`);
|
|
}
|
|
console.log('PASS: H3 cancellation classification, cache stability, mobile log-card/keyboard contracts and origin help.');
|
|
console.log('NOT VERIFIED: Rust build, actual QUIC navigation or full authenticated mobile UI.');
|