ic_test/icp/
mod.rs

1use std::{sync::Arc, time::Duration};
2
3use candid::Principal;
4use pocket_ic::{nonblocking::PocketIc, PocketIcBuilder, Time};
5use test_principals::TEST_PRINCIPALS;
6use user::IcpUser;
7
8pub mod caller;
9pub mod deployer;
10pub mod provider;
11pub mod user;
12
13#[cfg(feature = "evm")]
14pub(crate) mod http_outcalls;
15
16pub(crate) mod test_principals;
17
18/// A local Internet Computer environment based on `PocketIc`.
19pub struct Icp {
20    /// Shared reference to the `PocketIc` instance.
21    pub pic: Arc<PocketIc>,
22}
23
24impl Icp {
25    /// Create a new `Icp` environment.
26    pub async fn new() -> Self {
27        let pic = PocketIcBuilder::new()
28            .with_nns_subnet()
29            .with_ii_subnet()
30            .with_log_level(slog::Level::Error)
31            .build_async()
32            .await;
33
34        // Set the starting time to a fixed value for determinism
35        let time = Time::from_nanos_since_unix_epoch(1_740_000_000_000_000_000);
36
37        pic.set_time(time).await;
38
39        Self { pic: Arc::new(pic) }
40    }
41
42    /// The total number of predefined test users available.
43    pub fn test_user_count(&self) -> usize {
44        TEST_PRINCIPALS.len()
45    }
46
47    /// Get a test user by index.
48    pub fn test_user(&self, index: usize) -> IcpUser {
49        if index >= self.test_user_count() {
50            panic!(
51                "Reached maximum number of test users: {}",
52                self.test_user_count()
53            );
54        }
55        self.user_from(Principal::from_text(TEST_PRINCIPALS[index]).unwrap())
56    }
57
58    /// Return the default test user (index 0).
59    pub fn default_user(&self) -> IcpUser {
60        self.test_user(0)
61    }
62
63    /// Construct an `IcpUser` from a given principal.
64    pub fn user_from(&self, principal: Principal) -> IcpUser {
65        IcpUser {
66            principal,
67            pic: Arc::clone(&self.pic),
68        }
69    }
70
71    /// Advance simulated time by 1 second and tick the IC.
72    pub async fn tick(&self) {
73        self.pic.advance_time(Duration::from_secs(1)).await;
74        self.pic.tick().await;
75    }
76
77    /// Returns a reference to the underlying `PocketIc` instance.
78    pub fn pocket_ic(&self) -> &PocketIc {
79        &self.pic
80    }
81}