ic_test/icp/
mod.rs

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