diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
index 600b408..278d146 100644
--- a/.gitea/workflows/ci.yml
+++ b/.gitea/workflows/ci.yml
@@ -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
diff --git a/RUSTREWRITE.md b/RUSTREWRITE.md
index 6b82e68..a1b19bd 100644
--- a/RUSTREWRITE.md
+++ b/RUSTREWRITE.md
@@ -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
diff --git a/ci/ci-coverage.json b/ci/ci-coverage.json
index 67b32f3..702b48f 100644
--- a/ci/ci-coverage.json
+++ b/ci/ci-coverage.json
@@ -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",
diff --git a/ci/evidence/provenance-audit.json b/ci/evidence/provenance-audit.json
index 1d844b6..fe229dc 100644
--- a/ci/evidence/provenance-audit.json
+++ b/ci/evidence/provenance-audit.json
@@ -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"
diff --git a/crates/libremetaverse/src/caps.rs b/crates/libremetaverse/src/caps.rs
index 38dfb22..a75dc75 100644
--- a/crates/libremetaverse/src/caps.rs
+++ b/crates/libremetaverse/src/caps.rs
@@ -83,6 +83,7 @@ pub(crate) struct CapsInner {
event_queue: Mutex>,
seed_task: Mutex >,
events: Arc,
+ 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, 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))
diff --git a/crates/libremetaverse/src/inventory_manager.rs b/crates/libremetaverse/src/inventory_manager.rs
index f288722..ec06b9a 100644
--- a/crates/libremetaverse/src/inventory_manager.rs
+++ b/crates/libremetaverse/src/inventory_manager.rs
@@ -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 {
diff --git a/release/DISTRIBUTION-MANIFEST.json b/release/DISTRIBUTION-MANIFEST.json
index fcb58a7..afcf757 100644
--- a/release/DISTRIBUTION-MANIFEST.json
+++ b/release/DISTRIBUTION-MANIFEST.json
@@ -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",
diff --git a/tests/PARITY.md b/tests/PARITY.md
index 9e62d3d..1b3d76d 100644
--- a/tests/PARITY.md
+++ b/tests/PARITY.md
@@ -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` |
diff --git a/tests/compat/tests/task_inventory_semantics.rs b/tests/compat/tests/task_inventory_semantics.rs
index 1d248e8..a8227e2 100644
--- a/tests/compat/tests/task_inventory_semantics.rs
+++ b/tests/compat/tests/task_inventory_semantics.rs
@@ -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 {
" ".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(entries: &[Box]) -> &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());
}
diff --git a/tests/red-suite-baseline.json b/tests/red-suite-baseline.json
index fbd5dbc..b4ea82e 100644
--- a/tests/red-suite-baseline.json
+++ b/tests/red-suite-baseline.json
@@ -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
}
diff --git a/tests/upstream-tests.json b/tests/upstream-tests.json
index b04236c..7572e5b 100644
--- a/tests/upstream-tests.json
+++ b/tests/upstream-tests.json
@@ -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"
},
diff --git a/tools/audit_red_suite.py b/tools/audit_red_suite.py
index 3501c12..9c97d09 100644
--- a/tools/audit_red_suite.py
+++ b/tools/audit_red_suite.py
@@ -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"(? 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)}"
)
diff --git a/tools/ci-matrix/src/ci_gate.rs b/tools/ci-matrix/src/ci_gate.rs
index 28be02f..5c89c82 100644
--- a/tools/ci-matrix/src/ci_gate.rs
+++ b/tools/ci-matrix/src/ci_gate.rs
@@ -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",
diff --git a/tools/test_audit_red_suite.py b/tools/test_audit_red_suite.py
index 1d1b39d..3f8b639 100644
--- a/tools/test_audit_red_suite.py
+++ b/tools/test_audit_red_suite.py
@@ -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(
"""