Implement native VivoxTest validation (#95)
Some checks failed
Native code generation / deterministic (push) Failing after 2m19s
Imaging and meshing gate / native (push) Failing after 4m24s
JPEG 2000 feature / linux (push) Successful in 2m50s
Native Rust workspace compile / compile (push) Failing after 15m31s
Skia feature / linux (push) Successful in 31m51s
Some checks failed
Native code generation / deterministic (push) Failing after 2m19s
Imaging and meshing gate / native (push) Failing after 4m24s
JPEG 2000 feature / linux (push) Successful in 2m50s
Native Rust workspace compile / compile (push) Failing after 15m31s
Skia feature / linux (push) Successful in 31m51s
This commit is contained in:
@@ -20,6 +20,7 @@ libremetaverse-types = { path = "../../crates/libremetaverse-types" }
|
||||
libremetaverse-utilities = { path = "../../crates/libremetaverse-utilities" }
|
||||
libremetaverse-voice-vivox = { path = "../../crates/libremetaverse-voice-vivox" }
|
||||
libremetaverse-voice-webrtc = { path = "../../crates/libremetaverse-voice-webrtc" }
|
||||
tokio = { version = "1.47.1", features = ["io-util", "macros", "net", "rt-multi-thread", "time"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
117
tests/compat/tests/vivox_protocol_semantics.rs
Normal file
117
tests/compat/tests/vivox_protocol_semantics.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use libremetaverse_voice_vivox::VivoxControlClient;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::time::Duration;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
const EXPECTED_ACTIONS: [&str; 10] = [
|
||||
"Aux.GetCaptureDevices.1",
|
||||
"Aux.GetRenderDevices.1",
|
||||
"Connector.Create.1",
|
||||
"Account.Login.1",
|
||||
"Session.Create.1",
|
||||
"Session.Connect.1",
|
||||
"Session.SetParticipantVolumeForMe.1",
|
||||
"Session.Terminate.1",
|
||||
"Account.Logout.1",
|
||||
"Connector.InitiateShutdown.1",
|
||||
];
|
||||
|
||||
fn response(id: &str, action: &str, result: &str) -> String {
|
||||
format!(
|
||||
"<Response requestId=\"{id}\" action=\"{action}\"><ReturnCode>0</ReturnCode><Results><StatusCode>0</StatusCode><StatusString>OK</StatusString>{result}</Results></Response>\n\n\n"
|
||||
)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn native_vivox_protocol_preserves_control_order_events_and_teardown() {
|
||||
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await.unwrap();
|
||||
let endpoint = listener.local_addr().unwrap();
|
||||
let server = tokio::spawn(async move {
|
||||
let (stream, _) = listener.accept().await.unwrap();
|
||||
let (reader, mut writer) = stream.into_split();
|
||||
let mut reader = BufReader::new(reader);
|
||||
let mut actions = Vec::new();
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
assert_ne!(reader.read_line(&mut line).await.unwrap(), 0);
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let id = line
|
||||
.split("requestId=\"")
|
||||
.nth(1)
|
||||
.and_then(|value| value.split('"').next())
|
||||
.unwrap();
|
||||
let action = line
|
||||
.split("action=\"")
|
||||
.nth(1)
|
||||
.and_then(|value| value.split('"').next())
|
||||
.unwrap();
|
||||
actions.push(action.to_owned());
|
||||
let result = match action {
|
||||
"Aux.GetCaptureDevices.1" => {
|
||||
"<CaptureDevices><CaptureDevice><Device>Mic</Device></CaptureDevice></CaptureDevices><CurrentCaptureDevice><Device>Mic</Device></CurrentCaptureDevice>"
|
||||
}
|
||||
"Aux.GetRenderDevices.1" => {
|
||||
"<RenderDevices><RenderDevice><Device>Speakers</Device></RenderDevice></RenderDevices><CurrentRenderDevice><Device>Speakers</Device></CurrentRenderDevice>"
|
||||
}
|
||||
"Connector.Create.1" => "<ConnectorHandle>connector-secret</ConnectorHandle>",
|
||||
"Account.Login.1" => "<AccountHandle>account-secret</AccountHandle>",
|
||||
"Session.Create.1" => "<SessionHandle>session-secret</SessionHandle>",
|
||||
"Session.Connect.1"
|
||||
| "Session.SetParticipantVolumeForMe.1"
|
||||
| "Session.Terminate.1"
|
||||
| "Account.Logout.1"
|
||||
| "Connector.InitiateShutdown.1" => "",
|
||||
_ => panic!("unexpected Vivox action {action}"),
|
||||
};
|
||||
writer
|
||||
.write_all(response(id, action, result).as_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
if action == "Session.Connect.1" {
|
||||
writer.write_all(b"<Event type=\"ParticipantPropertiesEvent\"><SessionHandle>session-secret</SessionHandle><ParticipantURI>sip:participant-token@example.test</ParticipantURI><DisplayName>Alice Resident</DisplayName><IsSpeaking>true</IsSpeaking><Volume>0</Volume><Energy>0.25</Energy></Event>\n\n\n").await.unwrap();
|
||||
}
|
||||
if action == "Connector.InitiateShutdown.1" {
|
||||
writer.shutdown().await.unwrap();
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut client = VivoxControlClient::connect(endpoint, Duration::from_secs(2))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(client.capture_devices().await.unwrap().available, ["Mic"]);
|
||||
assert_eq!(
|
||||
client.render_devices().await.unwrap().available,
|
||||
["Speakers"]
|
||||
);
|
||||
client
|
||||
.create_connector("https://www.voice.example.test/api2/")
|
||||
.await
|
||||
.unwrap();
|
||||
client.login("voice-user", "voice-password").await.unwrap();
|
||||
let session = client
|
||||
.create_session("sip:channel-token@example.test", "Parity Region", None)
|
||||
.await
|
||||
.unwrap();
|
||||
client.connect_session(&session).await.unwrap();
|
||||
let event = client.next_event().await.unwrap();
|
||||
assert_eq!(event.kind, "ParticipantPropertiesEvent");
|
||||
assert_eq!(event.display_name.as_deref(), Some("Alice Resident"));
|
||||
assert_eq!(event.is_speaking, Some(true));
|
||||
let participant = event.participant_uri.unwrap();
|
||||
client
|
||||
.set_participant_volume(&session, &participant, 0)
|
||||
.await
|
||||
.unwrap();
|
||||
client.terminate_session(&session).await.unwrap();
|
||||
client.logout().await.unwrap();
|
||||
client.shutdown().await.unwrap();
|
||||
client.shutdown().await.unwrap();
|
||||
let actions = server.await.unwrap();
|
||||
assert_eq!(actions, EXPECTED_ACTIONS);
|
||||
}
|
||||
Reference in New Issue
Block a user