Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom environment in E2E tests #1645

Merged
merged 19 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Support custom environment in E2E tests - [#1645](https://github.com/paritytech/ink/pull/1645)

### Changed
- E2E: spawn a separate contracts node instance per test ‒ [#1642](https://github.com/paritytech/ink/pull/1642)

Expand Down
8 changes: 7 additions & 1 deletion crates/e2e/macro/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ impl InkE2ETest {
syn::ReturnType::Type(rarrow, ret_type) => quote! { #rarrow #ret_type },
};

let environment = self
.test
.config
.environment()
.unwrap_or_else(|| syn::parse_quote! { ::ink::env::DefaultEnvironment });

let mut additional_contracts: Vec<String> =
self.test.config.additional_contracts();
let default_main_contract_manifest_path = String::from("Cargo.toml");
Expand Down Expand Up @@ -158,7 +164,7 @@ impl InkE2ETest {

let mut client = ::ink_e2e::Client::<
::ink_e2e::PolkadotConfig,
ink::env::DefaultEnvironment
#environment
>::new(
node_proc.client(),
[ #( #contracts ),* ]
Expand Down
102 changes: 85 additions & 17 deletions crates/e2e/macro/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ pub struct E2EConfig {
whitelisted_attributes: WhitelistedAttributes,
/// Additional contracts that have to be built before executing the test.
additional_contracts: Vec<String>,
/// The [`Environment`](https://docs.rs/ink_env/4.0.0-rc/ink_env/trait.Environment.html) to use
/// during test execution.
///
/// If no `Environment` is specified, the
/// [`DefaultEnvironment`](https://docs.rs/ink_env/4.0.0-rc/ink_env/enum.DefaultEnvironment.html)
/// will be used.
environment: Option<syn::Path>,
}

impl TryFrom<ast::AttributeArgs> for E2EConfig {
Expand All @@ -36,6 +43,7 @@ impl TryFrom<ast::AttributeArgs> for E2EConfig {
fn try_from(args: ast::AttributeArgs) -> Result<Self, Self::Error> {
let mut whitelisted_attributes = WhitelistedAttributes::default();
let mut additional_contracts: Option<(syn::LitStr, ast::MetaNameValue)> = None;
let mut environment: Option<(syn::Path, ast::MetaNameValue)> = None;

for arg in args.into_iter() {
if arg.name.is_ident("keep_attr") {
Expand All @@ -46,15 +54,27 @@ impl TryFrom<ast::AttributeArgs> for E2EConfig {
ast,
arg,
"additional_contracts",
"e2e test",
"E2E test",
))
}
if let ast::PathOrLit::Lit(syn::Lit::Str(lit_str)) = &arg.value {
additional_contracts = Some((lit_str.clone(), arg))
} else {
return Err(format_err_spanned!(
arg,
"expected a bool literal for `additional_contracts` ink! e2e test configuration argument",
"expected a string literal for `additional_contracts` ink! E2E test configuration argument",
))
}
} else if arg.name.is_ident("environment") {
if let Some((_, ast)) = environment {
return Err(duplicate_config_err(ast, arg, "environment", "E2E test"))
}
if let ast::PathOrLit::Path(path) = &arg.value {
environment = Some((path.clone(), arg))
} else {
return Err(format_err_spanned!(
arg,
"expected a path for `environment` ink! E2E test configuration argument",
))
}
} else {
Expand All @@ -67,9 +87,12 @@ impl TryFrom<ast::AttributeArgs> for E2EConfig {
let additional_contracts = additional_contracts
.map(|(value, _)| value.value().split(' ').map(String::from).collect())
.unwrap_or_else(Vec::new);
let environment = environment.map(|(path, _)| path);

Ok(E2EConfig {
additional_contracts,
whitelisted_attributes,
environment,
})
}
}
Expand All @@ -80,20 +103,10 @@ impl E2EConfig {
pub fn additional_contracts(&self) -> Vec<String> {
self.additional_contracts.clone()
}
}

/// The environmental types definition.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Environment {
/// The underlying Rust type.
pub path: syn::Path,
}

impl Default for Environment {
fn default() -> Self {
Self {
path: syn::parse_quote! { ::ink_env::DefaultEnvironment },
}
/// Custom environment for the contracts, if specified.
pub fn environment(&self) -> Option<syn::Path> {
self.environment.clone()
}
}

Expand Down Expand Up @@ -128,18 +141,72 @@ mod tests {
}

#[test]
fn duplicate_args_fails() {
fn duplicate_additional_contracts_fails() {
assert_try_from(
syn::parse_quote! {
additional_contracts = "adder/Cargo.toml",
additional_contracts = "adder/Cargo.toml",
},
Err(
"encountered duplicate ink! e2e test `additional_contracts` configuration argument",
"encountered duplicate ink! E2E test `additional_contracts` configuration argument",
),
);
}

HCastano marked this conversation as resolved.
Show resolved Hide resolved
#[test]
fn duplicate_environment_fails() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also be cool to see some UI tests for the E2E macros, but that would be for a future PR

assert_try_from(
syn::parse_quote! {
environment = crate::CustomEnvironment,
environment = crate::CustomEnvironment,
},
Err(
"encountered duplicate ink! E2E test `environment` configuration argument",
),
);
}

#[test]
fn environment_as_literal_fails() {
assert_try_from(
syn::parse_quote! {
environment = "crate::CustomEnvironment",
},
Err("expected a path for `environment` ink! E2E test configuration argument"),
);
}

#[test]
fn specifying_environment_works() {
assert_try_from(
syn::parse_quote! {
environment = crate::CustomEnvironment,
},
Ok(E2EConfig {
environment: Some(syn::parse_quote! { crate::CustomEnvironment }),
..Default::default()
}),
);
}

#[test]
fn full_config_works() {
assert_try_from(
syn::parse_quote! {
additional_contracts = "adder/Cargo.toml flipper/Cargo.toml",
environment = crate::CustomEnvironment,
HCastano marked this conversation as resolved.
Show resolved Hide resolved
},
Ok(E2EConfig {
whitelisted_attributes: Default::default(),
additional_contracts: vec![
"adder/Cargo.toml".into(),
"flipper/Cargo.toml".into(),
],
environment: Some(syn::parse_quote! { crate::CustomEnvironment }),
}),
);
}

#[test]
fn keep_attr_works() {
let mut attrs = WhitelistedAttributes::default();
Expand All @@ -152,6 +219,7 @@ mod tests {
Ok(E2EConfig {
whitelisted_attributes: attrs,
additional_contracts: Vec::new(),
environment: None,
}),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ error[E0599]: the method `try_invoke` exists for struct `ink::ink_env::call::Cal
= note: the following trait bounds were not satisfied:
`NonCodecType: parity_scale_codec::Decode`
note: the following trait must be implemented
--> $CARGO/parity-scale-codec-3.3.0/src/codec.rs
--> $CARGO/parity-scale-codec-3.4.0/src/codec.rs
|
| pub trait Decode: Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder<E, Set<Call
= note: the following trait bounds were not satisfied:
`NonCodec: parity_scale_codec::Decode`
note: the following trait must be implemented
--> $CARGO/parity-scale-codec-3.3.0/src/codec.rs
--> $CARGO/parity-scale-codec-3.4.0/src/codec.rs
|
| pub trait Decode: Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^
9 changes: 9 additions & 0 deletions examples/custom-environment/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore build artifacts from the local tests sub-crate.
/target/

# Ignore backup files creates by cargo fmt.
**/*.rs.bk

# Remove Cargo.lock when creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
31 changes: 31 additions & 0 deletions examples/custom-environment/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "custom-environment"
version = "4.0.0-rc"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
publish = false

[dependencies]
ink = { path = "../../crates/ink", default-features = false }

scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true }

[dev-dependencies]
ink_e2e = { path = "../../crates/e2e" }

[lib]
HCastano marked this conversation as resolved.
Show resolved Hide resolved
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
"scale/std",
"scale-info/std",
]
ink-as-dependency = []
e2e-tests = []

# Assumes that the node used in E2E testing allows for at least 6 event topics.
permissive-node = []
28 changes: 28 additions & 0 deletions examples/custom-environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# `custom-environment` example

## What is this example about?

It demonstrates how to use custom environment, both in the contract and in the E2E tests.

## Chain-side configuration

To integrate this example into Substrate you need to adjust pallet contracts configuration in your runtime:

```rust
// In your node's runtime configuration file (runtime.rs)
parameter_types! {
pub Schedule: pallet_contracts::Schedule<Runtime> = pallet_contracts::Schedule::<Runtime> {
limits: pallet_contracts::Limits {
event_topics: 6,
..Default::default()
},
..Default::default()
};
}

impl pallet_contracts::Config for Runtime {
type Schedule = Schedule;
}
```
Loading