From 5c5a8c488c60b4e0387374a01e404e28fb4676a0 Mon Sep 17 00:00:00 2001 From: Eric Swanson <64809312+ericswanson-dfinity@users.noreply.github.com> Date: Mon, 17 Oct 2022 04:46:50 -0700 Subject: [PATCH] test: add basic canister http test (#2683) The original intent was to run a webserver during CI for this test, but that turned out not to be possible: - the canister http service requires the https scheme - the canister http service rejects requests to a local https server using a key/cert generated by openssl, with: "Failed to connect: error trying to connect: The certificate was not trusted." Instead, this test reads https://smartcontracts.org and looks for some terms that should always show up there Fixes https://dfinity.atlassian.net/browse/SDK-453 --- e2e/assets/canister_http/main.mo | 45 ++++++++++++++++++++++++ e2e/assets/canister_http/patch.bash | 1 + e2e/assets/canister_http/types.mo | 53 +++++++++++++++++++++++++++++ e2e/tests-dfx/canister_http.bash | 14 ++++++++ 4 files changed, 113 insertions(+) create mode 100644 e2e/assets/canister_http/main.mo create mode 100644 e2e/assets/canister_http/patch.bash create mode 100644 e2e/assets/canister_http/types.mo diff --git a/e2e/assets/canister_http/main.mo b/e2e/assets/canister_http/main.mo new file mode 100644 index 0000000000..c604359466 --- /dev/null +++ b/e2e/assets/canister_http/main.mo @@ -0,0 +1,45 @@ +import Types "types"; +import Cycles "mo:base/ExperimentalCycles"; +import Nat64 "mo:base/Nat64"; +import Text "mo:base/Text"; +import Blob "mo:base/Blob"; +import Nat "mo:base/Nat"; + +shared actor class HttpQuery() = this { + let MAX_RESPONSE_BYTES : Nat64 = 12000; + let CYCLES_TO_PAY : Nat = 2_000_000_000; + + public func get_url(host : Text, url : Text) : async Text { + let request_headers = [ + { name = "Host"; value = host }, + { name = "User-Agent"; value = "sdk-e2e-test" }, + ]; + + let request : Types.CanisterHttpRequestArgs = { + url = url; + max_response_bytes = ?MAX_RESPONSE_BYTES; + headers = request_headers; + body = null; + method = #get; + transform = ?(#function(transform)); + }; + + Cycles.add(CYCLES_TO_PAY); + let ic : Types.IC = actor ("aaaaa-aa"); + let response : Types.CanisterHttpResponsePayload = await ic.http_request(request); + let result : Text = switch (Text.decodeUtf8(Blob.fromArray(response.body))) { + case null ""; + case (?decoded) decoded; + }; + result + }; + + public query func transform(raw : Types.CanisterHttpResponsePayload) : async Types.CanisterHttpResponsePayload { + let transformed : Types.CanisterHttpResponsePayload = { + status = raw.status; + body = raw.body; + headers = []; + }; + transformed; + }; +}; \ No newline at end of file diff --git a/e2e/assets/canister_http/patch.bash b/e2e/assets/canister_http/patch.bash new file mode 100644 index 0000000000..da753f124a --- /dev/null +++ b/e2e/assets/canister_http/patch.bash @@ -0,0 +1 @@ +jq '.canisters.e2e_project_backend.main="main.mo"' dfx.json | sponge dfx.json diff --git a/e2e/assets/canister_http/types.mo b/e2e/assets/canister_http/types.mo new file mode 100644 index 0000000000..e7d74f2e35 --- /dev/null +++ b/e2e/assets/canister_http/types.mo @@ -0,0 +1,53 @@ +import HashMap "mo:base/HashMap"; +import Principal "mo:base/Principal"; + +module Types { + public type Timestamp = Nat64; + public type Rate = Text; + + public type TimeRange = { + start : Timestamp; + end : Timestamp; + }; + + public type RatesWithInterval = { + interval : Nat64; + rates : [(Timestamp, Rate)]; + }; + + public type HttpHeader = { + name : Text; + value : Text; + }; + + public type HttpMethod = { + #get; + #post; + #head; + }; + + public type TransformType = { + #function : shared CanisterHttpResponsePayload -> async CanisterHttpResponsePayload; + }; + + public type CanisterHttpRequestArgs = { + url : Text; + max_response_bytes : ?Nat64; + headers : [HttpHeader]; + body : ?[Nat8]; + method : HttpMethod; + transform : ?{ + #function : shared query CanisterHttpResponsePayload -> async CanisterHttpResponsePayload; + }; + }; + + public type CanisterHttpResponsePayload = { + status : Nat; + headers : [HttpHeader]; + body : [Nat8]; + }; + + public type IC = actor { + http_request : Types.CanisterHttpRequestArgs -> async Types.CanisterHttpResponsePayload; + }; +}; \ No newline at end of file diff --git a/e2e/tests-dfx/canister_http.bash b/e2e/tests-dfx/canister_http.bash index 121e2188e0..c2e0e19d6d 100644 --- a/e2e/tests-dfx/canister_http.bash +++ b/e2e/tests-dfx/canister_http.bash @@ -320,3 +320,17 @@ set_shared_local_network_canister_http_empty() { assert_command dfx start --background --verbose assert_match "log level: Critical" } + +@test "can query a website" { + dfx_start + + dfx_new + install_asset canister_http + + dfx deploy + + assert_command dfx canister call e2e_project_backend get_url '("smartcontracts.org:443","https://smartcontracts.org:443")' + assert_contains "Internet Computer" + assert_contains "smart contracts" + assert_contains "dapps" +}