Skip to content

Commit 013fedc

Browse files
committed
add unit tests
1 parent 521bf7a commit 013fedc

6 files changed

Lines changed: 98 additions & 20 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

supervisor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ orb-build-info = { workspace = true, features = ["build-script"] }
3434

3535
[dev-dependencies]
3636
dbus-launch = "0.2.0"
37+
portpicker = "0.1.1"
3738
tokio = { workspace = true, features = ["sync", "test-util"] }
3839

3940
[package.metadata.deb]

supervisor/src/startup.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::time::Duration;
1+
use std::{path::PathBuf, time::Duration};
22

33
use color_eyre::eyre::WrapErr as _;
44
use futures::{future::TryFutureExt as _, FutureExt as _};
@@ -13,6 +13,7 @@ use crate::{
1313
SIGNUP_PROXY_DEFAULT_OBJECT_PATH, SIGNUP_PROXY_DEFAULT_WELL_KNOWN_NAME,
1414
},
1515
tasks,
16+
tasks::zoci::GONDOR_BIN,
1617
};
1718

1819
pub const DBUS_WELL_KNOWN_NAME: &str = "org.worldcoin.OrbSupervisor1";
@@ -41,6 +42,7 @@ pub struct Settings {
4142
pub well_known_name: String,
4243
pub download_throttle: Duration,
4344
pub stop_core_after_signup: Duration,
45+
pub gondor_bin: PathBuf,
4446
}
4547

4648
impl Settings {
@@ -55,6 +57,7 @@ impl Settings {
5557
well_known_name: DBUS_WELL_KNOWN_NAME.to_string(),
5658
download_throttle: DEFAULT_DURATION_TO_ALLOW_DOWNLOADS,
5759
stop_core_after_signup: DURATION_TO_STOP_CORE_AFTER_LAST_SIGNUP,
60+
gondor_bin: PathBuf::from(GONDOR_BIN),
5861
}
5962
}
6063
}
@@ -151,9 +154,10 @@ impl Application {
151154
tasks::spawn_signup_started_task(&self.settings, &self.session_connection)
152155
.await?;
153156

154-
let zoci_handles = tasks::spawn_zoci_receiver(&self.zenorb)
155-
.await
156-
.wrap_err("failed to spawn zoci receiver")?;
157+
let zoci_handles =
158+
tasks::spawn_zoci_receiver(&self.zenorb, self.settings.gondor_bin.clone())
159+
.await
160+
.wrap_err("failed to spawn zoci receiver")?;
157161

158162
let ((),) = tokio::try_join!(
159163
// All tasks are joined here

supervisor/src/tasks/zoci.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::path::PathBuf;
2+
13
use color_eyre::{
24
eyre::{eyre, WrapErr},
35
Result,
@@ -7,20 +9,21 @@ use tokio::task::JoinHandle;
79
use tracing::{info, instrument};
810
use zenorb::{zenoh::query::Query, zoci::ZociQueryExt, Zenorb};
911

10-
const GONDOR_BIN: &str = "/usr/local/bin/gondor-calls-for-ota";
12+
pub const GONDOR_BIN: &str = "/usr/local/bin/gondor-calls-for-ota";
1113

12-
pub async fn spawn_zoci_receiver(zenorb: &Zenorb) -> Result<Vec<JoinHandle<()>>> {
14+
pub async fn spawn_zoci_receiver(
15+
zenorb: &Zenorb,
16+
gondor_bin: PathBuf,
17+
) -> Result<Vec<JoinHandle<()>>> {
1318
zenorb
14-
.receiver(())
15-
.queryable("job/gondor-calls-for-ota", |(), query| {
16-
gondor_calls_for_ota(query)
17-
})
19+
.receiver(gondor_bin)
20+
.queryable("job/gondor-calls-for-ota", gondor_calls_for_ota)
1821
.run()
1922
.await
2023
}
2124

2225
#[instrument(skip(query))]
23-
async fn gondor_calls_for_ota(query: Query) -> Result<()> {
26+
async fn gondor_calls_for_ota(gondor_bin: PathBuf, query: Query) -> Result<()> {
2427
let response = async {
2528
let version = query.payload_str()?;
2629
let version = version.trim();
@@ -29,9 +32,9 @@ async fn gondor_calls_for_ota(query: Query) -> Result<()> {
2932
return Err(eyre!("missing target version"));
3033
}
3134

32-
info!("running {GONDOR_BIN} {version}");
35+
info!("running {} {version}", gondor_bin.display());
3336

34-
let output = Command::new(GONDOR_BIN)
37+
let output = Command::new(&gondor_bin)
3538
.arg(version)
3639
.output()
3740
.await

supervisor/tests/it/helpers.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,22 @@ pub fn make_settings(dbus_instances: &DbusInstances) -> Settings {
5757

5858
pub async fn spawn_supervisor_service(
5959
settings: Settings,
60+
zenorb: Zenorb,
6061
) -> color_eyre::Result<Application> {
6162
Lazy::force(&TRACING);
62-
let zenorb = Zenorb::from_cfg(isolated_zenoh_cfg())
63+
let application = Application::build(settings.clone(), zenorb).await?;
64+
Ok(application)
65+
}
66+
67+
/// A self-contained `Zenorb` that doesn't connect to anything. Suitable for tests
68+
/// that only need to satisfy the `Application::build` signature without exercising
69+
/// any zenoh-backed behavior.
70+
pub async fn isolated_supervisor_zenorb() -> color_eyre::Result<Zenorb> {
71+
Zenorb::from_cfg(isolated_zenoh_cfg())
6372
.liveliness(false)
6473
.orb_id(OrbId::from_str("ea2ea744").unwrap())
6574
.with_name("supervisor")
66-
.await?;
67-
let application = Application::build(settings.clone(), zenorb).await?;
68-
Ok(application)
75+
.await
6976
}
7077

7178
fn isolated_zenoh_cfg() -> zenoh::Config {
@@ -76,6 +83,34 @@ fn isolated_zenoh_cfg() -> zenoh::Config {
7683
cfg
7784
}
7885

86+
/// Spins up an in-process zenoh router on a free loopback port and returns a pair of
87+
/// `Zenorb` clients (named via the supplied arguments) that share the same orb id and
88+
/// communicate through that router. The returned `zenoh::Session` is the router and
89+
/// must be kept alive for the duration of the test.
90+
pub async fn spawn_zenoh_router_and_clients(
91+
name_a: &str,
92+
name_b: &str,
93+
) -> color_eyre::Result<(zenoh::Session, Zenorb, Zenorb)> {
94+
let port = portpicker::pick_unused_port().expect("no free ports");
95+
let router = zenoh::open(zenorb::router_cfg(port))
96+
.await
97+
.map_err(|e| color_eyre::eyre::eyre!("{e}"))?;
98+
99+
let orb_id = OrbId::from_str("ea2ea744").unwrap();
100+
let zenorb_a = Zenorb::from_cfg(zenorb::client_cfg(port))
101+
.liveliness(false)
102+
.orb_id(orb_id.clone())
103+
.with_name(name_a)
104+
.await?;
105+
let zenorb_b = Zenorb::from_cfg(zenorb::client_cfg(port))
106+
.liveliness(false)
107+
.orb_id(orb_id)
108+
.with_name(name_b)
109+
.await?;
110+
111+
Ok((router, zenorb_a, zenorb_b))
112+
}
113+
79114
#[proxy(
80115
interface = "org.worldcoin.OrbSupervisor1.Manager",
81116
gen_async = true,

supervisor/tests/it/main.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::time::Duration;
1+
use std::{path::PathBuf, time::Duration};
22

33
use tap::TapFallible;
44
use tracing::error;
@@ -11,8 +11,10 @@ async fn supervisor_disallows_downloads_if_signup_started_received(
1111
let dbus_instances = helpers::launch_dbuses().await??;
1212

1313
let settings = helpers::make_settings(&dbus_instances);
14+
let zenorb = helpers::isolated_supervisor_zenorb().await?;
1415

15-
let application = helpers::spawn_supervisor_service(settings.clone()).await?;
16+
let application =
17+
helpers::spawn_supervisor_service(settings.clone(), zenorb).await?;
1618
let _application_handle = tokio::spawn(application.run());
1719

1820
let update_agent_proxy =
@@ -47,7 +49,9 @@ async fn supervisor_stops_orb_core_when_update_permission_is_requested(
4749
let dbus_instances = helpers::launch_dbuses().await??;
4850

4951
let settings = helpers::make_settings(&dbus_instances);
50-
let application = helpers::spawn_supervisor_service(settings.clone()).await?;
52+
let zenorb = helpers::isolated_supervisor_zenorb().await?;
53+
let application =
54+
helpers::spawn_supervisor_service(settings.clone(), zenorb).await?;
5155

5256
let _application_handle = tokio::spawn(application.run());
5357

@@ -91,3 +95,33 @@ async fn supervisor_stops_orb_core_when_update_permission_is_requested(
9195

9296
Ok(())
9397
}
98+
99+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
100+
async fn application_serves_gondor_zoci_handler_end_to_end() -> color_eyre::Result<()> {
101+
let dbus_instances = helpers::launch_dbuses().await??;
102+
103+
let (_router, supervisor_zenorb, client_zenorb) =
104+
helpers::spawn_zenoh_router_and_clients("supervisor", "test-client").await?;
105+
106+
let mut settings = helpers::make_settings(&dbus_instances);
107+
settings.gondor_bin = PathBuf::from("/bin/true");
108+
109+
let application =
110+
helpers::spawn_supervisor_service(settings, supervisor_zenorb).await?;
111+
let _application_handle = tokio::spawn(application.run());
112+
113+
// Give Application::run a beat to register its zoci queryable on the router.
114+
tokio::time::sleep(Duration::from_millis(300)).await;
115+
116+
let reply = client_zenorb
117+
.command_raw("supervisor/job/gondor-calls-for-ota", "v1.0.0")
118+
.await?;
119+
120+
if let Err(reply_err) = reply {
121+
let payload =
122+
String::from_utf8_lossy(&reply_err.payload().to_bytes()).into_owned();
123+
panic!("expected success reply, got error: {payload}");
124+
}
125+
126+
Ok(())
127+
}

0 commit comments

Comments
 (0)