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

[ink_e2e] auto detect contracts to be built #1691

Merged
merged 16 commits into from
Mar 3, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Basic support for `dyn Trait` to allow cross-contract calls only with trait - [#1673](https://github.com/paritytech/ink/pull/1673)
- E2E: auto detect contracts to be built - [#1691](https://github.com/paritytech/ink/pull/1691)

## Version 4.0.1

Expand Down
1 change: 1 addition & 0 deletions crates/e2e/macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ proc-macro = true

[dependencies]
ink_ir = { version = "4.0.1", path = "../../ink/ir" }
cargo_metadata = "0.15.3"
contract-build = "2.0.2"
derive_more = "0.99.17"
env_logger = "0.10.0"
Expand Down
80 changes: 73 additions & 7 deletions crates/e2e/macro/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

use crate::ir;
use contract_build::ManifestPath;
use core::cell::RefCell;
use derive_more::From;
use proc_macro2::TokenStream as TokenStream2;
Expand Down Expand Up @@ -78,11 +79,20 @@ impl InkE2ETest {
.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");
let mut contracts_to_build_and_import = vec![default_main_contract_manifest_path];
contracts_to_build_and_import.append(&mut additional_contracts);
let contract_manifests = ContractManifests::from_crate_metadata();

let contracts_to_build_and_import =
if self.test.config.additional_contracts().is_empty() {
contract_manifests.all_contracts_to_build()
} else {
// backwards compatibility if `additional_contracts` specified
let mut additional_contracts: Vec<String> =
self.test.config.additional_contracts();
let mut contracts_to_build_and_import: Vec<String> =
contract_manifests.root_package.iter().cloned().collect();
contracts_to_build_and_import.append(&mut additional_contracts);
contracts_to_build_and_import
};

let mut already_built_contracts = already_built_contracts();
if already_built_contracts.is_empty() {
Expand All @@ -100,7 +110,7 @@ impl InkE2ETest {
// `additional_contracts` for this particular test contain ones
// that haven't been build before
for manifest_path in contracts_to_build_and_import {
if already_built_contracts.get("Cargo.toml").is_none() {
if already_built_contracts.get(&manifest_path).is_none() {
let dest_wasm = build_contract(&manifest_path);
let _ = already_built_contracts.insert(manifest_path, dest_wasm);
}
Expand Down Expand Up @@ -188,6 +198,63 @@ impl InkE2ETest {
}
}

#[derive(Debug)]
struct ContractManifests {
/// The manifest path of the root package where the E2E test is defined.
/// `None` if the root package is not an `ink!` contract definition.
root_package: Option<String>,
/// The manifest paths of any dependencies which are `ink!` contracts.
contract_dependencies: Vec<String>,
}

impl ContractManifests {
/// Load any manifests for packages which are detected to be `ink!` contracts. Any package
/// with the `ink-as-dependency` feature enabled is assumed to be an `ink!` contract.
fn from_crate_metadata() -> Self {
// The default manifest path is the `Cargo.toml` in the current directory.
// So in this case the package within which the E2E test is defined.
let manifest_path = ManifestPath::default();
let crate_metadata = contract_build::CrateMetadata::collect(&manifest_path)
.unwrap_or_else(|err| {
panic!(
"Error loading crate metadata for '{}': {}",
manifest_path.as_ref().display(),
err
)
});

fn maybe_contract_package(package: &cargo_metadata::Package) -> Option<String> {
package
.features
.iter()
.any(|(feat, _)| feat == "ink-as-dependency")
.then(|| package.manifest_path.to_string())
}

let root_package = maybe_contract_package(&crate_metadata.root_package);

let contract_dependencies = crate_metadata
.cargo_meta
.packages
.iter()
.filter_map(maybe_contract_package)
.collect();

Self {
root_package,
contract_dependencies,
}
}

/// Returns all the contract manifests which are to be built, including the root package
/// if it is determined to be an `ink!` contract.
fn all_contracts_to_build(&self) -> Vec<String> {
let mut all_manifests: Vec<String> = self.root_package.iter().cloned().collect();
all_manifests.append(&mut self.contract_dependencies.clone());
all_manifests
}
}

/// Builds the contract at `manifest_path`, returns the path to the contract
/// Wasm build artifact.
fn build_contract(path_to_cargo_toml: &str) -> String {
Expand All @@ -196,7 +263,6 @@ fn build_contract(path_to_cargo_toml: &str) -> String {
BuildMode,
ExecuteArgs,
Features,
ManifestPath,
Network,
OptimizationPasses,
OutputType,
Expand Down
9 changes: 8 additions & 1 deletion crates/e2e/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,14 @@ where
let wasm_path = self
.contracts
.get(&contract.replace('-', "_"))
.unwrap_or_else(|| panic!("Unknown contract {contract}"));
.unwrap_or_else(||
panic!(
"Unknown contract {contract}. Available contracts: {:?}.\n\
For a contract to be built, add it as a dependency to the `Cargo.toml`, or add \
the manifest path to `#[ink_e2e::test(additional_contracts = ..)]`",
self.contracts.keys()
)
);
let code = std::fs::read(wasm_path).unwrap_or_else(|err| {
panic!("Error loading '{}': {:?}", wasm_path.display(), err)
});
Expand Down
4 changes: 1 addition & 3 deletions integration-tests/delegator/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,7 @@ mod delegator {

type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[ink_e2e::test(
additional_contracts = "accumulator/Cargo.toml adder/Cargo.toml subber/Cargo.toml"
)]
#[ink_e2e::test]
async fn e2e_delegator(mut client: ink_e2e::Client<C, E>) -> E2EResult<()> {
// given
let accumulator_hash = client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,7 @@ mod call_builder {

type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[ink_e2e::test(
additional_contracts = "../integration-flipper/Cargo.toml ../constructors-return-value/Cargo.toml"
)]
#[ink_e2e::test]
async fn e2e_invalid_message_selector_can_be_handled(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -221,7 +219,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_invalid_message_selector_panics_on_invoke(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -258,7 +256,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_works_with_valid_selector(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -299,7 +297,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_fails_with_invalid_selector(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -340,7 +338,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_with_infallible_revert_constructor_encodes_ok(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -385,7 +383,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_can_handle_fallible_constructor_success(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -426,7 +424,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_can_handle_fallible_constructor_error(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -474,7 +472,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_with_fallible_revert_constructor_encodes_ok(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -519,7 +517,7 @@ mod call_builder {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_create_builder_with_fallible_revert_constructor_encodes_err(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ mod contract_ref {

type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_ref_can_flip_correctly(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -117,7 +117,7 @@ mod contract_ref {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_fallible_ref_can_be_instantiated(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down Expand Up @@ -147,7 +147,7 @@ mod contract_ref {
Ok(())
}

#[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")]
#[ink_e2e::test]
async fn e2e_fallible_ref_fails_to_be_instantiated(
mut client: ink_e2e::Client<C, E>,
) -> E2EResult<()> {
Expand Down