-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: extract ic-mgmt call transform (#774)
# Motivation It’s literally impossible to test the internal `transform` function used within the static `create` function of the `ic-mgmt` class. However, as we need to address an issue to support WASM installation with chunks (#773), we must extend it. That’s why this PR extracts the function into a module, allowing us to provide tests for the mapping. # Notes We delegate the responsibility of calling the `transform` function to `agent-js`, as it is used internally there and as we are "just" implementing the interface exposed by agent-js. While it is not thoroughly covered at the moment in the agent, I submitted a PR [#954](dfinity/agent-js#954) today that adds at least one assertion. No particular entry in CHANGELOG. This is an internal refactoring. # Changes - Extract internal `transform` function to a utility. - JSdocs and tests. - Improve types of the function (expected interface and return type) --------- Signed-off-by: David Dal Busco <[email protected]> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
- Loading branch information
1 parent
2b06baa
commit 41871fa
Showing
4 changed files
with
123 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import type { CallConfig } from "@dfinity/agent"; | ||
import { Principal } from "@dfinity/principal"; | ||
import { mockCanisterId } from "../ic-management.mock"; | ||
import { transform } from "./transform.utils"; | ||
|
||
describe("transform", () => { | ||
it("should map the effectiveCanisterId when a valid canister_id is provided as principal in the request", () => { | ||
const methodName = "someMethod"; | ||
const args = [{ canister_id: mockCanisterId }]; | ||
const callConfig: CallConfig = {}; | ||
|
||
const result = transform(methodName, args, callConfig); | ||
|
||
expect(result).toEqual({ | ||
effectiveCanisterId: mockCanisterId, | ||
}); | ||
}); | ||
|
||
it("should map the effectiveCanisterId when a valid canister_id is provided as string in the request", () => { | ||
const methodName = "someMethod"; | ||
const args = [{ canister_id: mockCanisterId.toText() }]; | ||
const callConfig: CallConfig = {}; | ||
|
||
const result = transform(methodName, args, callConfig); | ||
|
||
expect(result).toEqual({ | ||
effectiveCanisterId: mockCanisterId, | ||
}); | ||
}); | ||
|
||
it("should return effectiveCanisterId aaaaa-aa when args is empty", () => { | ||
const methodName = "someMethod"; | ||
const args: unknown[] = []; | ||
const callConfig: CallConfig = {}; | ||
|
||
const result = transform(methodName, args, callConfig); | ||
|
||
expect(result).toEqual({ | ||
effectiveCanisterId: Principal.fromHex(""), | ||
}); | ||
}); | ||
|
||
it("should return effectiveCanisterId aaaaa-aa when canister_id is missing in the first argument", () => { | ||
const methodName = "someMethod"; | ||
const args = [{}]; | ||
const callConfig: CallConfig = {}; | ||
|
||
const result = transform(methodName, args, callConfig); | ||
|
||
expect(result).toEqual({ | ||
effectiveCanisterId: Principal.fromHex(""), | ||
}); | ||
}); | ||
|
||
it("should return effectiveCanisterId aaaaa-aa when the first argument is not an object", () => { | ||
const methodName = "someMethod"; | ||
const args = [42]; | ||
const callConfig: CallConfig = {}; | ||
|
||
const result = transform(methodName, args, callConfig); | ||
|
||
expect(result).toEqual({ | ||
effectiveCanisterId: Principal.fromHex(""), | ||
}); | ||
}); | ||
|
||
it("should throw an error if canister_id is provided in the request but is not a valid principal or representation", () => { | ||
const methodName = "someMethod"; | ||
const args = [{ canister_id: 12345 }]; | ||
const callConfig: CallConfig = {}; | ||
|
||
expect(() => transform(methodName, args, callConfig)).toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type { ActorConfig, CallConfig } from "@dfinity/agent"; | ||
import { Principal } from "@dfinity/principal"; | ||
|
||
type CallTransform = Required<ActorConfig>["callTransform"]; | ||
|
||
type QueryTransform = Required<ActorConfig>["queryTransform"]; | ||
|
||
/** | ||
* Transformer function for service creation with `callTransform` or `queryTransform`. | ||
* | ||
* This function maps the `effective_canister_id` for calls to the Management Canister (`aaaaa-aa`). | ||
* | ||
* Original source `getManagementCanister` in agent-js. | ||
* | ||
* Providing a transformer is required to determine the effective_canister_id when the request is an update call to the Management Canister (aaaaa-aa). | ||
* | ||
* @link https://internetcomputer.org/docs/current/references/ic-interface-spec/#http-effective-canister-id | ||
**/ | ||
export const transform: CallTransform | QueryTransform = ( | ||
_methodName: string, | ||
args: unknown[], | ||
_callConfig: CallConfig, | ||
): { effectiveCanisterId: Principal } => { | ||
const first = args[0] as { canister_id: string }; | ||
let effectiveCanisterId = Principal.fromHex(""); | ||
if (first && typeof first === "object" && first.canister_id) { | ||
effectiveCanisterId = Principal.from(first.canister_id as unknown); | ||
} | ||
return { effectiveCanisterId }; | ||
}; |