fix(ci): close capability races and green audit
This commit is contained in:
@@ -48,7 +48,11 @@ jobs:
|
||||
required:
|
||||
name: required
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
# A source edit rebuilds the monolithic compatibility crate under several
|
||||
# feature/profile graphs. Serialized compilation is required by the ARM64
|
||||
# runner's memory ceiling, so retain a small margin above the measured
|
||||
# 25-minute full gate instead of aborting a healthy graph at 12 minutes.
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
# The all-features graph includes Skia, OpenJPEG, and the pure-Rust J2K
|
||||
# codec. Serialize rustc/clippy on the memory-constrained ARM64 runner so
|
||||
|
||||
@@ -364,7 +364,7 @@ The test-suite gate is complete only when:
|
||||
- no production method contains real behavior beyond what is required to make
|
||||
signatures and constants compile.
|
||||
|
||||
### 3.3 Fixed controlled-red baseline
|
||||
### 3.3 Fixed compatibility baseline
|
||||
|
||||
Milestone 03 closes against the pinned 1,289-invocation catalog, not the older
|
||||
1,295 source-text estimate. The six-case difference is intentional: five
|
||||
@@ -374,21 +374,22 @@ tests that NUnit never runs.
|
||||
|
||||
`tests/red-suite-baseline.json` fixes the machine-checked ledger at 1,266
|
||||
ordinary translations, 19 live-grid translations, four benchmarks, and zero
|
||||
pending, drifted, duplicate, missing, or unreviewed cases. Run the controlled
|
||||
pending, drifted, duplicate, missing, or unreviewed cases. The historical
|
||||
red-suite filename is retained for automation compatibility, but the reviewed
|
||||
Rust translations and benchmarks are now required to pass. Run the controlled
|
||||
audit with:
|
||||
|
||||
```sh
|
||||
python3 tools/audit_red_suite.py
|
||||
```
|
||||
|
||||
With all three live-grid credentials present, the baseline executes every case:
|
||||
22 tests pass, 1,287 fail at 131 standardized C# member IDs, and none are
|
||||
ignored. Twenty passes are gate/support tests. The only two passing parity cases
|
||||
verify the required `BAKED_TEXTURE_COUNT` constant and composable validation
|
||||
flags; they do not represent implemented production behavior. Without complete
|
||||
credentials, the same audit conditionally ignores exactly the 19 live-grid
|
||||
cases and requires the remaining 1,268 parity failures to retain standardized
|
||||
member IDs. Production crates remain the failure-only milestone-02 shims.
|
||||
Without the explicit live-grid opt-in, the audit requires all 1,266 ordinary
|
||||
translations and four benchmark cases to pass, conditionally ignores exactly
|
||||
the 19 live-grid cases, and pins the independently counted support-test total.
|
||||
Setting `RUN_LIVE_TESTS=1` with all three live-grid credentials makes those 19
|
||||
cases required passes as well. Any ordinary failure, unexpected ignore,
|
||||
nonstandard failure, parity-catalog drift, or support-test-count drift fails the
|
||||
audit.
|
||||
|
||||
## 4. Validated Rust dependency map
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"schema": 1,
|
||||
"required_workflow": ".gitea/workflows/ci.yml",
|
||||
"release_workflow": ".gitea/workflows/release.yml",
|
||||
"hard_timeout_minutes": 15,
|
||||
"internal_target_seconds": 720,
|
||||
"hard_timeout_minutes": 30,
|
||||
"internal_target_seconds": 1680,
|
||||
"required_checks": [
|
||||
"format",
|
||||
"deterministic-generation",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"recorded_unix_seconds": 1786611260,
|
||||
"recorded_unix_seconds": 1786614077,
|
||||
"upstream_commit": "2aa70bb68513b39795da5d13c88f31b86e85a3ba",
|
||||
"material_count": 27,
|
||||
"generated_output_count": 8,
|
||||
@@ -12,7 +12,7 @@
|
||||
"dependency_manifest_sha256": "5f80b45ab18a45365673b55b52d68318bc31f602ce2f6559f573027cc446c58e",
|
||||
"third_party_notices_sha256": "c4d381944a9b57277963d2a5ee4e23a9a064c2ba93a676a49e023931b53a71d6",
|
||||
"native_notices_sha256": "b417ee7bf6b748cc86839e5354753c0f8c1f8309d13c0fea379c77f602e69fc0",
|
||||
"distribution_manifest_sha256": "95af81f60a3823cac35e6716d1500d052bc7e22127d84f705798414a085f6762",
|
||||
"distribution_manifest_sha256": "c58a89ad662bf05dc9420f875204ca8ef20cc4a4aaf5c821a2c4622b9eaf122f",
|
||||
"unknown_materials": 0,
|
||||
"unknown_bundled_assets": 0,
|
||||
"status": "ok"
|
||||
|
||||
@@ -83,6 +83,7 @@ pub(crate) struct CapsInner {
|
||||
event_queue: Mutex<Option<EventQueueClient>>,
|
||||
seed_task: Mutex<Option<SeedTask>>,
|
||||
events: Arc<CapabilitiesEventState>,
|
||||
seed_request_completed: AtomicBool,
|
||||
disconnected: AtomicBool,
|
||||
}
|
||||
|
||||
@@ -193,6 +194,7 @@ impl Caps {
|
||||
event_queue: Mutex::new(None),
|
||||
seed_task: Mutex::new(None),
|
||||
events: Arc::new(CapabilitiesEventState::default()),
|
||||
seed_request_completed: AtomicBool::new(false),
|
||||
disconnected: AtomicBool::new(false),
|
||||
});
|
||||
start_seed_task(&inner)?;
|
||||
@@ -257,9 +259,7 @@ impl Caps {
|
||||
}
|
||||
|
||||
pub(crate) fn seed_request_finished(&self) -> bool {
|
||||
mutex(&self.inner.seed_task)
|
||||
.as_ref()
|
||||
.is_none_or(|task| task.handle.is_finished())
|
||||
self.inner.seed_request_completed.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
pub fn disconnect(&self, immediate: bool) -> Result<(), Error> {
|
||||
@@ -379,10 +379,14 @@ async fn run_seed_requests(weak: Weak<CapsInner>, cancellation: CancellationToke
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
finish_seed_request(&inner, simulator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Ok((response, _)) if response.status_code == 404 => return,
|
||||
Ok((response, _)) if response.status_code == 404 => {
|
||||
finish_seed_request(&inner, simulator);
|
||||
return;
|
||||
}
|
||||
Err(Error::Cancelled) if cancellation.is_cancellation_requested() => return,
|
||||
Ok(_) | Err(_) => {}
|
||||
}
|
||||
@@ -461,10 +465,15 @@ async fn install_seed_response(
|
||||
let _ = simulator.features.set_features(None, Some(bytes), None);
|
||||
}
|
||||
cancellation.throw_if_cancellation_requested()?;
|
||||
inner.emit_capabilities_received(simulator.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish_seed_request(inner: &CapsInner, simulator: Simulator) {
|
||||
if !inner.seed_request_completed.swap(true, Ordering::AcqRel) {
|
||||
inner.emit_capabilities_received(simulator);
|
||||
}
|
||||
}
|
||||
|
||||
fn seed_retry_delay(uri: &Uri, retry: u32) -> Duration {
|
||||
let multiplier = 1_u32
|
||||
.checked_shl(retry.saturating_sub(1).min(30))
|
||||
|
||||
@@ -3962,6 +3962,12 @@ impl InventoryManager {
|
||||
if let Some(uri) = caps.capability_uri(name.to_owned())? {
|
||||
return Ok(Some(uri));
|
||||
}
|
||||
// Seed completion can race subscription registration. The completion
|
||||
// bit is published before the event, so this post-subscribe check
|
||||
// closes the lost-notification window without polling or sleeping.
|
||||
if caps.seed_request_finished() {
|
||||
return Ok(None);
|
||||
}
|
||||
let cancellation = cancellation_token.cancelled();
|
||||
futures_util::pin_mut!(receiver, cancellation);
|
||||
match select(receiver, cancellation).await {
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
},
|
||||
{
|
||||
"path": ".gitea/workflows/ci.yml",
|
||||
"bytes": 7567,
|
||||
"sha256": "ae8f50aaf0ab6bd07cfff49d75ba7cd1f051bbd6c7599dc8f1d5f239db5b8561"
|
||||
"bytes": 7875,
|
||||
"sha256": "6bf276d38174ef88546eff5d992181e65535baf02c5be9126b625d9a69e7ea50"
|
||||
},
|
||||
{
|
||||
"path": ".gitea/workflows/release.yml",
|
||||
@@ -67,8 +67,8 @@
|
||||
},
|
||||
{
|
||||
"path": "RUSTREWRITE.md",
|
||||
"bytes": 55217,
|
||||
"sha256": "487dce943fbe823ab5967bbedff506e1229b70508cb73d33fe6726ee11a2fc68"
|
||||
"bytes": 55222,
|
||||
"sha256": "0bcc41a325c382c9c0d1d6861f46512f50d87d701bd30951c9009f492c9277c9"
|
||||
},
|
||||
{
|
||||
"path": "api/API-COVERAGE.md",
|
||||
@@ -212,8 +212,8 @@
|
||||
},
|
||||
{
|
||||
"path": "ci/ci-coverage.json",
|
||||
"bytes": 5694,
|
||||
"sha256": "40eed10def683f978c65deba5d2c09f463330fe1cd6357efafc875d86ed1afa3"
|
||||
"bytes": 5695,
|
||||
"sha256": "248294710a97ac541882a44d37e8e5b527c32506f2ed95b19b2f255146d866a0"
|
||||
},
|
||||
{
|
||||
"path": "ci/concurrency-thresholds.json",
|
||||
@@ -1167,8 +1167,8 @@
|
||||
},
|
||||
{
|
||||
"path": "crates/libremetaverse/src/caps.rs",
|
||||
"bytes": 26955,
|
||||
"sha256": "c8ca6bd5416ac9500ce949360c1777f936ec977897679b645f91080ffa9bfe75"
|
||||
"bytes": 27291,
|
||||
"sha256": "ee109437e7b48aa7fec7bfc84b0e51e4c9fd35142e7a411f1580929904b3c508"
|
||||
},
|
||||
{
|
||||
"path": "crates/libremetaverse/src/caps_http.rs",
|
||||
@@ -1317,8 +1317,8 @@
|
||||
},
|
||||
{
|
||||
"path": "crates/libremetaverse/src/inventory_manager.rs",
|
||||
"bytes": 205943,
|
||||
"sha256": "7aa18b3f102520995b3795c2d2dd5e24ca23fa25dc9cfea792526b4aec83c0d3"
|
||||
"bytes": 206253,
|
||||
"sha256": "a48d8f235ea70b33723770ca7575667025850f25c5bf165acaadcd09f73c1360"
|
||||
},
|
||||
{
|
||||
"path": "crates/libremetaverse/src/j2k.rs",
|
||||
@@ -2083,7 +2083,7 @@
|
||||
{
|
||||
"path": "tests/PARITY.md",
|
||||
"bytes": 619515,
|
||||
"sha256": "923d869be32e56b78191721d402732413384a045e1777c00d6358d2edd33b8a8"
|
||||
"sha256": "b62f868fa90ca20ac5888ee87564b31aab4ec37db039644c5c04dd4b4cae974f"
|
||||
},
|
||||
{
|
||||
"path": "tests/api-compile/Cargo.lock",
|
||||
@@ -2382,8 +2382,8 @@
|
||||
},
|
||||
{
|
||||
"path": "tests/compat/tests/task_inventory_semantics.rs",
|
||||
"bytes": 8559,
|
||||
"sha256": "a6d04b4a9bdaf7147c67ea1fd9a2cdad53f60c7a6c0359cf4fb36f306e96e8c3"
|
||||
"bytes": 9655,
|
||||
"sha256": "249c1e95355843459840d546fddaa3c71ca6854c08348471c8f79ff5c951f897"
|
||||
},
|
||||
{
|
||||
"path": "tests/compat/tests/types_structured_shims.rs",
|
||||
@@ -2467,8 +2467,8 @@
|
||||
},
|
||||
{
|
||||
"path": "tests/red-suite-baseline.json",
|
||||
"bytes": 13697,
|
||||
"sha256": "c531e53ed9bfc48dba92df66544cd1d1e88b950b86202fe41197ee19e7a2cdcb"
|
||||
"bytes": 435,
|
||||
"sha256": "8556c57ff87591a80a43ed1d1baca59f9af30ebbbc49ac544529f3397963eda8"
|
||||
},
|
||||
{
|
||||
"path": "tests/semver-port/Cargo.lock",
|
||||
@@ -2488,7 +2488,7 @@
|
||||
{
|
||||
"path": "tests/upstream-tests.json",
|
||||
"bytes": 1348797,
|
||||
"sha256": "b6c223b7186dfa0675eaf910ed1f47b59c3b71ee46644459311edec69997fd1f"
|
||||
"sha256": "494ab6ca1a16befd28ea8874d20ab75f21fd645f5c455162d12b97596bc05f61"
|
||||
},
|
||||
{
|
||||
"path": "tools/api-catalog/ApiCatalog.csproj",
|
||||
@@ -2502,8 +2502,8 @@
|
||||
},
|
||||
{
|
||||
"path": "tools/audit_red_suite.py",
|
||||
"bytes": 7488,
|
||||
"sha256": "96140b455a857144636ff14b8fc2952edfb2472bff07f2a482273f813d52c653"
|
||||
"bytes": 10082,
|
||||
"sha256": "8b9d36b324414701c0967898c6084c4e2d046dff9455f65d005356158ef7a2cc"
|
||||
},
|
||||
{
|
||||
"path": "tools/check_api_coverage.py",
|
||||
@@ -2637,8 +2637,8 @@
|
||||
},
|
||||
{
|
||||
"path": "tools/ci-matrix/src/ci_gate.rs",
|
||||
"bytes": 45662,
|
||||
"sha256": "5a3666a3c84993fb3c3ac8d920aed4ea6ecdd2bfa06b6c94ab84942ba7a33db5"
|
||||
"bytes": 45664,
|
||||
"sha256": "d1ebbd96de67078ce01ec0f9a42a6f823ced7946a10b31d97b0f0229ac6ae588"
|
||||
},
|
||||
{
|
||||
"path": "tools/ci-matrix/src/dependency.rs",
|
||||
@@ -2752,8 +2752,8 @@
|
||||
},
|
||||
{
|
||||
"path": "tools/test_audit_red_suite.py",
|
||||
"bytes": 1212,
|
||||
"sha256": "358ff6ab4313acc88bc4d2d3e9faf0301648a5f521fbe4d527bd39b49c7c4956"
|
||||
"bytes": 1636,
|
||||
"sha256": "a2183e36c5038d8da2f47aee7251b1d2663a5a909c909b7b1d27b859d7a591e7"
|
||||
},
|
||||
{
|
||||
"path": "tools/test_generate_surface.py",
|
||||
|
||||
@@ -1129,10 +1129,10 @@ Reviewed Rust tests live outside `generated_parity.rs` and carry a `parity-case`
|
||||
| `LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_EmptyDaysClearsSchedule::test` | `RegionScheduleTests.SetRegionRestartScheduleAsync_EmptyDaysClearsSchedule` | `` | `LibreMetaverse.Tests/RegionScheduleTests.cs:157` | `Estate` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/world_capability_semantics.rs:415 (`set_region_restart_schedule_empty_days_clears_schedule`)` | `translated` | `57ef3c0f8d9eeac58a7d1b3e7dbc44413016f39303d304cacd3071bd2c55f320` |
|
||||
| `LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_NoCapability_ReturnsFalseWithoutRequest::test` | `RegionScheduleTests.SetRegionRestartScheduleAsync_NoCapability_ReturnsFalseWithoutRequest` | `` | `LibreMetaverse.Tests/RegionScheduleTests.cs:177` | `Estate` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/world_capability_semantics.rs:435 (`set_region_restart_schedule_no_capability_returns_false_without_request`)` | `translated` | `be03507fe574b9f7c7174c39af44b7b693e1b7a496845db46451ef09bf9db206` |
|
||||
| `LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_NonSuccessStatus_ReturnsFalse::test` | `RegionScheduleTests.SetRegionRestartScheduleAsync_NonSuccessStatus_ReturnsFalse` | `` | `LibreMetaverse.Tests/RegionScheduleTests.cs:195` | `Estate` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/world_capability_semantics.rs:453 (`set_region_restart_schedule_non_success_returns_false`)` | `translated` | `16c8988d7aa15ea9f58deaa2e3f416b6115978e23073fd99749843f4f410dca4` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_CapAvailable_ReturnsContentsFolderAndDecryptsShadowId::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_CapAvailable_ReturnsContentsFolderAndDecryptsShadowId` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:73` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:138 (`cap_available_returns_contents_folder_and_decrypts_shadow_id`)` | `translated` | `c9bfc5526260f9e2dffa8a22938999911fdd80be4b2b6d6487bf6171f8dbb56a` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_PlainAssetId_ParsesWithoutDecryption::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_PlainAssetId_ParsesWithoutDecryption` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:115` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:176 (`plain_asset_id_parses_without_decryption`)` | `translated` | `95f39928dae61bca86b7d0a0702307db6c5fdc754e51f73a24bd5ee131e6de3f` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_NonSuccessStatus_ReturnsContentsFolderOnly::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_NonSuccessStatus_ReturnsContentsFolderOnly` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:143` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:196 (`non_success_status_returns_contents_folder_only`)` | `translated` | `b8a25891064e470ac8d77ecd8a4847cf773b043de5ebeae275a9dd6669518585` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_NoCapability_DoesNotMakeHttpRequest::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_NoCapability_DoesNotMakeHttpRequest` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:164` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:211 (`no_capability_does_not_make_http_request`)` | `translated` | `c0c43ebcf781fb81b1fef7ce1dd2774e350d92ef882f49876f1a16d23a338592` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_CapAvailable_ReturnsContentsFolderAndDecryptsShadowId::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_CapAvailable_ReturnsContentsFolderAndDecryptsShadowId` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:73` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:149 (`cap_available_returns_contents_folder_and_decrypts_shadow_id`)` | `translated` | `c9bfc5526260f9e2dffa8a22938999911fdd80be4b2b6d6487bf6171f8dbb56a` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_PlainAssetId_ParsesWithoutDecryption::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_PlainAssetId_ParsesWithoutDecryption` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:115` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:187 (`plain_asset_id_parses_without_decryption`)` | `translated` | `95f39928dae61bca86b7d0a0702307db6c5fdc754e51f73a24bd5ee131e6de3f` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_NonSuccessStatus_ReturnsContentsFolderOnly::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_NonSuccessStatus_ReturnsContentsFolderOnly` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:143` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:207 (`non_success_status_returns_contents_folder_only`)` | `translated` | `b8a25891064e470ac8d77ecd8a4847cf773b043de5ebeae275a9dd6669518585` |
|
||||
| `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs::RequestTaskInventoryCapTests.GetTaskInventoryAsync_NoCapability_DoesNotMakeHttpRequest::test` | `RequestTaskInventoryCapTests.GetTaskInventoryAsync_NoCapability_DoesNotMakeHttpRequest` | `` | `LibreMetaverse.Tests/RequestTaskInventoryCapTests.cs:164` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/task_inventory_semantics.rs:222 (`no_capability_does_not_make_http_request`)` | `translated` | `c0c43ebcf781fb81b1fef7ce1dd2774e350d92ef882f49876f1a16d23a338592` |
|
||||
| `LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_HappyPath_PostsMetadataThenImageAndReturnsTrue::test` | `SendPostcardTests.SendPostcardAsync_HappyPath_PostsMetadataThenImageAndReturnsTrue` | `` | `LibreMetaverse.Tests/SendPostcardTests.cs:68` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/asset_capability_semantics.rs:548 (`postcard_posts_metadata_then_image`)` | `translated` | `2e02bd16ef1431c2ca82d7804dffc764be0175cff5daff8c38d0a61641439e06` |
|
||||
| `LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_UploaderMissingFromResponse_ReturnsFalseWithoutSecondRequest::test` | `SendPostcardTests.SendPostcardAsync_UploaderMissingFromResponse_ReturnsFalseWithoutSecondRequest` | `` | `LibreMetaverse.Tests/SendPostcardTests.cs:100` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/asset_capability_semantics.rs:586 (`postcard_missing_uploader_returns_false_after_one_request`)` | `translated` | `2f9498d57d7a512399f9b108765e6e8da8e4c937402f9671d580c66332630432` |
|
||||
| `LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_UploadDoesNotComplete_ReturnsFalse::test` | `SendPostcardTests.SendPostcardAsync_UploadDoesNotComplete_ReturnsFalse` | `` | `LibreMetaverse.Tests/SendPostcardTests.cs:112` | `` | `LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs` | `tests/compat/tests/asset_capability_semantics.rs:608 (`postcard_incomplete_upload_returns_false`)` | `translated` | `937b682b406506ec9fba9570852bbf8689450a11cbecb85979af97609b1794f9` |
|
||||
|
||||
@@ -8,10 +8,11 @@ use libremetaverse::{
|
||||
use libremetaverse_compat_tests::block_on;
|
||||
use libremetaverse_types::UUID;
|
||||
use libremetaverse_types::compat::{
|
||||
CancellationToken, CancellationTokenSource, HttpMessageHandler, HttpRequest, HttpResponse, Uri,
|
||||
CancellationTokenSource, HttpMessageHandler, HttpRequest, HttpResponse, Uri,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex, mpsc};
|
||||
use std::time::Duration;
|
||||
|
||||
const CAP: &str = "http://test.invalid/request-task-inventory";
|
||||
@@ -35,8 +36,11 @@ fn client_with_cap(response: HttpResponse, expose_capability: bool) -> (GridClie
|
||||
} else {
|
||||
"<llsd><map></map></llsd>".into()
|
||||
};
|
||||
let release_seed = Arc::new(AtomicBool::new(false));
|
||||
let handler_release_seed = Arc::clone(&release_seed);
|
||||
let handler = HttpMessageHandler::new(move |request, _| {
|
||||
let result = if request.uri.0 == SEED {
|
||||
let is_seed = request.uri.0 == SEED;
|
||||
let result = if is_seed {
|
||||
HttpResponse {
|
||||
status_code: 200,
|
||||
headers: BTreeMap::new(),
|
||||
@@ -52,7 +56,15 @@ fn client_with_cap(response: HttpResponse, expose_capability: bool) -> (GridClie
|
||||
body: Vec::new(),
|
||||
})
|
||||
};
|
||||
async move { result }
|
||||
let handler_release_seed = Arc::clone(&handler_release_seed);
|
||||
async move {
|
||||
if is_seed {
|
||||
while !handler_release_seed.load(Ordering::Acquire) {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
});
|
||||
let mut client = GridClient::new().expect("GridClient constructor");
|
||||
client.set_http_caps_client(HttpCapsClient::new(handler.clone()).unwrap());
|
||||
@@ -69,6 +81,15 @@ fn client_with_cap(response: HttpResponse, expose_capability: bool) -> (GridClie
|
||||
simulator
|
||||
.set_seed_caps(Some(Uri(SEED.into())), Some(true))
|
||||
.unwrap();
|
||||
let caps = simulator.clone().caps.expect("seed capability client");
|
||||
let (seed_complete, completion) = mpsc::channel();
|
||||
let _subscription = caps.subscribe_capabilities_received(Some(Arc::new(move |_| {
|
||||
seed_complete.send(()).unwrap();
|
||||
})));
|
||||
release_seed.store(true, Ordering::Release);
|
||||
completion
|
||||
.recv_timeout(Duration::from_secs(2))
|
||||
.expect("seed capability request completed");
|
||||
let mut network = client.network();
|
||||
network.set_current_sim(Some(simulator));
|
||||
client.set_network(network);
|
||||
@@ -116,16 +137,6 @@ fn item_json(
|
||||
)
|
||||
}
|
||||
|
||||
fn cancellation_after(duration: Duration) -> CancellationToken {
|
||||
let source = Arc::new(CancellationTokenSource::new());
|
||||
let token = source.token();
|
||||
std::thread::spawn(move || {
|
||||
std::thread::sleep(duration);
|
||||
source.cancel();
|
||||
});
|
||||
token
|
||||
}
|
||||
|
||||
fn single<T: 'static>(entries: &[Box<dyn InventoryObjectClass>]) -> &T {
|
||||
let mut matching = entries
|
||||
.iter()
|
||||
@@ -212,13 +223,22 @@ fn non_success_status_returns_contents_folder_only() {
|
||||
#[test]
|
||||
fn no_capability_does_not_make_http_request() {
|
||||
let (client, recording) = client_with_cap(response(404, String::new()), false);
|
||||
let result = block_on(client.inventory().get_task_inventory(
|
||||
uuid(),
|
||||
12_345,
|
||||
None,
|
||||
Some(cancellation_after(Duration::from_millis(50))),
|
||||
))
|
||||
.expect("GetTaskInventoryAsync");
|
||||
let cancellation = CancellationTokenSource::new();
|
||||
let token = cancellation.token();
|
||||
let inventory = client.inventory();
|
||||
let (result, ()) = block_on(async move {
|
||||
tokio::join!(
|
||||
inventory.get_task_inventory(uuid(), 12_345, None, Some(token)),
|
||||
async move {
|
||||
// `join!` polls the inventory branch before this branch can
|
||||
// resume after yielding, so cancellation releases the legacy
|
||||
// callback wait instead of racing seed discovery or entry.
|
||||
tokio::task::yield_now().await;
|
||||
cancellation.cancel();
|
||||
}
|
||||
)
|
||||
});
|
||||
let result = result.expect("GetTaskInventoryAsync");
|
||||
assert!(result.is_empty());
|
||||
assert!(recording.requests().is_empty());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"schema_version": 2,
|
||||
"upstream_commit": "2aa70bb68513b39795da5d13c88f31b86e85a3ba",
|
||||
"reviewed_cases": 1289,
|
||||
"parity_report": {
|
||||
@@ -10,142 +10,10 @@
|
||||
"drifted": 0,
|
||||
"unreviewed": 0
|
||||
},
|
||||
"allowed_parity_passes": [
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Length_KnownVector::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Length_UnitVector::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Normalize_GivesUnitLength::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Normalize_ZeroVector_DoesNotThrow::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Normalize_ZeroVector_GivesZero::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Cross_XaxisTimesYaxis_GivesZaxis::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Cross_YaxisTimesXaxis_GivesNegZaxis::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::CoordTests.Coord_Add_IsCommutative::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Quat_AxisAngle_IsNormalized::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Quat_Identity_RotatesCoordUnchanged::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Coord_RotateByQuat_90DegAroundXaxis_YbecomesZ::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Coord_RotateByQuat_90DegAroundXaxis_ZbecomesNegY_BugRegression::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Coord_RotateByQuat_90DegAroundZaxis_XbecomesY::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Coord_RotateByQuat_90DegAroundYaxis_ZbecomesX::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Coord_RotateByQuat_180DegAroundZaxis_NegatesXandY::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Coord_RotateByQuat_PreservesLength::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Quat_Multiply_TwoNineties_AroundZ_Gives180::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs::QuatTests.Quat_Multiply_IsAssociative::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_Linear_HasVerticesAndFaces::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_Linear_AllFaceIndicesInRange::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Cylinder_Linear_HasGeometry::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Prism_Linear_HasGeometry::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Torus_Circular_HasGeometry::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Torus_Circular_AllFaceIndicesInRange::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_WithHollow_HasGeometry::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_WithProfileCut_HasGeometry::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_ViewerMode_HasViewerFaces::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_ViewerMode_AllViewerFaceVerticesFinite::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Box_ViewerMode_NumPrimFaces_Is6::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Cylinder_ViewerMode_NumPrimFaces_AtLeast2::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Torus_ViewerMode_NumPrimFaces_Is1::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Sphere_ViewerMode_NumPrimFaces_Is1::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Extrude_Torus_ViewerMode_HasViewerFaces::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.CalcNormals_Box_ProducesOneNormalPerFace::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.CalcNormals_Box_AllNonZeroNormalsUnitLength::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.CalcNormals_CalledTwice_IsIdempotent::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.VertexIndexer_Box_IsNotNull::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.VertexIndexer_NonViewerMode_ReturnsNull::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.VertexIndexer_Box_AllPolygonIndicesInRange::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Copy_Box_ProducesIndependentInstance::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.AddPos_ShiftsAllCoords::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.Scale_ScalesAllCoords::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.AddRot_ByIdentity_DoesNotChangeCoords::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.SurfaceNormal_Box_FirstFace_IsUnitLength::test",
|
||||
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs::PrimMeshTests.SurfaceNormal_InvalidIndex_Throws::test",
|
||||
"LibreMetaverse.Tests/AppearanceManagerTests.cs::AppearanceManagerTests.BAKED_TEXTURE_COUNT_Is11::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeArray::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeBool::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeDateTime::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeDictionary::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeInteger::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeLLSDBinary::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeNestedComposite::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeReal::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeString::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeURI::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeUUID::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.DeserializeUndef::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.HelperFunctions::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeArray::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeBool::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeDateTime::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeDictionary::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeInteger::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeLLSDBinary::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeLongMessage::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeNestedComposite::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeReal::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeString::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeURI::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeUUID::test",
|
||||
"LibreMetaverse.Tests/BinaryLLSDTests.cs::BinarySDTests.SerializeUndef::test",
|
||||
"LibreMetaverse.Tests/ManagedImageTests.cs::ManagedImageTests.ConvertChannels_AddsAlphaAndInitializesTo255::test",
|
||||
"LibreMetaverse.Tests/ManagedImageTests.cs::ManagedImageTests.ExportRaw_RGBA_OrderAndFlip::test",
|
||||
"LibreMetaverse.Tests/ManagedImageTests.cs::ManagedImageTests.ResizeNearestNeighbor_RepeatsSourcePixels::test",
|
||||
"LibreMetaverse.Tests/MarketplaceFolderClassifierTests.cs::MarketplaceFolderClassifierTests.ValidateListing_ValidFlags_AreBitmaskComposable::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeArray::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeBoolean::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeDate::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeInteger::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeMap::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeReal::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeRealWorldExamples::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeString::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeURI::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeUUID::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.DeserializeUndef::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.HelperFunctions::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeArray::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeBinary::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeBoolean::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeDate::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeFormattedTest::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeInteger::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeMap::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeReal::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeString::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeURI::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeUUID::test",
|
||||
"LibreMetaverse.Tests/NotationLLSDTests.cs::NotationSDTests.SerializeUndef::test",
|
||||
"LibreMetaverse.Tests/PacketTests.cs::PacketTests.HeaderFlags::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.AutoDetectProtobuf::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeArray::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeBinary::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeBoolean::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeDate::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeInteger::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeMap::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeNestedComposite::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeReal::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeString::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeUUID::test",
|
||||
"LibreMetaverse.Tests/ProtobufTests.cs::ProtobufTests.SerializeUri::test",
|
||||
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.LLSDTerseParsing::test",
|
||||
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.Quaternions::test",
|
||||
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.TestMatrix::test",
|
||||
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.UUIDs::test",
|
||||
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.Vector3ApproxEquals::test",
|
||||
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorCasting::test",
|
||||
"LibreMetaverse.Tests/UtilsConversionsTests.cs::UtilsConversionsTests.StringToBytes::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeBinary::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeBoolean::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeDates::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeIntegers::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeLLSDSample::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeNestedContainers::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeNoDTD::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeReals::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeSillyPI::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeSillyPI_LowercasePI::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeSillyPI_NoWhitespaceAfterPI::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeStrings::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeURI::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUUID::test",
|
||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUndef::test"
|
||||
],
|
||||
"support_passes": 143
|
||||
"parity_expectation": {
|
||||
"translated": "pass",
|
||||
"ignored-live": "pass-with-credentials-otherwise-ignore",
|
||||
"benchmark": "pass"
|
||||
},
|
||||
"support_passes": 747
|
||||
}
|
||||
|
||||
@@ -23100,7 +23100,7 @@
|
||||
"rust_body_sha256": "b8b44bec8f1a443c7205114c203177b9b3bb383e3df93a42d93b7862195838d0",
|
||||
"status": "translated",
|
||||
"rust_file": "tests/compat/tests/task_inventory_semantics.rs",
|
||||
"rust_line": 138,
|
||||
"rust_line": 149,
|
||||
"rust_test": "cap_available_returns_contents_folder_and_decrypts_shadow_id",
|
||||
"semantic_review": "reviewed"
|
||||
},
|
||||
@@ -23121,7 +23121,7 @@
|
||||
"rust_body_sha256": "216d66e54920b1c4d7e2c11b6e02d562636ce996269c3fd1f5188767c757d462",
|
||||
"status": "translated",
|
||||
"rust_file": "tests/compat/tests/task_inventory_semantics.rs",
|
||||
"rust_line": 176,
|
||||
"rust_line": 187,
|
||||
"rust_test": "plain_asset_id_parses_without_decryption",
|
||||
"semantic_review": "reviewed"
|
||||
},
|
||||
@@ -23142,7 +23142,7 @@
|
||||
"rust_body_sha256": "70980b8b2c37d807b00d3ad484db1c3a1e0e7bcce2890173b543225c0dac580e",
|
||||
"status": "translated",
|
||||
"rust_file": "tests/compat/tests/task_inventory_semantics.rs",
|
||||
"rust_line": 196,
|
||||
"rust_line": 207,
|
||||
"rust_test": "non_success_status_returns_contents_folder_only",
|
||||
"semantic_review": "reviewed"
|
||||
},
|
||||
@@ -23160,10 +23160,10 @@
|
||||
"fixture_dependencies": [
|
||||
"LibreMetaverse.Tests/TestHelpers/FakeGridClient.cs"
|
||||
],
|
||||
"rust_body_sha256": "61b164811b90a2a6a62cfa7a0179dd70c8efbaa79e853113eb657463c60c05a6",
|
||||
"rust_body_sha256": "428fdc142b85177e6ed8dc1e94f1f90eb5a66147efe324132d6bbb213bed0ef6",
|
||||
"status": "translated",
|
||||
"rust_file": "tests/compat/tests/task_inventory_semantics.rs",
|
||||
"rust_line": 211,
|
||||
"rust_line": 222,
|
||||
"rust_test": "no_capability_does_not_make_http_request",
|
||||
"semantic_review": "reviewed"
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
CATALOG = ROOT / "tests" / "upstream-tests.json"
|
||||
BASELINE = ROOT / "tests" / "red-suite-baseline.json"
|
||||
LIVE_KEYS = ("GRID_USER", "GRID_PASSWORD", "GRID_LOGIN_URL")
|
||||
LIVE_OPT_IN = "RUN_LIVE_TESTS"
|
||||
SUMMARY_RE = re.compile(
|
||||
r"test result: (?:ok|FAILED)\. (\d+) passed; (\d+) failed; "
|
||||
r"(\d+) ignored; (\d+) measured; (\d+) filtered out"
|
||||
@@ -24,10 +25,14 @@ SUMMARY_RE = re.compile(
|
||||
RESULT_RE = re.compile(
|
||||
r"^test (.+) \.\.\. (ok|FAILED|ignored)(?:, .*)?$", re.MULTILINE
|
||||
)
|
||||
RESULT_START_RE = re.compile(r"^test (.+) \.\.\. ?(.*)$")
|
||||
RESULT_END_RE = re.compile(r"^(ok|FAILED|ignored)(?:, .*)?$")
|
||||
PANIC_RE = re.compile(r"(?:^|\n)thread '([^']+)'(?: \(\d+\))? panicked at ")
|
||||
MEMBER_RE = re.compile(
|
||||
r'unimplemented C# API member: ([^\n]+)|NotImplemented \{ csharp_member: "([^"]+)" \}'
|
||||
)
|
||||
PENDING_CALL_RE = re.compile(r"(?<![:.\w])pending\s*\(")
|
||||
PENDING_DEFINITION_RE = re.compile(r"\bfn\s+pending\s*\(")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -50,7 +55,25 @@ def parse_log(text: str) -> LogAudit:
|
||||
if not summaries:
|
||||
raise ValueError("controlled suite log contains no libtest summaries")
|
||||
totals = tuple(sum(row[index] for row in summaries) for index in range(5))
|
||||
results = RESULT_RE.findall(text)
|
||||
results: list[tuple[str, str]] = []
|
||||
pending_results: deque[str] = deque()
|
||||
for line in text.splitlines():
|
||||
complete = RESULT_RE.fullmatch(line)
|
||||
if complete:
|
||||
results.append((complete.group(1), complete.group(2)))
|
||||
continue
|
||||
start = RESULT_START_RE.match(line)
|
||||
if start:
|
||||
pending_results.append(start.group(1))
|
||||
continue
|
||||
end = RESULT_END_RE.fullmatch(line)
|
||||
if end and pending_results:
|
||||
results.append((pending_results.popleft(), end.group(1)))
|
||||
if pending_results:
|
||||
raise ValueError(
|
||||
"controlled suite log contains unterminated test results: "
|
||||
+ ", ".join(pending_results)
|
||||
)
|
||||
names = {
|
||||
state: tuple(name for name, result in results if result == state)
|
||||
for state in ("ok", "FAILED", "ignored")
|
||||
@@ -102,16 +125,24 @@ def dotenv_values() -> dict[str, str]:
|
||||
return values
|
||||
|
||||
|
||||
def has_live_credentials() -> bool:
|
||||
def live_tests_enabled() -> bool:
|
||||
opted_in = os.environ.get(LIVE_OPT_IN, "").strip().lower() in {
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
}
|
||||
dotenv = dotenv_values()
|
||||
return all((os.environ.get(key) or dotenv.get(key, "")).strip() for key in LIVE_KEYS)
|
||||
return opted_in and all(
|
||||
(os.environ.get(key) or dotenv.get(key, "")).strip() for key in LIVE_KEYS
|
||||
)
|
||||
|
||||
|
||||
def pending_calls() -> list[str]:
|
||||
pending: list[str] = []
|
||||
roots = (ROOT / "tests" / "compat" / "tests", ROOT / "crates")
|
||||
for path in sorted(file for root in roots for file in root.rglob("*.rs")):
|
||||
if re.search(r"\bpending\s*\(", path.read_text()):
|
||||
text = PENDING_DEFINITION_RE.sub("", path.read_text())
|
||||
if PENDING_CALL_RE.search(text):
|
||||
pending.append(path.relative_to(ROOT).as_posix())
|
||||
return pending
|
||||
|
||||
@@ -132,16 +163,48 @@ def verify(log: LogAudit, live: bool) -> None:
|
||||
if pending:
|
||||
raise ValueError("pending( remains in Rust test sources: " + ", ".join(pending))
|
||||
|
||||
if baseline.get("schema_version") != 2:
|
||||
raise ValueError("red-suite baseline schema must be 2")
|
||||
expected_policy = {
|
||||
"translated": "pass",
|
||||
"ignored-live": "pass-with-credentials-otherwise-ignore",
|
||||
"benchmark": "pass",
|
||||
}
|
||||
if baseline.get("parity_expectation") != expected_policy:
|
||||
raise ValueError("red-suite parity expectation is not the reviewed green policy")
|
||||
|
||||
by_test = defaultdict(list)
|
||||
for case in catalog["tests"]:
|
||||
by_test[case["rust_test"]].append(case["id"])
|
||||
passed_cases = sorted(
|
||||
case_id for name in log.passed_names for case_id in by_test.get(name, [])
|
||||
def parity_cases(names: tuple[str, ...]) -> list[str]:
|
||||
case_ids = {
|
||||
case_id
|
||||
for name in names
|
||||
for case_id in by_test.get(name.rsplit("::", 1)[-1], [])
|
||||
}
|
||||
return sorted(case_ids)
|
||||
|
||||
passed_cases = parity_cases(log.passed_names)
|
||||
expected_passes = sorted(
|
||||
case["id"]
|
||||
for case in catalog["tests"]
|
||||
if case["status"] in {"translated", "benchmark"}
|
||||
or (live and case["status"] == "ignored-live")
|
||||
)
|
||||
allowed_passes = sorted(baseline["allowed_parity_passes"])
|
||||
if passed_cases != allowed_passes:
|
||||
if passed_cases != expected_passes:
|
||||
raise ValueError(
|
||||
f"parity pass baseline changed: expected {allowed_passes}, found {passed_cases}"
|
||||
f"parity pass baseline changed: expected {expected_passes}, found {passed_cases}"
|
||||
)
|
||||
ignored_cases = parity_cases(log.ignored_names)
|
||||
expected_ignored_cases = sorted(
|
||||
case["id"]
|
||||
for case in catalog["tests"]
|
||||
if not live and case["status"] == "ignored-live"
|
||||
)
|
||||
if ignored_cases != expected_ignored_cases:
|
||||
raise ValueError(
|
||||
"parity ignore baseline changed: "
|
||||
f"expected {expected_ignored_cases}, found {ignored_cases}"
|
||||
)
|
||||
support_passes = log.passed - len(passed_cases)
|
||||
if support_passes != baseline["support_passes"]:
|
||||
@@ -151,7 +214,7 @@ def verify(log: LogAudit, live: bool) -> None:
|
||||
)
|
||||
|
||||
expected_ignored = 0 if live else report["ignored_live"]
|
||||
expected_failed = expected_cases - len(allowed_passes) - expected_ignored
|
||||
expected_failed = 0
|
||||
if (log.failed, log.ignored) != (expected_failed, expected_ignored):
|
||||
raise ValueError(
|
||||
"controlled totals changed: "
|
||||
@@ -186,16 +249,25 @@ def main() -> None:
|
||||
parser.add_argument("--log", type=Path, help="audit an existing captured cargo-test log")
|
||||
args = parser.parse_args()
|
||||
if args.log:
|
||||
return_code, text = 101, args.log.read_text()
|
||||
return_code, text = None, args.log.read_text()
|
||||
else:
|
||||
return_code, text = run_suite()
|
||||
if return_code != 101:
|
||||
raise SystemExit(f"controlled suite returned {return_code}, expected Cargo test failure 101")
|
||||
live = has_live_credentials()
|
||||
if return_code not in {None, 0, 101}:
|
||||
tail = "\n".join(text.splitlines()[-40:])
|
||||
raise SystemExit(
|
||||
f"controlled suite could not run (Cargo returned {return_code}):\n{tail}"
|
||||
)
|
||||
live = live_tests_enabled()
|
||||
audit = parse_log(text)
|
||||
verify(audit, live)
|
||||
expected_return_code = 101 if audit.failed else 0
|
||||
if return_code is not None and return_code != expected_return_code:
|
||||
raise SystemExit(
|
||||
f"controlled suite returned {return_code}, expected {expected_return_code}"
|
||||
)
|
||||
print(
|
||||
f"controlled red suite is current: passed={audit.passed}, failed={audit.failed}, "
|
||||
f"controlled compatibility suite is current: passed={audit.passed}, "
|
||||
f"failed={audit.failed}, "
|
||||
f"ignored={audit.ignored}, live_credentials={str(live).lower()}, "
|
||||
f"standardized_members={len(audit.members)}"
|
||||
)
|
||||
|
||||
@@ -988,8 +988,8 @@ fn validate_coverage(manifest: &CoverageManifest) -> Result<()> {
|
||||
if manifest.schema != 1
|
||||
|| manifest.required_workflow != REQUIRED_WORKFLOW
|
||||
|| manifest.release_workflow != RELEASE_WORKFLOW
|
||||
|| manifest.hard_timeout_minutes != 15
|
||||
|| manifest.internal_target_seconds > 720
|
||||
|| manifest.hard_timeout_minutes != 30
|
||||
|| manifest.internal_target_seconds > 1_680
|
||||
|| manifest.legacy_workflows.len() != LEGACY_WORKFLOW_COUNT
|
||||
{
|
||||
return Err(MatrixError::new(
|
||||
@@ -1066,7 +1066,7 @@ fn validate_workflows(root: &Path, manifest: &CoverageManifest) -> Result<()> {
|
||||
for marker in [
|
||||
"push:",
|
||||
"pull_request:",
|
||||
"timeout-minutes: 15",
|
||||
"timeout-minutes: 30",
|
||||
"cancel-in-progress: true",
|
||||
"runs-on: ubuntu-latest",
|
||||
"required-gate",
|
||||
|
||||
@@ -4,6 +4,21 @@ from audit_red_suite import parse_log
|
||||
|
||||
|
||||
class AuditRedSuiteTests(unittest.TestCase):
|
||||
def test_parses_result_split_by_captured_output(self) -> None:
|
||||
audit = parse_log(
|
||||
"""
|
||||
test noisy ... diagnostic output
|
||||
more diagnostic output
|
||||
ok
|
||||
test expected_panic ...
|
||||
thread 'expected_panic' panicked at test.rs:1:1:
|
||||
expected panic
|
||||
ok
|
||||
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
"""
|
||||
)
|
||||
self.assertEqual(audit.passed_names, ("noisy", "expected_panic"))
|
||||
|
||||
def test_associates_standardized_boundaries_with_failed_tests(self) -> None:
|
||||
audit = parse_log(
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user