fix(ci): close capability races and green audit
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user