diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d34066f611..fd63e76ce6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -379,7 +379,7 @@ examples-contract-build: <<: *test-refs script: - rustup component add rust-src --toolchain stable - - cargo install cargo-contract --git https://github.com/paritytech/cargo-contract --version 2.0.0-alpha.3 --force + - cargo install cargo-contract --git https://github.com/paritytech/cargo-contract --version 2.0.0-alpha.4 --force - cargo contract -V - for example in examples/*/; do if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi; diff --git a/Cargo.toml b/Cargo.toml index c15cc56cd6..197cc7f8ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ members = [ "crates/ink/macro", "crates/prelude", "crates/primitives", + "crates/e2e", + "crates/e2e/macro", "crates/engine", "crates/env", "crates/storage", diff --git a/crates/e2e/Cargo.toml b/crates/e2e/Cargo.toml new file mode 100644 index 0000000000..0a9931cccd --- /dev/null +++ b/crates/e2e/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "ink_e2e" +version = "4.0.0-alpha.3" +authors = ["Parity Technologies "] +edition = "2021" + +license = "Apache-2.0" +readme = "README.md" +repository = "https://github.com/paritytech/ink" +documentation = "https://docs.rs/ink_e2e/" +homepage = "https://www.parity.io/" +description = "[ink!] End-to-end testing framework for smart contracts." +keywords = ["wasm", "parity", "webassembly", "blockchain", "edsl"] +categories = ["no-std", "embedded"] +include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"] + +[dependencies] +ink_e2e_macro = { version = "4.0.0-alpha.3", path = "./macro" } +ink_env = { version = "4.0.0-alpha.3", path = "../env" } + +contract-metadata = { version = "2.0.0-alpha.2" } +impl-serde = { version = "0.3.1", default-features = false } +jsonrpsee = { version = "0.15.1", features = ["ws-client"] } +pallet-contracts-primitives = { version = "6.0.0" } +serde = { version = "1.0.137", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.81" } +tokio = { version = "1.18.2", features = ["rt-multi-thread"] } +log = { version = "0.4" } +env_logger = { version = "0.9" } +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "full"] } +subxt = { version = "0.24.0" } + +# Substrate +sp-rpc = { version = "6.0.0" } +sp-core = { version = "6.0.0" } +sp-keyring = { version = "6.0.0" } +sp-runtime = { version = "6.0.0" } + +# TODO(#1421) `smart-bench_macro` needs to be forked. +smart-bench-macro = { git = "https://github.com/paritytech/smart-bench", branch = "aj-ink-e2e-test-mvp", package = "smart-bench-macro" } + +[features] +default = ["std"] +std = [] diff --git a/crates/e2e/LICENSE b/crates/e2e/LICENSE new file mode 120000 index 0000000000..30cff7403d --- /dev/null +++ b/crates/e2e/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/crates/e2e/README.md b/crates/e2e/README.md new file mode 120000 index 0000000000..fe84005413 --- /dev/null +++ b/crates/e2e/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml new file mode 100644 index 0000000000..9f8398b847 --- /dev/null +++ b/crates/e2e/macro/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ink_e2e_macro" +version = "4.0.0-alpha.3" +authors = ["Parity Technologies "] +edition = "2021" + +license = "Apache-2.0" +readme = "README.md" +repository = "https://github.com/paritytech/ink" +documentation = "https://docs.rs/ink_macro/" +homepage = "https://www.parity.io/" +description = "[ink!] Macro for generating end-to-end tests" +keywords = ["wasm", "parity", "webassembly", "blockchain", "edsl"] +categories = ["no-std", "embedded"] +include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] + +[lib] +name = "ink_e2e_macro" +proc-macro = true + +[dependencies] +ink_ir = { version = "4.0.0-alpha.3", path = "../../ink/ir" } +derive_more = "0.99.17" +env_logger = "0.9.1" +log = "0.4.17" +serde_json = "1.0.85" +syn = "1" +proc-macro2 = "1" +quote = "1" diff --git a/crates/ink/codegen/src/generator/ink_e2e_test.rs b/crates/e2e/macro/src/codegen.rs similarity index 83% rename from crates/ink/codegen/src/generator/ink_e2e_test.rs rename to crates/e2e/macro/src/codegen.rs index 4c49c8b744..815ba900d7 100644 --- a/crates/ink/codegen/src/generator/ink_e2e_test.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::GenerateCode; +use crate::ir; use core::cell::RefCell; use derive_more::From; use proc_macro2::TokenStream as TokenStream2; @@ -38,14 +38,14 @@ pub fn contract_path() -> Option { /// Generates code for the `[ink::e2e_test]` macro. #[derive(From)] -pub struct InkE2ETest<'a> { +pub struct InkE2ETest { /// The test function to generate code for. - test: &'a ir::InkE2ETest, + test: ir::InkE2ETest, } -impl GenerateCode for InkE2ETest<'_> { +impl InkE2ETest { /// Generates the code for `#[ink:e2e_test]`. - fn generate_code(&self) -> TokenStream2 { + pub fn generate_code(&self) -> TokenStream2 { #[cfg(clippy)] if true { return quote! {} @@ -147,42 +147,46 @@ impl GenerateCode for InkE2ETest<'_> { quote! { #( #attrs )* - #[ink::env::e2e::tokio::test] - async #vis fn #fn_name () #ret { - use ink::env::e2e::log_info; - ink::env::e2e::LOG_PREFIX.with(|log_prefix| { + #[test] + #vis fn #fn_name () #ret { + use ::ink_e2e::log_info; + ::ink_e2e::LOG_PREFIX.with(|log_prefix| { let str = format!("test: {}", stringify!(#fn_name)); *log_prefix.borrow_mut() = String::from(str); }); log_info("setting up e2e test"); - ink::env::e2e::INIT.call_once(|| { - ink::env::e2e::env_logger::init(); + ::ink_e2e::INIT.call_once(|| { + ::ink_e2e::env_logger::init(); }); log_info("extracting metadata"); // TODO(#1421) `smart-bench_macro` needs to be forked. - ink::env::e2e::smart_bench_macro::contract!(#path); + ::ink_e2e::smart_bench_macro::contract!(#path); log_info("creating new client"); - // TODO(#xxx) Make those two generic environments customizable. - let mut client = ink::env::e2e::Client::< - ink::env::e2e::PolkadotConfig, - ink::env::DefaultEnvironment - >::new(&#path, &#ws_url, &#node_log).await; - - let __ret = { - #block + let run = async { + // TODO(#xxx) Make those two generic environments customizable. + let mut client = ::ink_e2e::Client::< + ::ink_e2e::PolkadotConfig, + ink::env::DefaultEnvironment + >::new(&#path, &#ws_url, &#node_log).await; + + let __ret = { + #block + }; + __ret }; - __ret + + { + return ::ink_e2e::tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("Failed building the Runtime") + .block_on(run); + } } } } } - -impl GenerateCode for ir::InkE2ETest { - fn generate_code(&self) -> TokenStream2 { - InkE2ETest::from(self).generate_code() - } -} diff --git a/crates/ink/ir/src/ir/e2e_config.rs b/crates/e2e/macro/src/config.rs similarity index 97% rename from crates/ink/ir/src/ir/e2e_config.rs rename to crates/e2e/macro/src/config.rs index ff00a8bff0..45785fdac0 100644 --- a/crates/ink/ir/src/ir/e2e_config.rs +++ b/crates/e2e/macro/src/config.rs @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ +use ink_ir::{ ast, + format_err_spanned, utils::{ duplicate_config_err, WhitelistedAttributes, @@ -121,11 +122,6 @@ impl E2EConfig { let default_skip_build = syn::LitBool::new(false, proc_macro2::Span::call_site()); self.skip_build.clone().unwrap_or(default_skip_build) } - - /// Return set of attributes that can be passed to call builder in the codegen. - pub fn whitelisted_attributes(&self) -> &WhitelistedAttributes { - &self.whitelisted_attributes - } } /// The environmental types definition. diff --git a/crates/ink/ir/src/ir/ink_e2e_test.rs b/crates/e2e/macro/src/ir.rs similarity index 77% rename from crates/ink/ir/src/ir/ink_e2e_test.rs rename to crates/e2e/macro/src/ir.rs index ab1b512c5d..5965a0d862 100644 --- a/crates/ink/ir/src/ir/ink_e2e_test.rs +++ b/crates/e2e/macro/src/ir.rs @@ -13,9 +13,8 @@ // limitations under the License. use crate::{ - ast, + config::E2EConfig, ir, - ir::idents_lint, }; use proc_macro2::TokenStream as TokenStream2; @@ -24,32 +23,24 @@ pub struct InkE2ETest { /// The function which was annotated. pub item_fn: E2EFn, /// The specified configuration. - pub config: ir::E2EConfig, + pub config: E2EConfig, } /// The End-to-End test with all required information. +#[derive(derive_more::From)] pub struct E2EFn { /// The function which was annotated. pub item_fn: syn::ItemFn, } -impl TryFrom for E2EFn { - type Error = syn::Error; - - fn try_from(item_fn: syn::ItemFn) -> Result { - idents_lint::ensure_no_ink_identifiers(&item_fn)?; - Ok(E2EFn { item_fn }) - } -} - impl InkE2ETest { /// Returns `Ok` if the test matches all requirements for an /// ink! E2E test definition. pub fn new(attrs: TokenStream2, input: TokenStream2) -> Result { - let config = syn::parse2::(attrs)?; + let config = syn::parse2::(attrs)?; let e2e_config = ir::E2EConfig::try_from(config)?; let item_fn = syn::parse2::(input)?; - let e2e_fn = E2EFn::try_from(item_fn)?; + let e2e_fn = E2EFn::from(item_fn); Ok(Self { item_fn: e2e_fn, config: e2e_config, diff --git a/crates/e2e/macro/src/lib.rs b/crates/e2e/macro/src/lib.rs new file mode 100644 index 0000000000..7c66562e8e --- /dev/null +++ b/crates/e2e/macro/src/lib.rs @@ -0,0 +1,166 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// extern crate proc_macro; + +mod codegen; +mod config; +mod ir; + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use syn::Result; + +/// Defines an End-to-End test. +/// +/// The system requirements are: +/// +/// - A Substrate node with `pallet-contracts` running in the background. +/// You can e.g. use [`substrate-contracts-node`](https://github.com/paritytech/substrate-contracts-node) +/// and launch it with +/// `substrate-contracts-node -lerror,runtime::contracts=debug > /tmp/contracts-node.log 2>&1`. +/// - A `cargo-contract` installation that can build the contract. +/// +/// Before the test function is invoked the contract will have been build. Any errors +/// that occur during the contract build will prevent the test function from being +/// invoked. +/// +/// ## Header Arguments +/// +/// The `#[ink::e2e_test]` macro can be provided with some additional comma-separated +/// header arguments: +/// +/// - `ws_url: String` +/// +/// The `ws_url` denotes the WebSocket URL where to connect to the RPC +/// endpoint of the node. +/// +/// **Usage Example:** +/// ```no_compile +/// # // TODO(#xxx) Remove the `no_compile`. +/// type E2EResult = std::result::Result>; +/// #[ink::e2e_test(ws_url = "ws://localhost:9944")] +/// async fn e2e_contract_must_transfer_value_to_sender( +/// mut client: ::ink_e2e::Client, +/// ) -> E2EResult<()> { +/// Ok(()) +/// } +/// ``` +/// +/// **Default value:** `"ws://localhost:9944"`. +/// +/// - `node_log: String` +/// +/// The `node_log` denotes the path under which to find the node's log. +/// +/// **Usage Example:** +/// ```no_compile +/// # // TODO(#xxx) Remove the `no_compile`. +/// type E2EResult = std::result::Result>; +/// #[ink::e2e_test(ws_url = "ws://localhost:9944")] +/// async fn e2e_contract_must_transfer_value_to_sender( +/// mut client: ::ink_e2e::Client, +/// ) -> E2EResult<()> { +/// assert!(client.node_log_contains("requested value: 100000000000000\n")); +/// Ok(()) +/// } +/// ``` +/// +/// **Default value:** `"/tmp/contracts-node.log"`. +/// +/// - `skip_build: true` +/// +/// Skips building the contract as part of the test. This is handy for debugging +/// test logic, when one wants to avoid the overhead of building the contract. +/// +/// **Usage Example:** +/// ```no_compile +/// # // TODO(#xxx) Remove the `no_compile`. +/// type E2EResult = std::result::Result>; +/// #[ink::e2e_test(skip_build = true)] +/// async fn e2e_contract_must_transfer_value_to_sender( +/// mut client: ::ink_e2e::Client, +/// ) -> E2EResult<()> { +/// Ok(()) +/// } +/// ``` +/// +/// **Default value:** `false`. +/// +/// # Example +/// +/// ```no_compile +/// # // TODO(#xxx) Remove the `no_compile`. +/// #[cfg(test)] +/// mod tests { +/// use ::ink_e2e::*; +/// type E2EResult = std::result::Result>; +/// +/// #[ink::e2e_test(skip_build = true)] +/// async fn e2e_test_2(mut client: ::ink_e2e::Client) -> E2EResult<()> { +/// // given +/// let constructor = contract_transfer::constructors::new(); +/// let contract_acc_id = client.instantiate( +/// &mut ::ink_e2e::alice(), +/// constructor, +/// 1337, +/// None, +/// ) +/// .await +/// .expect("instantiating contract failed") +/// .account_id; +/// +/// // when +/// let transfer = contract_transfer::messages::give_me(120); +/// let call_res = client.call( +/// &mut ::ink_e2e::bob(), +/// contract_acc_id.clone(), +/// transfer.into(), +/// 10, +/// None, +/// ) +/// .await; +/// +/// // then +/// assert!(call_res.is_ok()); +/// Ok(()) +/// } +/// } +/// ``` +/// +/// You can also use build the `Signer` type yourself, without going through +/// the pre-defined functions: +/// +/// ```no_compile +/// let mut bob = ::ink_e2e::PairSigner::new( +/// ::ink_e2e::AccountKeyring::Bob.pair() +/// ); +/// ``` +#[proc_macro_attribute] +pub fn e2e_test(attr: TokenStream, item: TokenStream) -> TokenStream { + generate(attr.into(), item.into()).into() +} + +fn generate(attr: TokenStream2, input: TokenStream2) -> TokenStream2 { + match generate_or_err(attr, input) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error(), + } +} + +fn generate_or_err(attr: TokenStream2, input: TokenStream2) -> Result { + let test_definition = ir::InkE2ETest::new(attr, input)?; + let codegen = codegen::InkE2ETest::from(test_definition); + Ok(codegen.generate_code()) +} diff --git a/crates/env/metadata/contracts-node.scale b/crates/e2e/metadata/contracts-node.scale similarity index 100% rename from crates/env/metadata/contracts-node.scale rename to crates/e2e/metadata/contracts-node.scale diff --git a/crates/env/src/engine/e2e/client.rs b/crates/e2e/src/client.rs similarity index 99% rename from crates/env/src/engine/e2e/client.rs rename to crates/e2e/src/client.rs index 64994589d0..a1cdf5cb36 100644 --- a/crates/env/src/engine/e2e/client.rs +++ b/crates/e2e/src/client.rs @@ -33,7 +33,7 @@ use super::{ InkMessage, Signer, }; -use crate::Environment; +use ink_env::Environment; use std::path::PathBuf; use sp_runtime::traits::{ diff --git a/crates/env/src/engine/e2e/default_accounts.rs b/crates/e2e/src/default_accounts.rs similarity index 100% rename from crates/env/src/engine/e2e/default_accounts.rs rename to crates/e2e/src/default_accounts.rs diff --git a/crates/env/src/engine/e2e/mod.rs b/crates/e2e/src/lib.rs similarity index 99% rename from crates/env/src/engine/e2e/mod.rs rename to crates/e2e/src/lib.rs index 214ddc61ef..f6cba1b602 100644 --- a/crates/env/src/engine/e2e/mod.rs +++ b/crates/e2e/src/lib.rs @@ -32,11 +32,11 @@ pub use smart_bench_macro; use xts::ContractsApi; pub use env_logger; +pub use ink_e2e_macro::e2e_test; pub use sp_keyring::AccountKeyring; pub use subxt::tx::PairSigner; pub use tokio; -use log; use sp_core::sr25519; use sp_runtime::traits::{ IdentifyAccount, diff --git a/crates/env/src/engine/e2e/xts.rs b/crates/e2e/src/xts.rs similarity index 97% rename from crates/env/src/engine/e2e/xts.rs rename to crates/e2e/src/xts.rs index e6d634c23f..238f5fb91e 100644 --- a/crates/env/src/engine/e2e/xts.rs +++ b/crates/e2e/src/xts.rs @@ -21,7 +21,10 @@ use super::{ Signer, Verify, }; -use crate::Environment; +use ink_env::{ + Environment, + Gas, +}; use core::marker::PhantomData; use jsonrpsee::{ @@ -57,7 +60,7 @@ pub struct InstantiateWithCode { #[codec(compact)] value: B, #[codec(compact)] - gas_limit: crate::types::Gas, + gas_limit: Gas, storage_deposit_limit: Option, code: Vec, data: Vec, @@ -71,7 +74,7 @@ pub struct Call { #[codec(compact)] value: B, #[codec(compact)] - gas_limit: crate::types::Gas, + gas_limit: Gas, storage_deposit_limit: Option, data: Vec, } @@ -82,7 +85,7 @@ pub struct Call { struct InstantiateRequest { origin: C::AccountId, value: E::Balance, - gas_limit: crate::types::Gas, + gas_limit: Gas, storage_deposit_limit: Option, code: Code, data: Vec, @@ -109,7 +112,7 @@ struct RpcCallRequest { origin: C::AccountId, dest: C::AccountId, value: E::Balance, - gas_limit: crate::types::Gas, + gas_limit: Gas, storage_deposit_limit: Option, input_data: Vec, } @@ -196,7 +199,7 @@ where pub async fn instantiate_with_code( &self, value: E::Balance, - gas_limit: crate::types::Gas, + gas_limit: Gas, storage_deposit_limit: Option, code: Vec, data: Vec, @@ -283,7 +286,7 @@ where &self, contract: sp_runtime::MultiAddress, value: E::Balance, - gas_limit: crate::types::Gas, + gas_limit: Gas, storage_deposit_limit: Option, data: Vec, signer: &Signer, diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index 3a049c3113..b6b556ae94 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -50,26 +50,6 @@ secp256k1 = { version = "0.24", features = ["recovery", "global-context"], optio rand = { version = "0.8", default-features = false, features = ["alloc"], optional = true } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } -contract-metadata = { version = "2.0.0-alpha.2", optional = true } -impl-serde = { version = "0.3.1", default-features = false, optional = true } -jsonrpsee = { version = "0.15.1", features = ["ws-client"], optional = true } -pallet-contracts-primitives = { version = "6.0.0", optional = true } -serde = { version = "1.0.137", default-features = false, features = ["derive"], optional = true } -serde_json = { version = "1.0.81", optional = true } -tokio = { version = "1.18.2", features = ["rt-multi-thread"], optional = true } -log = { version = "0.4", optional = true } -env_logger = { version = "0.9", optional = true } -subxt = { version = "0.24.0", optional = true } - -# Substrate -sp-rpc = { version = "6.0.0", optional = true } -sp-core = { version = "6.0.0", optional = true } -sp-keyring = { version = "6.0.0", optional = true } -sp-runtime = { version = "6.0.0", optional = true } - -# TODO(#1421) `smart-bench_macro` needs to be forked. -smart-bench-macro = { git = "https://github.com/paritytech/smart-bench", branch = "cmichi-ink-e2e-test-mvp", package = "smart-bench-macro", optional = true} - [features] default = ["std"] std = [ @@ -89,22 +69,6 @@ std = [ "sha2", "sha3", "blake2", - # E2E testing environment - "contract-metadata", - "impl-serde", - "jsonrpsee", - "pallet-contracts-primitives", - "serde", - "serde_json", - "tokio", - "log", - "env_logger", - "subxt", - "sp-rpc", - "sp-core", - "sp-keyring", - "sp-runtime", - "smart-bench-macro", ] # Enable contract debug messages via `debug_print!` and `debug_println!`. ink-debug = [] diff --git a/crates/env/src/engine/mod.rs b/crates/env/src/engine/mod.rs index 811776663c..2e74d582e1 100644 --- a/crates/env/src/engine/mod.rs +++ b/crates/env/src/engine/mod.rs @@ -29,7 +29,6 @@ cfg_if! { mod on_chain; pub use self::on_chain::EnvInstance; } else if #[cfg(feature = "std")] { - pub mod e2e; pub mod off_chain; pub use self::off_chain::EnvInstance; } else { diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index f53f6fd713..052919bfd4 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -84,10 +84,6 @@ mod tests; #[doc(inline)] pub use self::engine::off_chain::test_api as test; -#[cfg(any(feature = "std", test, doc))] -#[doc(inline)] -pub use self::engine::e2e; - use self::backend::{ EnvBackend, TypedEnvBackend, @@ -107,6 +103,7 @@ pub use self::{ DefaultEnvironment, Environment, FromLittleEndian, + Gas, NoChainExtension, }, }; diff --git a/crates/ink/codegen/src/generator/mod.rs b/crates/ink/codegen/src/generator/mod.rs index eec4fab204..960a1b58dd 100644 --- a/crates/ink/codegen/src/generator/mod.rs +++ b/crates/ink/codegen/src/generator/mod.rs @@ -34,7 +34,6 @@ mod contract; mod dispatch; mod env; mod events; -mod ink_e2e_test; mod ink_test; mod item_impls; mod metadata; @@ -60,7 +59,6 @@ pub use self::{ dispatch::Dispatch, env::Env, events::Events, - ink_e2e_test::InkE2ETest, ink_test::InkTest, item_impls::ItemImpls, metadata::Metadata, diff --git a/crates/ink/codegen/src/lib.rs b/crates/ink/codegen/src/lib.rs index a61efef20e..df7d2148ff 100644 --- a/crates/ink/codegen/src/lib.rs +++ b/crates/ink/codegen/src/lib.rs @@ -60,10 +60,6 @@ impl<'a> CodeGenerator for &'a ir::InkTraitDefinition { type Generator = generator::TraitDefinition<'a>; } -impl<'a> CodeGenerator for &'a ir::InkE2ETest { - type Generator = generator::InkE2ETest<'a>; -} - impl<'a> CodeGenerator for &'a ir::InkTest { type Generator = generator::InkTest<'a>; } diff --git a/crates/ink/ir/src/ir/mod.rs b/crates/ink/ir/src/ir/mod.rs index bf255dea4f..1f09ca5f7a 100644 --- a/crates/ink/ir/src/ir/mod.rs +++ b/crates/ink/ir/src/ir/mod.rs @@ -19,9 +19,7 @@ mod blake2; mod chain_extension; mod config; mod contract; -mod e2e_config; mod idents_lint; -mod ink_e2e_test; mod ink_test; mod item; mod item_impl; @@ -69,8 +67,6 @@ pub use self::{ }, config::Config, contract::Contract, - e2e_config::E2EConfig, - ink_e2e_test::InkE2ETest, ink_test::InkTest, item::{ Event, diff --git a/crates/ink/ir/src/ir/utils.rs b/crates/ink/ir/src/ir/utils.rs index 6f4b47d256..886a92afda 100644 --- a/crates/ink/ir/src/ir/utils.rs +++ b/crates/ink/ir/src/ir/utils.rs @@ -122,7 +122,7 @@ impl WhitelistedAttributes { } /// Return an error to notify about duplicate ink! configuration arguments. -pub(crate) fn duplicate_config_err( +pub fn duplicate_config_err( first: F, second: S, name: &str, diff --git a/crates/ink/ir/src/lib.rs b/crates/ink/ir/src/lib.rs index cd43d5d451..78f5e2aeb4 100644 --- a/crates/ink/ir/src/lib.rs +++ b/crates/ink/ir/src/lib.rs @@ -30,7 +30,7 @@ #[macro_use] mod error; -mod ast; +pub mod ast; mod ir; mod literal; @@ -51,7 +51,6 @@ pub use self::{ Event, ExtensionId, ImplItem, - InkE2ETest, InkItem, InkItemTrait, InkTest, diff --git a/crates/ink/macro/src/ink_e2e_test.rs b/crates/ink/macro/src/ink_e2e_test.rs deleted file mode 100644 index 7cb58319bd..0000000000 --- a/crates/ink/macro/src/ink_e2e_test.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018-2022 Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use ink_codegen::generate_code; -use proc_macro2::TokenStream as TokenStream2; -use syn::Result; - -pub fn generate(attr: TokenStream2, input: TokenStream2) -> TokenStream2 { - match generate_or_err(attr, input) { - Ok(tokens) => tokens, - Err(err) => err.to_compile_error(), - } -} - -pub fn generate_or_err(attr: TokenStream2, input: TokenStream2) -> Result { - let test_definition = ink_ir::InkE2ETest::new(attr, input)?; - Ok(generate_code(&test_definition)) -} diff --git a/crates/ink/macro/src/lib.rs b/crates/ink/macro/src/lib.rs index b5b7e18130..3794d76111 100644 --- a/crates/ink/macro/src/lib.rs +++ b/crates/ink/macro/src/lib.rs @@ -17,7 +17,6 @@ extern crate proc_macro; mod blake2b; mod chain_extension; mod contract; -mod ink_e2e_test; mod ink_test; mod selector; mod storage; @@ -836,136 +835,6 @@ pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream { ink_test::generate(attr.into(), item.into()).into() } -/// Defines an End-to-End test. -/// -/// The system requirements are: -/// -/// - A Substrate node with `pallet-contracts` running in the background. -/// You can e.g. use [`substrate-contracts-node`](https://github.com/paritytech/substrate-contracts-node) -/// and launch it with -/// `substrate-contracts-node -lerror,runtime::contracts=debug > /tmp/contracts-node.log 2>&1`. -/// - A `cargo-contract` installation that can build the contract. -/// -/// Before the test function is invoked the contract will have been build. Any errors -/// that occur during the contract build will prevent the test function from being -/// invoked. -/// -/// ## Header Arguments -/// -/// The `#[ink::e2e_test]` macro can be provided with some additional comma-separated -/// header arguments: -/// -/// - `ws_url: String` -/// -/// The `ws_url` denotes the WebSocket URL where to connect to the RPC -/// endpoint of the node. -/// -/// **Usage Example:** -/// ```no_compile -/// # // TODO(#xxx) Remove the `no_compile`. -/// type E2EResult = std::result::Result>; -/// #[ink::e2e_test(ws_url = "ws://localhost:9944")] -/// async fn e2e_contract_must_transfer_value_to_sender( -/// mut client: ink::env::e2e::Client, -/// ) -> E2EResult<()> { -/// Ok(()) -/// } -/// ``` -/// -/// **Default value:** `"ws://localhost:9944"`. -/// -/// - `node_log: String` -/// -/// The `node_log` denotes the path under which to find the node's log. -/// -/// **Usage Example:** -/// ```no_compile -/// # // TODO(#xxx) Remove the `no_compile`. -/// type E2EResult = std::result::Result>; -/// #[ink::e2e_test(ws_url = "ws://localhost:9944")] -/// async fn e2e_contract_must_transfer_value_to_sender( -/// mut client: ink::env::e2e::Client, -/// ) -> E2EResult<()> { -/// assert!(client.node_log_contains("requested value: 100000000000000\n")); -/// Ok(()) -/// } -/// ``` -/// -/// **Default value:** `"/tmp/contracts-node.log"`. -/// -/// - `skip_build: true` -/// -/// Skips building the contract as part of the test. This is handy for debugging -/// test logic, when one wants to avoid the overhead of building the contract. -/// -/// **Usage Example:** -/// ```no_compile -/// # // TODO(#xxx) Remove the `no_compile`. -/// type E2EResult = std::result::Result>; -/// #[ink::e2e_test(skip_build = true)] -/// async fn e2e_contract_must_transfer_value_to_sender( -/// mut client: ink::env::e2e::Client, -/// ) -> E2EResult<()> { -/// Ok(()) -/// } -/// ``` -/// -/// **Default value:** `false`. -/// -/// # Example -/// -/// ```no_compile -/// # // TODO(#xxx) Remove the `no_compile`. -/// #[cfg(test)] -/// mod tests { -/// use ink::env::e2e::*; -/// type E2EResult = std::result::Result>; -/// -/// #[ink::e2e_test(skip_build = true)] -/// async fn e2e_test_2(mut client: ink::env::e2e::Client) -> E2EResult<()> { -/// // given -/// let constructor = contract_transfer::constructors::new(); -/// let contract_acc_id = client.instantiate( -/// &mut ink::env::e2e::alice(), -/// constructor, -/// 1337, -/// None, -/// ) -/// .await -/// .expect("instantiating contract failed") -/// .account_id; -/// -/// // when -/// let transfer = contract_transfer::messages::give_me(120); -/// let call_res = client.call( -/// &mut ink::env::e2e::bob(), -/// contract_acc_id.clone(), -/// transfer.into(), -/// 10, -/// None, -/// ) -/// .await; -/// -/// // then -/// assert!(call_res.is_ok()); -/// Ok(()) -/// } -/// } -/// ``` -/// -/// You can also use build the `Signer` type yourself, without going through -/// the pre-defined functions: -/// -/// ```no_compile -/// let mut bob = ink::env::e2e::PairSigner::new( -/// ink::env::e2e::AccountKeyring::Bob.pair() -/// ); -/// ``` -#[proc_macro_attribute] -pub fn e2e_test(attr: TokenStream, item: TokenStream) -> TokenStream { - ink_e2e_test::generate(attr.into(), item.into()).into() -} - /// Defines the interface for a chain extension. /// /// # Structure diff --git a/crates/ink/src/lib.rs b/crates/ink/src/lib.rs index f4302d2c8a..ab9ded0528 100644 --- a/crates/ink/src/lib.rs +++ b/crates/ink/src/lib.rs @@ -61,7 +61,6 @@ pub use ink_macro::{ blake2x256, chain_extension, contract, - e2e_test, selector_bytes, selector_id, storage_item, diff --git a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr index e14e589058..ddc49758a5 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr @@ -8,7 +8,6 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `NonCodecType` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs @@ -26,7 +25,6 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `NonCodecType` error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied @@ -44,7 +42,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonCodecType` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs diff --git a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr index 2b9e18abcb..e836a609d2 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr @@ -32,5 +32,4 @@ error[E0277]: the trait bound `&'static Contract: WrapperTypeDecode` is not sati Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `&'static Contract` diff --git a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr index c0134ae7cc..f2bd868f22 100644 --- a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr @@ -8,7 +8,6 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `NonCodecType` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs @@ -26,7 +25,6 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `NonCodecType` error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied @@ -44,7 +42,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonCodecType` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs diff --git a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr index 113b0cc191..64be580cf0 100644 --- a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr @@ -13,7 +13,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonCodecType` note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs @@ -36,7 +36,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonCodecType` note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs diff --git a/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr b/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr index ede532fa13..37f41696ea 100644 --- a/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr +++ b/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr @@ -8,7 +8,6 @@ error[E0277]: the trait bound `NonPacked: WrapperTypeDecode` is not satisfied Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `NonPacked` = note: required because of the requirements on the impl of `Packed` for `NonPacked` note: required by a bound in `consume_packed` @@ -32,7 +31,7 @@ error[E0277]: the trait bound `NonPacked: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonPacked` = note: required because of the requirements on the impl of `Packed` for `NonPacked` note: required by a bound in `consume_packed` diff --git a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr index f5ed42f793..1cc4417ded 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr @@ -8,7 +8,6 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeDecode` is not satisfied Arc Box Rc - sp_core::Bytes = note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `NonCodec` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs @@ -31,7 +30,7 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonCodec` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs diff --git a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr index 9891d5dd4f..96a3827b39 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr @@ -13,7 +13,7 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied Rc String Vec - and 2 others + parity_scale_codec::Ref<'a, T, U> = note: required because of the requirements on the impl of `Encode` for `NonCodec` note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs diff --git a/examples/contract-transfer/Cargo.toml b/examples/contract-transfer/Cargo.toml index a997af542f..2107424325 100644 --- a/examples/contract-transfer/Cargo.toml +++ b/examples/contract-transfer/Cargo.toml @@ -11,6 +11,9 @@ ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +[dev-dependencies] +ink_e2e = { path = "../../crates/e2e" } + [lib] name = "contract_transfer" path = "lib.rs" diff --git a/examples/contract-transfer/lib.rs b/examples/contract-transfer/lib.rs index 7667911d25..7e17fef194 100644 --- a/examples/contract-transfer/lib.rs +++ b/examples/contract-transfer/lib.rs @@ -183,18 +183,16 @@ pub mod give_me { #[cfg(test)] mod e2e_tests { use super::*; - use ink::env::e2e::*; - type E2EResult = std::result::Result>; - #[ink::e2e_test] + #[ink_e2e::e2e_test] async fn e2e_sending_value_to_give_me_must_fail( - mut client: ink::env::e2e::Client, + mut client: ink_e2e::Client, ) -> E2EResult<()> { // given let constructor = contract_transfer::constructors::new(); let contract_acc_id = client - .instantiate(&mut ink::env::e2e::alice(), constructor, 1000, None) + .instantiate(&mut ink_e2e::alice(), constructor, 1000, None) .await .expect("instantiate failed") .account_id; @@ -203,7 +201,7 @@ pub mod give_me { let transfer = contract_transfer::messages::give_me(120); let call_res = client .call( - &mut ink::env::e2e::bob(), + &mut ink_e2e::bob(), contract_acc_id.clone(), transfer.into(), 10, @@ -214,7 +212,7 @@ pub mod give_me { // then assert!(call_res.is_err()); let contains_err_msg = match call_res.unwrap_err() { - ink::env::e2e::Error::CallDryRun(dry_run) => { + ink_e2e::Error::CallDryRun(dry_run) => { String::from_utf8_lossy(&dry_run.debug_message) .contains("paid an unpayable message") } @@ -224,14 +222,14 @@ pub mod give_me { Ok(()) } - #[ink::e2e_test] + #[ink_e2e::e2e_test] async fn e2e_contract_must_transfer_value_to_sender( - mut client: ink::env::e2e::Client, + mut client: ink_e2e::Client, ) -> E2EResult<()> { // given let constructor = contract_transfer::constructors::new(); let contract_acc_id = client - .instantiate(&mut ink::env::e2e::bob(), constructor, 1337, None) + .instantiate(&mut ink_e2e::bob(), constructor, 1337, None) .await .expect("instantiate failed") .account_id; @@ -244,7 +242,7 @@ pub mod give_me { let transfer = contract_transfer::messages::give_me(120); let _ = client .call( - &mut ink::env::e2e::eve(), + &mut ink_e2e::eve(), contract_acc_id.clone(), transfer.into(), 0,