From 31f3b72a3cfdfa2341ba3c9da06c528853c13af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Tue, 31 Oct 2023 10:09:05 +0000 Subject: [PATCH] Retry some async functions in network tests * Some tests are failing in aarch64 and s390x (see #812). --- rust/agama-dbus-server/tests/common/mod.rs | 50 ++++++++++++----- rust/agama-dbus-server/tests/network.rs | 64 ++++++++++------------ 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/rust/agama-dbus-server/tests/common/mod.rs b/rust/agama-dbus-server/tests/common/mod.rs index bcef4aa50a..6d78a98b6a 100644 --- a/rust/agama-dbus-server/tests/common/mod.rs +++ b/rust/agama-dbus-server/tests/common/mod.rs @@ -1,4 +1,6 @@ +use agama_lib::error::ServiceError; use futures::stream::StreamExt; +use futures::Future; use std::error::Error; use std::process::{Child, Command}; use std::time::Duration; @@ -44,7 +46,7 @@ impl DBusServer { } } - pub async fn start(self) -> DBusServer { + pub async fn start(self) -> Result, ServiceError> { let child = Command::new("/usr/bin/dbus-daemon") .args([ "--config-file", @@ -54,22 +56,13 @@ impl DBusServer { ]) .spawn() .expect("to start the testing D-Bus daemon"); - self.wait(500).await; - let connection = agama_lib::connection_to(&self.address).await.unwrap(); - DBusServer { + let connection = async_retry(|| agama_lib::connection_to(&self.address)).await?; + + Ok(DBusServer { address: self.address, extra: Started { child, connection }, - } - } -} - -impl DBusServer { - /// Waits until the D-Bus daemon is ready. - // TODO: implement proper waiting instead of just using a sleep - async fn wait(&self, millis: u64) { - let wait_time = Duration::from_millis(millis); - async_std::task::sleep(wait_time).await; + }) } } @@ -119,3 +112,32 @@ impl NameOwnerChangedStream { } } } + +/// Run and retry an async function. +/// +/// Beware that, if the function is failing for a legit reason, you will +/// introduce a delay in your code. +/// +/// * `func`: async function to run. +pub async fn async_retry(func: F) -> Result +where + F: Fn() -> O, + O: Future>, +{ + const RETRIES: u8 = 10; + const INTERVAL: u64 = 500; + let mut retry = 0; + loop { + match func().await { + Ok(result) => return Ok(result), + Err(error) => { + if retry > RETRIES { + return Err(error); + } + retry = retry + 1; + let wait_time = Duration::from_millis(INTERVAL); + async_std::task::sleep(wait_time).await; + } + } + } +} diff --git a/rust/agama-dbus-server/tests/network.rs b/rust/agama-dbus-server/tests/network.rs index 192442d846..7c35ba964a 100644 --- a/rust/agama-dbus-server/tests/network.rs +++ b/rust/agama-dbus-server/tests/network.rs @@ -1,6 +1,6 @@ mod common; -use self::common::DBusServer; +use self::common::{async_retry, DBusServer}; use agama_dbus_server::network::{ self, model::{self, Ipv4Method, Ipv6Method}, @@ -9,6 +9,7 @@ use agama_dbus_server::network::{ use agama_lib::network::{settings, types::DeviceType, NetworkClient}; use async_std::test; use cidr::IpInet; +use std::error::Error; #[derive(Default)] pub struct NetworkTestAdapter(network::NetworkState); @@ -24,8 +25,8 @@ impl Adapter for NetworkTestAdapter { } #[test] -async fn test_read_connections() { - let mut server = DBusServer::new().start().await; +async fn test_read_connections() -> Result<(), Box> { + let mut server = DBusServer::new().start().await?; let device = model::Device { name: String::from("eth0"), @@ -35,39 +36,30 @@ async fn test_read_connections() { let state = NetworkState::new(vec![device], vec![eth0]); let adapter = NetworkTestAdapter(state); - let _service = NetworkService::start(&server.connection(), adapter) - .await - .unwrap(); + let _service = NetworkService::start(&server.connection(), adapter).await?; + server.request_name().await?; - server.request_name().await.unwrap(); - - let client = NetworkClient::new(server.connection()).await.unwrap(); - let conns = client.connections().await.unwrap(); + let client = NetworkClient::new(server.connection()).await?; + let conns = async_retry(|| client.connections()).await?; assert_eq!(conns.len(), 1); let dbus_eth0 = conns.first().unwrap(); assert_eq!(dbus_eth0.id, "eth0"); assert_eq!(dbus_eth0.device_type(), DeviceType::Ethernet); + Ok(()) } #[test] -async fn test_add_connection() { - let mut server = DBusServer::new().start().await; +async fn test_add_connection() -> Result<(), Box> { + let mut server = DBusServer::new().start().await?; let adapter = NetworkTestAdapter(NetworkState::default()); - let _service = NetworkService::start(&server.connection(), adapter) - .await - .unwrap(); - server.request_name().await.unwrap(); + let _service = NetworkService::start(&server.connection(), adapter).await?; + server.request_name().await?; - let client = NetworkClient::new(server.connection().clone()) - .await - .unwrap(); + let client = NetworkClient::new(server.connection().clone()).await?; - let addresses: Vec = vec![ - "192.168.0.2/24".parse().unwrap(), - "::ffff:c0a8:7ac7/64".parse().unwrap(), - ]; + let addresses: Vec = vec!["192.168.0.2/24".parse()?, "::ffff:c0a8:7ac7/64".parse()?]; let wlan0 = settings::NetworkConnection { id: "wlan0".to_string(), method4: Some("auto".to_string()), @@ -81,9 +73,9 @@ async fn test_add_connection() { }), ..Default::default() }; - client.add_or_update_connection(&wlan0).await.unwrap(); + client.add_or_update_connection(&wlan0).await?; - let conns = client.connections().await.unwrap(); + let conns = async_retry(|| client.connections()).await?; assert_eq!(conns.len(), 1); let conn = conns.first().unwrap(); @@ -94,11 +86,12 @@ async fn test_add_connection() { assert_eq!(method4, &Ipv4Method::Auto.to_string()); let method6 = conn.method6.as_ref().unwrap(); assert_eq!(method6, &Ipv6Method::Disabled.to_string()); + Ok(()) } #[test] -async fn test_update_connection() { - let mut server = DBusServer::new().start().await; +async fn test_update_connection() -> Result<(), Box> { + let mut server = DBusServer::new().start().await?; let device = model::Device { name: String::from("eth0"), @@ -108,16 +101,17 @@ async fn test_update_connection() { let state = NetworkState::new(vec![device], vec![eth0]); let adapter = NetworkTestAdapter(state); - let _service = NetworkService::start(&server.connection(), adapter) - .await - .unwrap(); + let _service = NetworkService::start(&server.connection(), adapter).await?; + server.request_name().await?; - server.request_name().await.unwrap(); + let client = NetworkClient::new(server.connection()).await?; + // make sure connections have been published. + let _conns = async_retry(|| client.connections()).await?; - let client = NetworkClient::new(server.connection()).await.unwrap(); - let mut dbus_eth0 = client.get_connection("eth0").await.unwrap(); + let mut dbus_eth0 = async_retry(|| client.get_connection("eth0")).await?; dbus_eth0.interface = Some("eth0".to_string()); - client.add_or_update_connection(&dbus_eth0).await.unwrap(); - let dbus_eth0 = client.get_connection("eth0").await.unwrap(); + client.add_or_update_connection(&dbus_eth0).await?; + let dbus_eth0 = client.get_connection("eth0").await?; assert_eq!(dbus_eth0.interface, Some("eth0".to_string())); + Ok(()) }