Skip to content

Commit 0415a91

Browse files
mraszykIDX GitHub Automation
andauthored
feat: migration canister candid service definition (#7506)
This PR adds a candid service definition for the migration canister and a unit test checking that the provided service definition matches the actual candid interface of the canister. --------- Co-authored-by: IDX GitHub Automation <[email protected]>
1 parent 4652fc6 commit 0415a91

File tree

7 files changed

+62
-5
lines changed

7 files changed

+62
-5
lines changed

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.

rs/migration_canister/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ rust_canister(
5050
rust_test(
5151
name = "mc_tests",
5252
srcs = glob(["src/**/*.rs"]),
53+
compile_data = [":migration_canister.did"],
5354
proc_macro_deps = [
5455
"@crate_index//:strum_macros",
5556
],
5657
deps = [
5758
# Keep sorted.
5859
"@crate_index//:candid",
60+
"@crate_index//:candid_parser",
5961
"@crate_index//:futures",
6062
"@crate_index//:ic-cdk",
6163
"@crate_index//:ic-cdk-timers",

rs/migration_canister/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ strum = { workspace = true }
2020
strum_macros = { workspace = true }
2121

2222
[dev-dependencies]
23+
candid_parser = { workspace = true }
2324
pocket-ic = { path = "../../packages/pocket-ic" }
2425
tempfile = { workspace = true }
2526
tokio = { workspace = true }
Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
1-
type MigrationCanisterInitPayload = record {};
1+
type ListEventsArgs = record { page_size : nat64; page_index : nat64 };
2+
type MigrationStatus = variant {
3+
Failed : record { time : nat64; reason : text };
4+
Succeeded : record { time : nat64 };
5+
InProgress : record { status : text };
6+
};
7+
8+
type MigrateCanisterArgs = record { source : principal; target : principal };
29

3-
service : (opt MigrationCanisterInitPayload) -> {
10+
type MigrationCanisterResult = variant { Ok; Err : MigrationCanisterError };
11+
type MigrationCanisterError = variant { CallerNotAuthorized };
412

13+
type ValidationResult = variant { Ok; Err : ValidationError };
14+
type ValidationError = variant {
15+
CanisterNotFound : record { canister : principal };
16+
CallFailed : record { reason : text };
17+
NotController : record { canister : principal };
18+
CallerNotController : record { canister : principal };
19+
TargetHasSnapshots;
20+
MigrationInProgress : record { canister : principal };
21+
SourceNotStopped;
22+
RateLimited;
23+
MigrationsDisabled;
24+
SourceNotReady;
25+
SourceInsufficientCycles;
26+
SameSubnet;
27+
TargetNotStopped;
528
};
29+
30+
type MigrationCanisterInitArgs = record { allowlist : opt vec principal };
31+
32+
service : (MigrationCanisterInitArgs) -> {
33+
disable_api : () -> (MigrationCanisterResult);
34+
enable_api : () -> (MigrationCanisterResult);
35+
list_events : (ListEventsArgs) -> (vec MigrationStatus) query;
36+
migrate_canister : (MigrateCanisterArgs) -> (ValidationResult);
37+
// The same `(source, target)` pair might be processed again after a failure
38+
// and thus we return a vector.
39+
migration_status : (MigrateCanisterArgs) -> (vec MigrationStatus) query;
40+
}

rs/migration_canister/src/migration_canister.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
};
2424

2525
#[derive(CandidType, Deserialize)]
26-
struct MigrationCanisterInitArgs {
26+
pub(crate) struct MigrationCanisterInitArgs {
2727
allowlist: Option<Vec<Principal>>,
2828
}
2929

@@ -124,7 +124,7 @@ fn migration_status(args: MigrateCanisterArgs) -> Vec<MigrationStatus> {
124124
}
125125

126126
#[derive(Clone, CandidType, Deserialize)]
127-
struct ListEventsArgs {
127+
pub(crate) struct ListEventsArgs {
128128
page_index: u64,
129129
page_size: u64,
130130
}

rs/migration_canister/src/privileged.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn check_caller() -> Result<(), MigrationCanisterError> {
2020
}
2121

2222
#[derive(Clone, Debug, CandidType, Deserialize)]
23-
enum MigrationCanisterError {
23+
pub(crate) enum MigrationCanisterError {
2424
CallerNotAuthorized,
2525
}
2626

rs/migration_canister/src/tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
//! Unit tests
2+
use crate::migration_canister::{ListEventsArgs, MigrationCanisterInitArgs};
3+
use crate::privileged::MigrationCanisterError;
4+
use crate::{MigrateCanisterArgs, MigrationStatus, ValidationError};
25
use candid::Principal;
6+
use candid_parser::utils::{CandidSource, service_equal};
37

48
use crate::{
59
Request, RequestState,
@@ -26,3 +30,17 @@ fn test() {
2630
insert_request(RequestState::Accepted { request });
2731
assert!(find_request(source, target).len() == 1);
2832
}
33+
34+
#[test]
35+
fn test_implemented_interface_matches_declared_interface_exactly() {
36+
let declared_interface = CandidSource::Text(include_str!("../migration_canister.did"));
37+
38+
// The line below generates did types and service definition.
39+
// The service definition is then obtained with `__export_service()`.
40+
candid::export_service!();
41+
let implemented_interface_str = __export_service();
42+
let implemented_interface = CandidSource::Text(&implemented_interface_str);
43+
44+
let result = service_equal(declared_interface, implemented_interface);
45+
assert!(result.is_ok(), "{:?}\n\n", result.unwrap_err());
46+
}

0 commit comments

Comments
 (0)