test: cover per-session participant metadata refresh
| | |
| | | } |
| | | |
| | | impl RealtimeAsrUpload { |
| | | pub(crate) fn start_with_participant_attributes<F>( |
| | | http: Client, |
| | | config: RealtimeAsrConfig, |
| | | call_id: &str, |
| | | trace_id: &str, |
| | | turn_id: &str, |
| | | initial_samples_48k: &[i16], |
| | | read_attributes: F, |
| | | ) -> Result<Self> |
| | | where |
| | | F: FnOnce() -> HashMap<String, String>, |
| | | { |
| | | let metadata = AudioIngressMetadata::from_participant(&read_attributes()) |
| | | .map_err(|reason| anyhow!(reason)) |
| | | .ok() |
| | | .flatten(); |
| | | Self::start( |
| | | http, |
| | | config, |
| | | call_id, |
| | | trace_id, |
| | | turn_id, |
| | | initial_samples_48k, |
| | | metadata.as_ref(), |
| | | ) |
| | | } |
| | | |
| | | pub(crate) fn start( |
| | | http: Client, |
| | | config: RealtimeAsrConfig, |
| | |
| | | ); |
| | | } |
| | | |
| | | #[tokio::test] |
| | | async fn production_session_boundary_reads_updated_attributes_per_session() { |
| | | let mut attributes = HashMap::new(); |
| | | attributes.insert( |
| | | "inputSourceCategory".to_string(), |
| | | "controlled_fixture".to_string(), |
| | | ); |
| | | attributes.insert( |
| | | "clientFixtureSequence".to_string(), |
| | | "fixture-01".to_string(), |
| | | ); |
| | | let (url1, captured1, server1) = |
| | | spawn_http_fixture(json!({"code": 0, "data": {"status": "cancelled"}}).to_string()); |
| | | let upload1 = RealtimeAsrUpload::start_with_participant_attributes( |
| | | Client::new(), |
| | | fixture_config(url1), |
| | | "call-001", |
| | | "trace-001", |
| | | "turn-0001", |
| | | &vec![1; 9_600], |
| | | || attributes.clone(), |
| | | ) |
| | | .expect("session one"); |
| | | upload1.cancel("test").await; |
| | | let request1 = captured1.recv().expect("session one request"); |
| | | server1.join().expect("session one server"); |
| | | assert!( |
| | | request1 |
| | | .body |
| | | .contains("\"clientFixtureSequence\":\"fixture-01\"") |
| | | ); |
| | | assert!(!request1.body.contains("fixture-02")); |
| | | |
| | | attributes.insert( |
| | | "clientFixtureSequence".to_string(), |
| | | "fixture-02".to_string(), |
| | | ); |
| | | let (url2, captured2, server2) = |
| | | spawn_http_fixture(json!({"code": 0, "data": {"status": "cancelled"}}).to_string()); |
| | | let upload2 = RealtimeAsrUpload::start_with_participant_attributes( |
| | | Client::new(), |
| | | fixture_config(url2), |
| | | "call-001", |
| | | "trace-001", |
| | | "turn-0002", |
| | | &vec![1; 9_600], |
| | | || attributes.clone(), |
| | | ) |
| | | .expect("session two"); |
| | | upload2.cancel("test").await; |
| | | let request2 = captured2.recv().expect("session two request"); |
| | | server2.join().expect("session two server"); |
| | | assert!( |
| | | request2 |
| | | .body |
| | | .contains("\"clientFixtureSequence\":\"fixture-02\"") |
| | | ); |
| | | assert!(!request2.body.contains("fixture-01")); |
| | | } |
| | | |
| | | #[test] |
| | | fn maximum_audio_chunk_stays_within_java_line_limit() { |
| | | let line = audio_chunk_line(1, &vec![0; 8_000]).expect("maximum chunk line"); |
| | |
| | | |
| | | if !was_in_speech && is_in_speech { |
| | | let turn_id = format!("turn-{:04}", vad.turn_index); |
| | | let ingress_metadata = match AudioIngressMetadata::from_participant( |
| | | &participant.attributes(), |
| | | ) { |
| | | Ok(value) => value, |
| | | Err(reason) => { |
| | | warn!(call_id = %call_id, trace_id = %trace_id, |
| | | turn_id = %turn_id, metadata_status = "invalid", reason = reason, |
| | | "runtime helper ignored invalid audio ingress metadata"); |
| | | None |
| | | } |
| | | }; |
| | | match RealtimeAsrUpload::start( |
| | | match RealtimeAsrUpload::start_with_participant_attributes( |
| | | http.clone(), |
| | | turn_bridge_config.realtime_asr_config(), |
| | | &call_id, |
| | | &trace_id, |
| | | &turn_id, |
| | | &vad.speech_samples, |
| | | ingress_metadata.as_ref(), |
| | | || participant.attributes(), |
| | | ) { |
| | | Ok(upload) => { |
| | | info!( |