Skip to content

Commit

Permalink
Extract e2e testing framework to its own crate (#1429)
Browse files Browse the repository at this point in the history
* Extract e2e to standalone crate

* WIP moving e2e macro code to e2e macro crate

* Fix remaining macro errors

* Fix some more errors

* Fmt

* Remove redundant import

* Fix UI tests

* Use new release of `cargo-contract` in CI

* Fix e2e refs and update smart-bench-macro branch

* Add TODO

* Replace tokio::test macro with explicit async init

* Fix integration test compilation
  • Loading branch information
ascjones authored Oct 6, 2022
1 parent a4594f0 commit 4156112
Show file tree
Hide file tree
Showing 35 changed files with 316 additions and 297 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ members = [
"crates/ink/macro",
"crates/prelude",
"crates/primitives",
"crates/e2e",
"crates/e2e/macro",
"crates/engine",
"crates/env",
"crates/storage",
Expand Down
44 changes: 44 additions & 0 deletions crates/e2e/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[package]
name = "ink_e2e"
version = "4.0.0-alpha.3"
authors = ["Parity Technologies <admin@parity.io>"]
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 = []
1 change: 1 addition & 0 deletions crates/e2e/LICENSE
1 change: 1 addition & 0 deletions crates/e2e/README.md
29 changes: 29 additions & 0 deletions crates/e2e/macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "ink_e2e_macro"
version = "4.0.0-alpha.3"
authors = ["Parity Technologies <admin@parity.io>"]
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"
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -38,14 +38,14 @@ pub fn contract_path() -> Option<PathBuf> {

/// 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! {}
Expand Down Expand Up @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
// limitations under the License.

use crate::{
ast,
config::E2EConfig,
ir,
ir::idents_lint,
};
use proc_macro2::TokenStream as TokenStream2;

Expand All @@ -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<syn::ItemFn> for E2EFn {
type Error = syn::Error;

fn try_from(item_fn: syn::ItemFn) -> Result<E2EFn, Self::Error> {
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<Self, syn::Error> {
let config = syn::parse2::<ast::AttributeArgs>(attrs)?;
let config = syn::parse2::<ink_ir::ast::AttributeArgs>(attrs)?;
let e2e_config = ir::E2EConfig::try_from(config)?;
let item_fn = syn::parse2::<syn::ItemFn>(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,
Expand Down
Loading

0 comments on commit 4156112

Please sign in to comment.