diff --git a/Cargo.lock b/Cargo.lock index cf4dd92f26..43d67d10f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1373,7 +1373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -2352,12 +2352,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "dotenvy" version = "0.15.7" @@ -4030,7 +4024,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4907,7 +4901,7 @@ dependencies = [ "cw3", "cw4", "dashmap", - "dotenv", + "dotenvy", "futures", "humantime-serde", "moka", @@ -4952,6 +4946,7 @@ dependencies = [ "sqlx", "tempfile", "tendermint", + "test-with", "thiserror 2.0.12", "time", "tokio", @@ -8229,6 +8224,28 @@ dependencies = [ "elliptic-curve", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -8397,7 +8414,7 @@ dependencies = [ "once_cell", "socket2 0.5.10", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -8882,7 +8899,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -10189,7 +10206,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix 1.0.8", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -10305,6 +10322,19 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-with" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f370b9efbfbbc5f057cbce9888373eaeb146a3095bb8cc869b199c94d15559" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "regex", + "syn 2.0.104", +] + [[package]] name = "testnet-manager" version = "0.1.0" @@ -11879,7 +11909,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fe96153058..3ad9a3e0a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -330,6 +330,7 @@ syn = "2" sysinfo = "0.37.0" tap = "1.0.1" tar = "0.4.44" +test-with = { version = "0.15.4", default-features = false } tempfile = "3.20" thiserror = "2.0" time = "0.3.41" diff --git a/common/task/src/cancellation.rs b/common/task/src/cancellation.rs index d45296caca..ba60f79308 100644 --- a/common/task/src/cancellation.rs +++ b/common/task/src/cancellation.rs @@ -110,6 +110,7 @@ impl ShutdownToken { // exposed method with the old name for easier migration // it will eventually be removed so please try to use `.clone_with_suffix` instead #[must_use] + #[deprecated(note = "use .clone_with_suffix instead")] pub fn fork>(&self, child_suffix: S) -> Self { self.clone_with_suffix(child_suffix) } @@ -117,6 +118,7 @@ impl ShutdownToken { // exposed method with the old name for easier migration // it will eventually be removed so please try to use `.clone().named(name)` instead #[must_use] + #[deprecated(note = "use .clone().named(name) instead")] pub fn fork_named>(&self, name: S) -> Self { self.clone().named(name) } @@ -232,6 +234,16 @@ impl ShutdownManager { manager.with_shutdown(async move { cancel_watcher.cancelled().await }) } + pub fn empty_mock() -> Self { + ShutdownManager { + root_token: ShutdownToken::ephemeral(), + legacy_task_manager: None, + shutdown_signals: Default::default(), + tracker: Default::default(), + max_shutdown_duration: Default::default(), + } + } + pub fn with_legacy_task_manager(mut self) -> Self { let mut legacy_manager = TaskManager::default().named(format!("{}-legacy", self.root_token.name())); diff --git a/deny.toml b/deny.toml index 7a3323ce1b..4809f4e766 100644 --- a/deny.toml +++ b/deny.toml @@ -119,7 +119,6 @@ exceptions = [ #{ allow = ["Zlib"], crate = "adler32" }, { allow = ["GPL-3.0"], crate = "nym-api" }, { allow = ["GPL-3.0"], crate = "nym-gateway" }, - { allow = ["GPL-3.0"], crate = "nym-mixnode" }, { allow = ["GPL-3.0"], crate = "nym-network-requester" }, { allow = ["GPL-3.0"], crate = "nym-node" }, { allow = ["GPL-3.0"], crate = "nym-validator-rewarder" }, diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index 018f037dff..87a8eb9ed2 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -126,7 +126,8 @@ cw3 = { workspace = true } cw-utils = { workspace = true } rand_chacha = { workspace = true } sha2 = { workspace = true } -dotenv = "0.15" +dotenvy = { workspace = true } +test-with = { workspace = true, default-features = false } [lints] workspace = true diff --git a/nym-api/src/ecash/dkg/controller/mod.rs b/nym-api/src/ecash/dkg/controller/mod.rs index 6182d2f175..d5a8f804e3 100644 --- a/nym-api/src/ecash/dkg/controller/mod.rs +++ b/nym-api/src/ecash/dkg/controller/mod.rs @@ -11,7 +11,7 @@ use anyhow::{bail, Result}; use nym_coconut_dkg_common::types::{Epoch, EpochId, EpochState}; use nym_crypto::asymmetric::ed25519; use nym_dkg::bte::keys::KeyPair as DkgKeyPair; -use nym_task::{TaskClient, TaskManager}; +use nym_task::{ShutdownManager, ShutdownToken}; use rand::rngs::OsRng; use rand::{CryptoRng, Rng, RngCore}; use std::path::PathBuf; @@ -273,7 +273,7 @@ impl DkgController { tick_duration < min } - pub(crate) async fn run(mut self, mut shutdown: TaskClient) { + pub(crate) async fn run(mut self, shutdown: ShutdownToken) { let mut interval = interval(self.polling_rate); interval.set_missed_tick_behavior(MissedTickBehavior::Delay); @@ -282,7 +282,7 @@ impl DkgController { let mut last_polled = OffsetDateTime::now_utc(); let mut last_tick_duration = Default::default(); - while !shutdown.is_shutdown() { + while !shutdown.is_cancelled() { tokio::select! { _ = interval.tick() => { let now = OffsetDateTime::now_utc(); @@ -300,7 +300,7 @@ impl DkgController { error!("failed to update the DKG state: {err}") } } - _ = shutdown.recv() => { + _ = shutdown.cancelled() => { trace!("DkgController: Received shutdown"); } } @@ -314,12 +314,12 @@ impl DkgController { dkg_bte_keypair: DkgKeyPair, identity_key: ed25519::PublicKey, rng: R, - shutdown: &TaskManager, + shutdown_manager: &ShutdownManager, ) -> Result<()> where R: Sync + Send + 'static, { - let shutdown_listener = shutdown.subscribe(); + let shutdown_listener = shutdown_manager.clone_token("DKG controller"); let dkg_controller = DkgController::new( config, nyxd_client, diff --git a/nym-api/src/ecash/state/cleaner.rs b/nym-api/src/ecash/state/cleaner.rs index 4b4c242e35..478443810b 100644 --- a/nym-api/src/ecash/state/cleaner.rs +++ b/nym-api/src/ecash/state/cleaner.rs @@ -6,7 +6,7 @@ use crate::node_status_api::models::NymApiStorageError; use crate::support::config::Config; use crate::support::storage::NymApiStorage; use nym_ecash_time::ecash_today_date; -use nym_task::TaskClient; +use nym_task::ShutdownToken; use std::time::Duration; use time::Date; use tokio::task::JoinHandle; @@ -20,11 +20,15 @@ pub struct EcashBackgroundStateCleaner { verified_tickets_retention_period_days: u32, storage: NymApiStorage, - task_client: TaskClient, + shutdown_token: ShutdownToken, } impl EcashBackgroundStateCleaner { - pub fn new(global_config: &Config, storage: NymApiStorage, task_client: TaskClient) -> Self { + pub fn new( + global_config: &Config, + storage: NymApiStorage, + shutdown_token: ShutdownToken, + ) -> Self { EcashBackgroundStateCleaner { run_interval: global_config.ecash_signer.debug.stale_data_cleaner_interval, issued_ticketbooks_retention_period_days: global_config @@ -36,7 +40,7 @@ impl EcashBackgroundStateCleaner { .debug .verified_tickets_retention_period_days, storage, - task_client, + shutdown_token, } } @@ -68,7 +72,7 @@ impl EcashBackgroundStateCleaner { let mut ticker = tokio::time::interval(self.run_interval); loop { tokio::select! { - _ = self.task_client.recv() => { + _ = self.shutdown_token.cancelled() => { trace!("EcashBackgroundStateCleaner: Received shutdown"); break; } diff --git a/nym-api/src/ecash/state/mod.rs b/nym-api/src/ecash/state/mod.rs index a4d8a39f46..78ca592acf 100644 --- a/nym-api/src/ecash/state/mod.rs +++ b/nym-api/src/ecash/state/mod.rs @@ -44,7 +44,7 @@ use nym_ecash_contract_common::deposit::{Deposit, DepositId}; use nym_ecash_contract_common::msg::ExecuteMsg; use nym_ecash_contract_common::redeem_credential::BATCH_REDEMPTION_PROPOSAL_TITLE; use nym_ecash_time::{ecash_default_expiration_date, ecash_today_date}; -use nym_task::TaskClient; +use nym_task::ShutdownManager; use nym_ticketbooks_merkle::{IssuedTicketbook, IssuedTicketbooksFullMerkleProof, MerkleLeaf}; use nym_validator_client::nyxd::AccountId; use nym_validator_client::EcashApiClient; @@ -126,7 +126,7 @@ impl EcashState { key_pair: KeyPair, comm_channel: D, storage: NymApiStorage, - task_client: TaskClient, + shutdown_manager: &ShutdownManager, ) -> Self where C: LocalClient + Send + Sync + 'static, @@ -135,7 +135,11 @@ impl EcashState { Self { config: EcashStateConfig::new(global_config), background_cleaner_state: BackgroundCleanerState::WaitingStartup( - EcashBackgroundStateCleaner::new(global_config, storage.clone(), task_client), + EcashBackgroundStateCleaner::new( + global_config, + storage.clone(), + shutdown_manager.clone_token("ecash-state-data-cleaner"), + ), ), global: GlobalEcachState::new(contract_address), local: LocalEcashState::new( diff --git a/nym-api/src/ecash/tests/mod.rs b/nym-api/src/ecash/tests/mod.rs index 2152ae7274..db067962b9 100644 --- a/nym-api/src/ecash/tests/mod.rs +++ b/nym-api/src/ecash/tests/mod.rs @@ -59,7 +59,7 @@ use nym_crypto::asymmetric::ed25519; use nym_dkg::{NodeIndex, Threshold}; use nym_ecash_contract_common::blacklist::{BlacklistedAccountResponse, Blacklisting}; use nym_ecash_contract_common::deposit::{Deposit, DepositId, DepositResponse}; -use nym_task::TaskClient; +use nym_task::ShutdownManager; use nym_validator_client::nym_api::routes::{ ECASH_BLIND_SIGN, ECASH_ISSUED_TICKETBOOKS_CHALLENGE_COMMITMENT, ECASH_ISSUED_TICKETBOOKS_FOR, ECASH_ROUTES, V1_API_VERSION, @@ -1348,7 +1348,7 @@ impl TestFixture { staged_key_pair, comm_channel, storage.clone(), - TaskClient::dummy(), + &ShutdownManager::empty_mock(), ); // ideally this would have been generic, but that's way too much work @@ -1489,7 +1489,6 @@ mod credential_tests { use super::*; use crate::ecash::storage::EcashStorageExt; use axum::http::StatusCode; - use nym_task::TaskClient; use nym_ticketbooks_merkle::MerkleLeaf; #[tokio::test] @@ -1580,7 +1579,7 @@ mod credential_tests { staged_key_pair, comm_channel, storage.clone(), - TaskClient::dummy(), + &ShutdownManager::empty_mock(), ); let deposit_id = 42; diff --git a/nym-api/src/epoch_operations/mod.rs b/nym-api/src/epoch_operations/mod.rs index 572b941c99..1137af51b1 100644 --- a/nym-api/src/epoch_operations/mod.rs +++ b/nym-api/src/epoch_operations/mod.rs @@ -21,7 +21,7 @@ use crate::support::storage::NymApiStorage; use error::RewardingError; pub(crate) use helpers::RewardedNodeWithParams; use nym_mixnet_contract_common::{CurrentIntervalResponse, Interval}; -use nym_task::{TaskClient, TaskManager}; +use nym_task::{ShutdownManager, ShutdownToken}; use std::time::Duration; use tokio::time::sleep; use tracing::{error, info, trace, warn}; @@ -164,7 +164,7 @@ impl EpochAdvancer { Ok(()) } - async fn wait_until_epoch_end(&mut self, shutdown: &mut TaskClient) -> Option { + async fn wait_until_epoch_end(&mut self, shutdown_token: &ShutdownToken) -> Option { const POLL_INTERVAL: Duration = Duration::from_secs(120); loop { @@ -175,7 +175,7 @@ impl EpochAdvancer { _ = sleep(POLL_INTERVAL) => { continue }, - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("wait_until_epoch_end: Received shutdown"); break None } @@ -203,7 +203,7 @@ impl EpochAdvancer { _ = sleep(wait_time) => { }, - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("wait_until_epoch_end: Received shutdown"); break None } @@ -212,7 +212,10 @@ impl EpochAdvancer { } } - pub(crate) async fn run(&mut self, mut shutdown: TaskClient) -> Result<(), RewardingError> { + pub(crate) async fn run( + &mut self, + shutdown_token: ShutdownToken, + ) -> Result<(), RewardingError> { info!("waiting for initial contract cache values before we can start rewarding"); self.nym_contract_cache .naive_wait_for_initial_values() @@ -221,8 +224,8 @@ impl EpochAdvancer { info!("waiting for initial self-described cache values before we can start rewarding"); self.described_cache.naive_wait_for_initial_values().await; - while !shutdown.is_shutdown() { - let interval_details = match self.wait_until_epoch_end(&mut shutdown).await { + while !shutdown_token.is_cancelled() { + let interval_details = match self.wait_until_epoch_end(&shutdown_token).await { // received a shutdown None => return Ok(()), Some(interval) => interval, @@ -243,17 +246,17 @@ impl EpochAdvancer { status_cache: &NodeStatusCache, described_cache: SharedCache, storage: &NymApiStorage, - shutdown: &TaskManager, + shutdown_manager: &ShutdownManager, ) { - let mut rewarded_set_updater = EpochAdvancer::new( + let mut epoch_advancer = EpochAdvancer::new( nyxd_client, nym_contract_cache.to_owned(), status_cache.to_owned(), described_cache, storage.to_owned(), ); - let shutdown_listener = shutdown.subscribe(); - tokio::spawn(async move { rewarded_set_updater.run(shutdown_listener).await }); + let shutdown_listener = shutdown_manager.clone_token("epoch-advancer"); + tokio::spawn(async move { epoch_advancer.run(shutdown_listener).await }); } } diff --git a/nym-api/src/key_rotation/mod.rs b/nym-api/src/key_rotation/mod.rs index c6bc0cbe8b..44f11be7ef 100644 --- a/nym-api/src/key_rotation/mod.rs +++ b/nym-api/src/key_rotation/mod.rs @@ -4,7 +4,7 @@ use crate::mixnet_contract_cache::cache::MixnetContractCache; use crate::support::caching::refresher::{CacheUpdateWatcher, RefreshRequester}; use nym_mixnet_contract_common::{Interval, KeyRotationState}; -use nym_task::TaskClient; +use nym_task::ShutdownToken; use time::OffsetDateTime; use tracing::{debug, error, info, trace}; @@ -110,14 +110,14 @@ impl KeyRotationController { } } - async fn run(&mut self, mut task_client: TaskClient) { + async fn run(&mut self, shutdown_token: ShutdownToken) { self.contract_cache.naive_wait_for_initial_values().await; self.handle_contract_cache_update().await; - while !task_client.is_shutdown() { + while !shutdown_token.is_cancelled() { tokio::select! { biased; - _ = task_client.recv() => { + _ = shutdown_token.cancelled() => { trace!("KeyRotationController: Received shutdown"); } _ = self.contract_cache_watcher.changed() => { @@ -129,8 +129,8 @@ impl KeyRotationController { trace!("KeyRotationController: exiting") } - pub(crate) fn start(mut self, task_client: TaskClient) { - tokio::spawn(async move { self.run(task_client).await }); + pub(crate) fn start(mut self, shutdown_token: ShutdownToken) { + tokio::spawn(async move { self.run(shutdown_token).await }); } } diff --git a/nym-api/src/network_monitor/mod.rs b/nym-api/src/network_monitor/mod.rs index d0134cafa6..eaa6f8667e 100644 --- a/nym-api/src/network_monitor/mod.rs +++ b/nym-api/src/network_monitor/mod.rs @@ -25,7 +25,7 @@ use nym_crypto::asymmetric::{ed25519, x25519}; use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::params::PacketType; use nym_sphinx::receiver::MessageReceiver; -use nym_task::TaskManager; +use nym_task::ShutdownManager; use std::sync::Arc; use tracing::info; @@ -167,12 +167,12 @@ impl NetworkMonitorRunnables { // TODO: note, that is not exactly doing what we want, because when // `ReceivedProcessor` is constructed, it already spawns a future // this needs to be refactored! - pub(crate) fn spawn_tasks(self, shutdown: &TaskManager) { + pub(crate) fn spawn_tasks(self, shutdown: &ShutdownManager) { let mut packet_receiver = self.packet_receiver; let mut monitor = self.monitor; - let shutdown_listener = shutdown.subscribe(); + let shutdown_listener = shutdown.clone_token("NM-packet-receiver"); tokio::spawn(async move { packet_receiver.run(shutdown_listener).await }); - let shutdown_listener = shutdown.subscribe(); + let shutdown_listener = shutdown.clone_token("NM-main"); tokio::spawn(async move { monitor.run(shutdown_listener).await }); } } @@ -241,7 +241,7 @@ pub(crate) async fn start( node_status_cache: NodeStatusCache, storage: &NymApiStorage, nyxd_client: nyxd::Client, - shutdown: &TaskManager, + shutdown: &ShutdownManager, ) { let monitor_builder = setup( config, diff --git a/nym-api/src/network_monitor/monitor/mod.rs b/nym-api/src/network_monitor/monitor/mod.rs index 360a946638..d51793acb9 100644 --- a/nym-api/src/network_monitor/monitor/mod.rs +++ b/nym-api/src/network_monitor/monitor/mod.rs @@ -12,7 +12,7 @@ use crate::support::config; use nym_mixnet_contract_common::NodeId; use nym_sphinx::params::PacketType; use nym_sphinx::receiver::MessageReceiver; -use nym_task::TaskClient; +use nym_task::ShutdownToken; use std::collections::{HashMap, HashSet}; use tokio::time::{sleep, Duration, Instant}; use tracing::{debug, error, info, trace}; @@ -325,7 +325,7 @@ impl Monitor { self.test_nonce += 1; } - pub(crate) async fn run(&mut self, mut shutdown: TaskClient) { + pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) { self.received_processor.start_receiving(); // wait for validator cache to be ready @@ -334,18 +334,18 @@ impl Monitor { .await; let mut run_interval = tokio::time::interval(self.run_interval); - while !shutdown.is_shutdown() { + while !shutdown_token.is_cancelled() { tokio::select! { _ = run_interval.tick() => { tokio::select! { biased; - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("UpdateHandler: Received shutdown"); } _ = self.test_run() => (), } } - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("UpdateHandler: Received shutdown"); } } diff --git a/nym-api/src/network_monitor/monitor/receiver.rs b/nym-api/src/network_monitor/monitor/receiver.rs index e84398b9b4..e5f27a1c0a 100644 --- a/nym-api/src/network_monitor/monitor/receiver.rs +++ b/nym-api/src/network_monitor/monitor/receiver.rs @@ -7,7 +7,7 @@ use futures::channel::mpsc; use futures::StreamExt; use nym_crypto::asymmetric::ed25519; use nym_gateway_client::{AcknowledgementReceiver, MixnetMessageReceiver}; -use nym_task::TaskClient; +use nym_task::ShutdownToken; use tracing::{error, trace}; pub(crate) type GatewayClientUpdateSender = mpsc::UnboundedSender; @@ -57,11 +57,11 @@ impl PacketReceiver { } } - pub(crate) async fn run(&mut self, mut shutdown: TaskClient) { - while !shutdown.is_shutdown() { + pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) { + while !shutdown_token.is_cancelled() { tokio::select! { biased; - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("UpdateHandler: Received shutdown"); } // unwrap here is fine as it can only return a `None` if the PacketSender has died diff --git a/nym-api/src/node_performance/contract_cache/mod.rs b/nym-api/src/node_performance/contract_cache/mod.rs index 412b2f00b1..be430935a5 100644 --- a/nym-api/src/node_performance/contract_cache/mod.rs +++ b/nym-api/src/node_performance/contract_cache/mod.rs @@ -10,7 +10,7 @@ use crate::support::caching::cache::SharedCache; use crate::support::caching::refresher::CacheRefresher; use crate::support::{config, nyxd}; use anyhow::bail; -use nym_task::TaskManager; +use nym_task::ShutdownManager; pub(crate) mod data; pub(crate) mod refresher; @@ -19,7 +19,7 @@ pub(crate) async fn start_cache_refresher( config: &config::PerformanceProvider, nyxd_client: nyxd::Client, mixnet_contract_cache: MixnetContractCache, - task_manager: &TaskManager, + shutdown_manager: &ShutdownManager, ) -> anyhow::Result> { let values_to_retain = config.debug.max_epoch_entries_to_retain; @@ -45,7 +45,7 @@ pub(crate) async fn start_cache_refresher( .with_update_fn(move |main_cache, update| { refresher_update_fn(main_cache, update, values_to_retain) }) - .start(task_manager.subscribe_named("performance-contract-cache-refresher")); + .start(shutdown_manager.clone_token("performance-contract-cache-refresher")); Ok(warmed_up_cache) } diff --git a/nym-api/src/node_status_api/cache/refresher.rs b/nym-api/src/node_status_api/cache/refresher.rs index 5232155625..ab323f918f 100644 --- a/nym-api/src/node_status_api/cache/refresher.rs +++ b/nym-api/src/node_status_api/cache/refresher.rs @@ -21,7 +21,7 @@ use nym_api_requests::models::{ NodePerformance, }; use nym_mixnet_contract_common::{NodeId, NymNodeDetails, RewardingParams}; -use nym_task::TaskClient; +use nym_task::ShutdownToken; use nym_topology::CachedEpochRewardedSet; use std::collections::HashMap; use std::time::Duration; @@ -66,20 +66,20 @@ impl NodeStatusCacheRefresher { } /// Runs the node status cache refresher task. - pub async fn run(&mut self, mut shutdown: TaskClient) { + pub async fn run(&mut self, shutdown_token: ShutdownToken) { let mut last_update = OffsetDateTime::now_utc(); let mut fallback_interval = time::interval(self.fallback_caching_interval); - while !shutdown.is_shutdown() { + while !shutdown_token.is_cancelled() { tokio::select! { biased; - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("NodeStatusCacheRefresher: Received shutdown"); } // Update node status cache when the contract cache / describe cache is updated Ok(_) = self.mixnet_contract_cache_listener.changed() => { tokio::select! { _ = self.maybe_refresh(&mut fallback_interval, &mut last_update) => (), - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("NodeStatusCacheRefresher: Received shutdown"); } } @@ -87,7 +87,7 @@ impl NodeStatusCacheRefresher { Ok(_) = self.describe_cache_listener.changed() => { tokio::select! { _ = self.maybe_refresh(&mut fallback_interval, &mut last_update) => (), - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("NodeStatusCacheRefresher: Received shutdown"); } } @@ -97,7 +97,7 @@ impl NodeStatusCacheRefresher { _ = fallback_interval.tick() => { tokio::select! { _ = self.maybe_refresh(&mut fallback_interval, &mut last_update) => (), - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("NodeStatusCacheRefresher: Received shutdown"); } } diff --git a/nym-api/src/node_status_api/mod.rs b/nym-api/src/node_status_api/mod.rs index 1b3d97f839..4473e0c155 100644 --- a/nym-api/src/node_status_api/mod.rs +++ b/nym-api/src/node_status_api/mod.rs @@ -11,7 +11,7 @@ use crate::{ support::{self}, }; pub(crate) use cache::NodeStatusCache; -use nym_task::TaskManager; +use nym_task::ShutdownManager; use std::time::Duration; use tokio::sync::watch; @@ -39,7 +39,7 @@ pub(crate) fn start_cache_refresh( performance_provider: Box, nym_contract_cache_listener: watch::Receiver, described_cache_cache_listener: watch::Receiver, - shutdown: &TaskManager, + shutdown_manager: &ShutdownManager, ) { let mut nym_api_cache_refresher = NodeStatusCacheRefresher::new( node_status_cache_state.to_owned(), @@ -50,6 +50,6 @@ pub(crate) fn start_cache_refresh( described_cache_cache_listener, performance_provider, ); - let shutdown_listener = shutdown.subscribe(); + let shutdown_listener = shutdown_manager.clone_token("node-status-refresher"); tokio::spawn(async move { nym_api_cache_refresher.run(shutdown_listener).await }); } diff --git a/nym-api/src/node_status_api/uptime_updater.rs b/nym-api/src/node_status_api/uptime_updater.rs index a68979ced1..c39d4785b5 100644 --- a/nym-api/src/node_status_api/uptime_updater.rs +++ b/nym-api/src/node_status_api/uptime_updater.rs @@ -6,7 +6,7 @@ use crate::node_status_api::models::{ }; use crate::node_status_api::ONE_DAY; use crate::storage::NymApiStorage; -use nym_task::{TaskClient, TaskManager}; +use nym_task::{ShutdownManager, ShutdownToken}; use std::time::Duration; use time::macros::time; use time::{OffsetDateTime, PrimitiveDateTime}; @@ -70,7 +70,7 @@ impl HistoricalUptimeUpdater { Ok(()) } - pub(crate) async fn run(&self, mut shutdown: TaskClient) { + pub(crate) async fn run(&self, shutdown_token: ShutdownToken) { // update uptimes at 23:00 UTC each day so that we'd have data from the actual [almost] whole day // and so that we would avoid the edge case of starting validator API at 23:59 and having some // nodes update for different days @@ -98,10 +98,10 @@ impl HistoricalUptimeUpdater { let start = Instant::now() + time_left; let mut interval = interval_at(start, ONE_DAY); - while !shutdown.is_shutdown() { + while !shutdown_token.is_cancelled() { tokio::select! { biased; - _ = shutdown.recv() => { + _ = shutdown_token.cancelled() => { trace!("UpdateHandler: Received shutdown"); } _ = interval.tick() => { @@ -116,9 +116,9 @@ impl HistoricalUptimeUpdater { } } - pub(crate) fn start(storage: NymApiStorage, shutdown: &TaskManager) { + pub(crate) fn start(storage: NymApiStorage, shutdown: &ShutdownManager) { let uptime_updater = HistoricalUptimeUpdater::new(storage); - let shutdown_listener = shutdown.subscribe(); + let shutdown_listener = shutdown.child_token("uptime-updater"); tokio::spawn(async move { uptime_updater.run(shutdown_listener).await }); } } diff --git a/nym-api/src/signers_cache/mod.rs b/nym-api/src/signers_cache/mod.rs index f79e1a1f1d..c902a4d52c 100644 --- a/nym-api/src/signers_cache/mod.rs +++ b/nym-api/src/signers_cache/mod.rs @@ -6,7 +6,7 @@ use crate::signers_cache::cache::SignersCacheData; use crate::support::caching::cache::SharedCache; use crate::support::caching::refresher::CacheRefresher; use crate::support::{config, nyxd}; -use nym_task::TaskManager; +use nym_task::ShutdownManager; pub(crate) mod cache; pub(crate) mod handlers; @@ -14,7 +14,7 @@ pub(crate) mod handlers; pub(crate) fn start_refresher( config: &config::SignersCache, nyxd_client: nyxd::Client, - task_manager: &TaskManager, + shutdown_manager: &ShutdownManager, ) -> SharedCache { let refresher = CacheRefresher::new( SignersCacheDataProvider::new(nyxd_client), @@ -23,7 +23,7 @@ pub(crate) fn start_refresher( .named("signers-cache-refresher"); let shared_cache = refresher.get_shared_cache(); refresher.start_with_delay( - task_manager.subscribe_named("signers-cache-refresher"), + shutdown_manager.clone_token("signers-cache-refresher"), config.debug.refresher_start_delay, ); shared_cache diff --git a/nym-api/src/support/caching/refresher.rs b/nym-api/src/support/caching/refresher.rs index cfb412e449..27d8480c03 100644 --- a/nym-api/src/support/caching/refresher.rs +++ b/nym-api/src/support/caching/refresher.rs @@ -4,7 +4,7 @@ use crate::support::caching::cache::SharedCache; use crate::support::caching::CacheNotification; use async_trait::async_trait; -use nym_task::TaskClient; +use nym_task::ShutdownToken; use std::sync::Arc; use std::time::Duration; use tokio::sync::{watch, Notify}; @@ -223,33 +223,33 @@ where } } - pub async fn refresh(&mut self, task_client: &mut TaskClient) { + pub async fn refresh(&mut self, shutdown_token: &ShutdownToken) { info!("{}: refreshing cache state", self.name); tokio::select! { biased; - _ = task_client.recv() => { + _ = shutdown_token.cancelled() => { trace!("{}: Received shutdown while refreshing cache", self.name) } _ = self.do_refresh_cache() => (), } } - pub async fn run(&mut self, mut task_client: TaskClient) { + pub async fn run(&mut self, shutdown_token: ShutdownToken) { self.provider.wait_until_ready().await; let mut refresh_interval = interval(self.refreshing_interval); - while !task_client.is_shutdown() { + while !shutdown_token.is_cancelled() { tokio::select! { biased; - _ = task_client.recv() => { + _ = shutdown_token.cancelled() => { trace!("{}: Received shutdown", self.name) } - _ = refresh_interval.tick() => self.refresh(&mut task_client).await, + _ = refresh_interval.tick() => self.refresh(&shutdown_token).await, // note: `Notify` is not cancellation safe, HOWEVER, there's only one listener, // so it doesn't matter if we lose our queue position _ = self.refresh_requester.0.notified() => { - self.refresh(&mut task_client).await; + self.refresh(&shutdown_token).await; // since we just performed the full request, we can reset our existing interval refresh_interval.reset(); } @@ -257,16 +257,16 @@ where } } - pub fn start(mut self, task_client: TaskClient) + pub fn start(mut self, shutdown_token: ShutdownToken) where T: Send + Sync + 'static, E: Send + Sync + 'static, S: Send + Sync + 'static, { - tokio::spawn(async move { self.run(task_client).await }); + tokio::spawn(async move { self.run(shutdown_token).await }); } - pub fn start_with_delay(mut self, mut task_client: TaskClient, delay: Duration) + pub fn start_with_delay(mut self, shutdown_token: ShutdownToken, delay: Duration) where T: Send + Sync + 'static, E: Send + Sync + 'static, @@ -276,24 +276,24 @@ where let sleep = tokio::time::sleep(delay); tokio::select! { biased; - _ = task_client.recv() => { + _ = shutdown_token.cancelled() => { trace!("{}: Received shutdown", self.name); return } _ = sleep => {}, } - self.run(task_client).await + self.run(shutdown_token).await }); } - pub fn start_with_watcher(self, task_client: TaskClient) -> CacheUpdateWatcher + pub fn start_with_watcher(self, shutdown_token: ShutdownToken) -> CacheUpdateWatcher where T: Send + Sync + 'static, E: Send + Sync + 'static, S: Send + Sync + 'static, { let receiver = self.update_watcher(); - self.start(task_client); + self.start(shutdown_token); receiver } } diff --git a/nym-api/src/support/cli/run.rs b/nym-api/src/support/cli/run.rs index eb8f609ee4..b6ce6f8cca 100644 --- a/nym-api/src/support/cli/run.rs +++ b/nym-api/src/support/cli/run.rs @@ -27,7 +27,7 @@ use crate::support::http::state::chain_status::ChainStatusCache; use crate::support::http::state::contract_details::ContractDetailsCache; use crate::support::http::state::force_refresh::ForcedRefresh; use crate::support::http::state::AppState; -use crate::support::http::{RouterBuilder, ShutdownHandles, TASK_MANAGER_TIMEOUT_S}; +use crate::support::http::{RouterBuilder, TASK_MANAGER_TIMEOUT_S}; use crate::support::nyxd; use crate::support::storage::runtime_migrations::m001_directory_services_v2_1::migrate_to_directory_services_v2_1; use crate::support::storage::NymApiStorage; @@ -39,12 +39,12 @@ use crate::{ use anyhow::{bail, Context}; use nym_config::defaults::NymNetworkDetails; use nym_sphinx::receiver::SphinxMessageReceiver; -use nym_task::TaskManager; +use nym_task::ShutdownManager; use nym_validator_client::nyxd::Coin; use std::net::SocketAddr; use std::sync::Arc; -use tokio_util::sync::CancellationToken; -use tracing::{error, info}; +use std::time::Duration; +use tracing::info; #[derive(clap::Args, Debug)] pub(crate) struct Args { @@ -119,8 +119,9 @@ pub(crate) struct Args { pub(crate) allow_illegal_ips: bool, } -async fn start_nym_api_tasks(config: &Config) -> anyhow::Result { - let task_manager = TaskManager::new(TASK_MANAGER_TIMEOUT_S); +async fn start_nym_api_tasks(config: &Config) -> anyhow::Result { + let shutdown_manager = ShutdownManager::new("nym-api") + .with_shutdown_duration(Duration::from_secs(TASK_MANAGER_TIMEOUT_S)); let nyxd_client = nyxd::Client::new(config)?; let connected_nyxd = config.get_nyxd_url(); @@ -171,7 +172,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result ecash_keypair_wrapper.clone(), comm_channel, storage.clone(), - task_manager.subscribe_named("ecash-state-data-cleaner"), + &shutdown_manager, ); // if ecash signer is enabled, there are additional constraints on the nym-api, @@ -204,7 +205,11 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result // check if signers cache is enabled, and if so, start the refresher let ecash_signers_cache = if config.signers_cache.enabled { - signers_cache::start_refresher(&config.signers_cache, nyxd_client.clone(), &task_manager) + signers_cache::start_refresher( + &config.signers_cache, + nyxd_client.clone(), + &shutdown_manager, + ) } else { SharedCache::new() }; @@ -244,7 +249,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result let describe_cache_refresh_requester = describe_cache_refresher.refresh_requester(); let describe_cache_watcher = describe_cache_refresher - .start_with_watcher(task_manager.subscribe_named("node-self-described-data-refresher")); + .start_with_watcher(shutdown_manager.clone_token("node-self-described-data-refresher")); let performance_provider = if config.performance_provider.use_performance_contract_data { if network_details @@ -260,7 +265,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result &config.performance_provider, nyxd_client.clone(), mixnet_contract_cache_state.clone(), - &task_manager, + &shutdown_manager, ) .await?; let provider = ContractPerformanceProvider::new( @@ -281,8 +286,8 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result &mixnet_contract_cache_state.clone(), nyxd_client.clone(), ); - let contract_cache_watcher = - mixnet_contract_cache_refresher.start_with_watcher(task_manager.subscribe()); + let contract_cache_watcher = mixnet_contract_cache_refresher + .start_with_watcher(shutdown_manager.clone_token("contracts-data-refresher")); node_status_api::start_cache_refresh( &config.node_status_api, @@ -292,7 +297,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result performance_provider, contract_cache_watcher.clone(), describe_cache_watcher, - &task_manager, + &shutdown_manager, ); // start dkg task @@ -306,7 +311,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result dkg_bte_keypair, identity_public_key, rand::rngs::OsRng, - &task_manager, + &shutdown_manager, )?; } @@ -323,11 +328,11 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result node_status_cache_state.clone(), &storage, nyxd_client.clone(), - &task_manager, + &shutdown_manager, ) .await; - HistoricalUptimeUpdater::start(storage.to_owned(), &task_manager); + HistoricalUptimeUpdater::start(storage.to_owned(), &shutdown_manager); } // start 'rewarding' if its enabled and there exists source for performance data @@ -339,7 +344,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result &node_status_cache_state, described_nodes_cache.clone(), &storage, - &task_manager, + &shutdown_manager, ); } @@ -350,24 +355,22 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result contract_cache_watcher, mixnet_contract_cache_state, ) - .start(task_manager.subscribe_named("KeyRotationController")); + .start(shutdown_manager.clone_token("KeyRotationController")); let bind_address = config.base.bind_address.to_owned(); let server = router.build_server(&bind_address).await?; - let cancellation_token = CancellationToken::new(); - let shutdown_button = cancellation_token.clone(); - let axum_shutdown_receiver = cancellation_token.cancelled_owned(); - let server_handle = tokio::spawn(async move { + let http_shutdown = shutdown_manager.clone_token("axum-http"); + tokio::spawn(async move { { info!("Started Axum HTTP V2 server on {bind_address}"); - server.run(axum_shutdown_receiver).await + server.run(http_shutdown).await } }); - let shutdown = ShutdownHandles::new(task_manager, server_handle, shutdown_button); + shutdown_manager.close(); - Ok(shutdown) + Ok(shutdown_manager) } pub(crate) async fn execute(args: Args) -> anyhow::Result<()> { @@ -378,32 +381,8 @@ pub(crate) async fn execute(args: Args) -> anyhow::Result<()> { config.validate()?; - let mut axum_shutdown = start_nym_api_tasks(&config).await?; - - // it doesn't matter which server catches the interrupt: it needs only be caught once - if let Err(err) = axum_shutdown.task_manager_mut().catch_interrupt().await { - error!("Error stopping axum tasks: {err}"); - } - - info!("Stopping nym API"); - - axum_shutdown.task_manager_mut().signal_shutdown().ok(); - axum_shutdown.task_manager_mut().wait_for_shutdown().await; - - let running_server = axum_shutdown.shutdown_axum(); - - match running_server.await { - Ok(Ok(_)) => { - info!("Axum HTTP server shut down without errors"); - } - Ok(Err(err)) => { - error!("Axum HTTP server terminated with: {err}"); - anyhow::bail!(err) - } - Err(err) => { - error!("Server task panicked: {err}"); - } - }; + let shutdown_manager = start_nym_api_tasks(&config).await?; + shutdown_manager.run_until_shutdown().await; Ok(()) } diff --git a/nym-api/src/support/http/mod.rs b/nym-api/src/support/http/mod.rs index 39049f38d3..db73c64a3c 100644 --- a/nym-api/src/support/http/mod.rs +++ b/nym-api/src/support/http/mod.rs @@ -1,10 +1,6 @@ // Copyright 2022-2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use nym_task::TaskManager; -use tokio::task::JoinHandle; -use tokio_util::sync::CancellationToken; - pub(crate) mod helpers; pub(crate) mod openapi; pub(crate) mod router; @@ -13,50 +9,3 @@ pub(crate) mod state; pub(crate) use router::RouterBuilder; pub(crate) const TASK_MANAGER_TIMEOUT_S: u64 = 10; - -/// Shutdown goes 2 directions: -/// 1. signal background tasks to gracefully finish -/// 2. signal server itself -/// -/// These are done through separate shutdown handles. Of course, shut down server -/// AFTER you have shut down BG tasks (or past their grace period). -pub(crate) struct ShutdownHandles { - task_manager: TaskManager, - axum_shutdown_button: ShutdownAxum, - /// Tokio JoinHandle for axum server's task - axum_join_handle: AxumJoinHandle, -} - -impl ShutdownHandles { - /// Cancellation token is given to Axum server constructor. When the token - /// receives a shutdown signal, Axum server will shut down gracefully. - pub(crate) fn new( - task_manager: TaskManager, - axum_server_handle: AxumJoinHandle, - shutdown_button: CancellationToken, - ) -> Self { - Self { - task_manager, - axum_shutdown_button: ShutdownAxum(shutdown_button.clone()), - axum_join_handle: axum_server_handle, - } - } - - pub(crate) fn task_manager_mut(&mut self) -> &mut TaskManager { - &mut self.task_manager - } - - /// Signal server to shut down, then return join handle to its - /// `tokio` task - /// - /// https://tikv.github.io/doc/tokio/task/struct.JoinHandle.html - #[must_use] - pub(crate) fn shutdown_axum(self) -> AxumJoinHandle { - self.axum_shutdown_button.0.cancel(); - self.axum_join_handle - } -} - -struct ShutdownAxum(CancellationToken); - -type AxumJoinHandle = JoinHandle>; diff --git a/nym-api/src/support/http/router.rs b/nym-api/src/support/http/router.rs index b04956eed8..1badfff81f 100644 --- a/nym-api/src/support/http/router.rs +++ b/nym-api/src/support/http/router.rs @@ -19,8 +19,8 @@ use axum::routing::get; use axum::Router; use core::net::SocketAddr; use nym_http_api_common::middleware::logging::log_request_info; +use nym_task::ShutdownToken; use tokio::net::TcpListener; -use tokio_util::sync::WaitForCancellationFutureOwned; use tower_http::cors::CorsLayer; use utoipa::OpenApi; use utoipa_swagger_ui::SwaggerUi; @@ -131,14 +131,13 @@ pub(crate) struct ApiHttpServer { } impl ApiHttpServer { - pub async fn run(self, receiver: WaitForCancellationFutureOwned) -> Result<(), std::io::Error> { - // into_make_service_with_connect_info allows us to see client ip address + pub async fn run(self, shutdown_token: ShutdownToken) -> Result<(), std::io::Error> { axum::serve( self.listener, self.router .into_make_service_with_connect_info::(), ) - .with_graceful_shutdown(receiver) + .with_graceful_shutdown(async move { shutdown_token.cancelled().await }) .await } } diff --git a/nym-api/tests/public-api/api_status.rs b/nym-api/tests/public-api/api_status.rs index f6e6230ff2..e06f42ea5c 100644 --- a/nym-api/tests/public-api/api_status.rs +++ b/nym-api/tests/public-api/api_status.rs @@ -1,6 +1,7 @@ use crate::utils::{base_url, make_request, validate_json_response}; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_health() -> Result<(), String> { let url = format!("{}/v1/api-status/health", base_url()?); let res = make_request(&url).await?; @@ -11,6 +12,7 @@ async fn test_health() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_build_information() -> Result<(), String> { let url = format!("{}/v1/api-status/build-information", base_url()?); let res = make_request(&url).await?; diff --git a/nym-api/tests/public-api/circulating_supply.rs b/nym-api/tests/public-api/circulating_supply.rs index 105c48dd07..0f112f0595 100644 --- a/nym-api/tests/public-api/circulating_supply.rs +++ b/nym-api/tests/public-api/circulating_supply.rs @@ -1,6 +1,7 @@ use crate::utils::{base_url, make_request, validate_json_response}; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_circulating_supply() -> Result<(), String> { let url = format!("{}/v1/circulating-supply", base_url()?); let res = make_request(&url).await?; @@ -14,6 +15,7 @@ async fn test_get_circulating_supply() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_circulating_supply_value() -> Result<(), String> { let url = format!( "{}/v1/circulating-supply/circulating-supply-value", @@ -32,6 +34,7 @@ async fn test_get_circulating_supply_value() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_total_supply_value() -> Result<(), String> { let url = format!("{}/v1/circulating-supply/total-supply-value", base_url()?); let res = make_request(&url).await?; diff --git a/nym-api/tests/public-api/contract_cache.rs b/nym-api/tests/public-api/contract_cache.rs index 8510f30d95..0d93bda1f8 100644 --- a/nym-api/tests/public-api/contract_cache.rs +++ b/nym-api/tests/public-api/contract_cache.rs @@ -1,6 +1,7 @@ use crate::utils::{base_url, make_request, validate_json_response}; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_current_epoch() -> Result<(), String> { let url = format!("{}/v1/epoch/current", base_url()?); let res = make_request(&url).await?; @@ -19,6 +20,7 @@ async fn test_get_current_epoch() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_reward_params() -> Result<(), String> { let url = format!("{}/v1/epoch/reward_params", base_url()?); let res = make_request(&url).await?; diff --git a/nym-api/tests/public-api/network.rs b/nym-api/tests/public-api/network.rs index b6e1e3bc4c..6b23f8df7d 100644 --- a/nym-api/tests/public-api/network.rs +++ b/nym-api/tests/public-api/network.rs @@ -1,6 +1,7 @@ use crate::utils::{base_url, test_client, validate_json_response}; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_chain_status() -> Result<(), String> { let url = format!("{}/v1/network/chain-status", base_url()?); let res = test_client() @@ -29,6 +30,7 @@ async fn test_get_chain_status() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_network_details() -> Result<(), String> { let url = format!("{}/v1/network/details", base_url()?); let res = test_client() @@ -54,6 +56,7 @@ async fn test_get_network_details() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_nym_contracts() -> Result<(), String> { let url = format!("{}/v1/network/nym-contracts", base_url()?); let res = test_client() @@ -75,6 +78,7 @@ async fn test_get_nym_contracts() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_nym_contracts_detailed() -> Result<(), String> { let url = format!("{}/v1/network/nym-contracts-detailed", base_url()?); let res = test_client() diff --git a/nym-api/tests/public-api/nym_nodes.rs b/nym-api/tests/public-api/nym_nodes.rs index 425a115620..35d2eaf0ea 100644 --- a/nym-api/tests/public-api/nym_nodes.rs +++ b/nym-api/tests/public-api/nym_nodes.rs @@ -2,6 +2,7 @@ use crate::utils::{base_url, get_any_node_id, make_request, test_client, validat use time::OffsetDateTime; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_bonded_nodes() -> Result<(), String> { let url = format!("{}/v1/nym-nodes/bonded", base_url()?); let res = make_request(&url).await?; @@ -19,6 +20,7 @@ async fn test_get_bonded_nodes() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_described_nodes() -> Result<(), String> { let url = format!("{}/v1/nym-nodes/described", base_url()?); let res = make_request(&url).await?; @@ -37,13 +39,14 @@ async fn test_get_described_nodes() -> Result<(), String> { // TODO enable this once noise is properly integrated // #[tokio::test] +#[test_with::env(NYM_API)] // async fn test_get_noise() -> Result<(), String> { // let url = format!("{}/v1/nym-nodes/noise", base_url()?); // let res = test_client().get(&url).send().await.map_err(|err| panic!("Failed to send request to {}: {}", url, err))?; // let json = validate_json_response(res).await; // } - #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_rewarded_set() -> Result<(), String> { let url = format!("{}/v1/nym-nodes/rewarded-set", base_url()?); let res = make_request(&url).await?; @@ -64,6 +67,7 @@ async fn test_get_rewarded_set() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_annotation_for_node() -> Result<(), String> { let id = get_any_node_id().await?; let url = format!("{}/v1/nym-nodes/annotation/{}", base_url()?, id); @@ -81,6 +85,7 @@ async fn test_get_annotation_for_node() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_historical_performance() -> Result<(), String> { let id = get_any_node_id().await?; let date = OffsetDateTime::now_utc().date().to_string(); @@ -101,6 +106,7 @@ async fn test_get_historical_performance() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_performance_history() -> Result<(), String> { let id = get_any_node_id().await?; let url = format!("{}/v1/nym-nodes/performance-history/{}", base_url()?, id); @@ -120,6 +126,7 @@ async fn test_get_performance_history() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_performance() -> Result<(), String> { let id = get_any_node_id().await?; let url = format!("{}/v1/nym-nodes/performance/{}", base_url()?, id); @@ -138,6 +145,7 @@ async fn test_get_performance() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_uptime_history() -> Result<(), String> { let id = get_any_node_id().await?; let url = format!("{}/v1/nym-nodes/uptime-history/{}", base_url()?, id); diff --git a/nym-api/tests/public-api/status.rs b/nym-api/tests/public-api/status.rs index d0631fb68f..36510f3360 100644 --- a/nym-api/tests/public-api/status.rs +++ b/nym-api/tests/public-api/status.rs @@ -1,6 +1,7 @@ use crate::utils::{base_url, make_request, validate_json_response}; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_config_score_details() -> Result<(), String> { let url = format!("{}/v1/status/config-score-details", base_url()?); let res = make_request(&url).await?; diff --git a/nym-api/tests/public-api/unstable_nym_nodes.rs b/nym-api/tests/public-api/unstable_nym_nodes.rs index e83aea6297..542ddbb35e 100644 --- a/nym-api/tests/public-api/unstable_nym_nodes.rs +++ b/nym-api/tests/public-api/unstable_nym_nodes.rs @@ -1,6 +1,7 @@ use crate::utils::{base_url, make_request, validate_json_response}; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_nodes_active() -> Result<(), String> { let url = format!("{}/v1/unstable/nym-nodes/skimmed/active", base_url()?); let res = make_request(&url).await?; @@ -19,6 +20,7 @@ async fn test_get_skimmed_nodes_active() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_active_mixnodes() -> Result<(), String> { let url = format!( "{}/v1/unstable/nym-nodes/skimmed/mixnodes/active", @@ -44,6 +46,7 @@ async fn test_get_skimmed_active_mixnodes() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_all_mixnodes() -> Result<(), String> { let url = format!("{}/v1/unstable/nym-nodes/skimmed/mixnodes/all", base_url()?); let res = make_request(&url).await?; @@ -66,6 +69,7 @@ async fn test_get_skimmed_all_mixnodes() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_active_exit_gateways() -> Result<(), String> { let url = format!( "{}/v1/unstable/nym-nodes/skimmed/exit-gateways/active", @@ -91,6 +95,7 @@ async fn test_get_skimmed_active_exit_gateways() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_all_exit_gateways() -> Result<(), String> { let url = format!( "{}/v1/unstable/nym-nodes/skimmed/exit-gateways/all", @@ -116,6 +121,7 @@ async fn test_get_skimmed_all_exit_gateways() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_active_entry_gateways() -> Result<(), String> { let url = format!( "{}/v1/unstable/nym-nodes/skimmed/entry-gateways/active", @@ -141,6 +147,7 @@ async fn test_get_skimmed_active_entry_gateways() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_skimmed_all_entry_gateways() -> Result<(), String> { let url = format!( "{}/v1/unstable/nym-nodes/skimmed/entry-gateways/all", diff --git a/nym-api/tests/public-api/unstable_status.rs b/nym-api/tests/public-api/unstable_status.rs index 52a0084480..6ebbb476ca 100644 --- a/nym-api/tests/public-api/unstable_status.rs +++ b/nym-api/tests/public-api/unstable_status.rs @@ -4,6 +4,7 @@ use crate::utils::{ }; #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_gateway_unstable_test_results() -> Result<(), String> { let identity = get_gateway_identity_key().await?; let url = format!( @@ -35,6 +36,7 @@ async fn test_get_gateway_unstable_test_results() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_mixnode_unstable_test_results() -> Result<(), String> { let mix_id = get_mixnode_node_id().await?; let url = format!( @@ -66,6 +68,7 @@ async fn test_get_mixnode_unstable_test_results() -> Result<(), String> { } #[tokio::test] +#[test_with::env(NYM_API)] async fn test_get_latest_network_monitor_run_details() -> Result<(), String> { let url = format!( "{}/v1/status/network-monitor/unstable/run/latest/details", diff --git a/nym-api/tests/public-api/utils.rs b/nym-api/tests/public-api/utils.rs index ad0f61f653..fb697945ff 100644 --- a/nym-api/tests/public-api/utils.rs +++ b/nym-api/tests/public-api/utils.rs @@ -1,4 +1,4 @@ -use dotenv::dotenv; +use dotenvy::dotenv; use reqwest::{Client, Response}; use serde_json::Value;