Skip to content

Commit 1adae31

Browse files
committed
refactor: simpler e2e runtime tests style
1 parent 1831d40 commit 1adae31

File tree

11 files changed

+195
-105
lines changed

11 files changed

+195
-105
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ tracing-subscriber = { version = "0.3.20" }
8181
trybuild = { version = "1.0.110" }
8282
which = { version = "8.0.0" }
8383
xxhash-rust = { version = "0.8" }
84-
const_env = { version = "0.1" }
84+
const_env = { version = "0.1.4" }
8585
const-hex = { version = "1.17.0", default-features = false }
8686

8787
# Substrate dependencies

crates/e2e/macro/src/config.rs

Lines changed: 149 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use darling::{
16+
FromMeta,
17+
ast::NestedMeta,
18+
};
19+
use proc_macro2::TokenStream as TokenStream2;
20+
use syn::{
21+
Meta,
22+
punctuated::Punctuated,
23+
spanned::Spanned,
24+
};
25+
1526
/// The type of the architecture that should be used to run test.
1627
#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
1728
#[darling(rename_all = "snake_case")]
@@ -129,25 +140,123 @@ impl E2EConfig {
129140
pub fn replace_test_attr(&self) -> Option<String> {
130141
self.replace_test_attr.clone()
131142
}
143+
144+
/// Parses the attribute arguments passed to `ink_e2e::test`.
145+
pub fn from_attr_tokens(attr: TokenStream2) -> Result<Self, syn::Error> {
146+
let nested_meta = NestedMeta::parse_meta_list(attr)?;
147+
Self::from_nested_meta(nested_meta)
148+
}
149+
150+
/// Builds the configuration from already parsed meta items.
151+
pub fn from_nested_meta(nested_meta: Vec<NestedMeta>) -> Result<Self, syn::Error> {
152+
let normalized = normalize_runtime_meta(nested_meta)?;
153+
Self::from_list(&normalized).map_err(syn::Error::from)
154+
}
155+
}
156+
157+
fn normalize_runtime_meta(
158+
nested_meta: Vec<NestedMeta>,
159+
) -> Result<Vec<NestedMeta>, syn::Error> {
160+
let mut args = Vec::with_capacity(nested_meta.len());
161+
let mut runtime = None;
162+
163+
for meta in nested_meta {
164+
if let Some(found) = RuntimeBackendArg::from_nested_meta(&meta)? {
165+
if runtime.replace(found).is_some() {
166+
return Err(syn::Error::new(
167+
meta.span(),
168+
"only a single `runtime` attribute is allowed",
169+
));
170+
}
171+
continue;
172+
}
173+
args.push(meta);
174+
}
175+
176+
if let Some(runtime) = runtime {
177+
args.push(runtime.into_backend_meta());
178+
}
179+
180+
Ok(args)
181+
}
182+
183+
struct RuntimeBackendArg {
184+
runtime: Option<syn::Path>,
185+
}
186+
187+
impl RuntimeBackendArg {
188+
fn from_nested_meta(meta: &NestedMeta) -> Result<Option<Self>, syn::Error> {
189+
let meta = match meta {
190+
NestedMeta::Meta(meta) if meta.path().is_ident("runtime") => meta,
191+
_ => return Ok(None),
192+
};
193+
194+
match meta {
195+
Meta::Path(_) => Ok(Some(Self { runtime: None })),
196+
Meta::List(list) => {
197+
let nested: Punctuated<NestedMeta, syn::Token![,]> =
198+
list.parse_args_with(Punctuated::parse_terminated)?;
199+
if nested.len() != 1 {
200+
return Err(syn::Error::new(
201+
list.span(),
202+
"`runtime` expects zero or one runtime type",
203+
));
204+
}
205+
match nested.first().unwrap() {
206+
NestedMeta::Meta(Meta::Path(path)) => {
207+
Ok(Some(Self {
208+
runtime: Some(path.clone()),
209+
}))
210+
}
211+
other => {
212+
Err(syn::Error::new(
213+
other.span(),
214+
"`runtime` expects a runtime type path",
215+
))
216+
}
217+
}
218+
}
219+
Meta::NameValue(name_value) => {
220+
Err(syn::Error::new(
221+
name_value.span(),
222+
"`runtime` does not support name-value pairs",
223+
))
224+
}
225+
}
226+
}
227+
228+
fn runtime(&self) -> syn::Path {
229+
self.runtime
230+
.clone()
231+
.unwrap_or_else(|| syn::parse_quote! { ::ink_runtime::DefaultRuntime })
232+
}
233+
234+
fn into_backend_meta(self) -> NestedMeta {
235+
let runtime = self.runtime();
236+
syn::parse_quote! {
237+
backend(runtime_only(sandbox = #runtime, client = ::ink_runtime::RuntimeClient))
238+
}
239+
}
132240
}
133241

134242
#[cfg(test)]
135243
mod tests {
136244
use super::*;
137-
use darling::{
138-
FromMeta,
139-
ast::NestedMeta,
140-
};
245+
use darling::ast::NestedMeta;
141246
use quote::quote;
142247

248+
fn parse_config(input: TokenStream2) -> E2EConfig {
249+
let nested = NestedMeta::parse_meta_list(input).unwrap();
250+
E2EConfig::from_nested_meta(nested).unwrap()
251+
}
252+
143253
#[test]
144254
fn config_works_backend_runtime_only() {
145255
let input = quote! {
146256
environment = crate::CustomEnvironment,
147257
backend(runtime_only(sandbox = ::ink_runtime::DefaultRuntime, client = ::ink_runtime::RuntimeClient)),
148258
};
149-
let config =
150-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
259+
let config = parse_config(input);
151260

152261
assert_eq!(
153262
config.environment(),
@@ -169,8 +278,7 @@ mod tests {
169278
let input = quote! {
170279
backend(runtime_only(default)),
171280
};
172-
let config =
173-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
281+
let config = parse_config(input);
174282

175283
assert_eq!(
176284
config.backend(),
@@ -186,8 +294,7 @@ mod tests {
186294
let input = quote! {
187295
backend(runtime_only(sandbox = ::ink_runtime::DefaultRuntime, client = ::ink_runtime::RuntimeClient)),
188296
};
189-
let config =
190-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
297+
let config = parse_config(input);
191298

192299
assert_eq!(
193300
config.backend(),
@@ -198,13 +305,40 @@ mod tests {
198305
);
199306
}
200307

308+
#[test]
309+
fn runtime_keyword_defaults() {
310+
let input = quote! { runtime };
311+
let config = parse_config(input);
312+
313+
assert_eq!(
314+
config.backend(),
315+
Backend::RuntimeOnly(RuntimeOnly {
316+
sandbox: syn::parse_quote! { ::ink_runtime::DefaultRuntime },
317+
client: syn::parse_quote! { ::ink_runtime::RuntimeClient },
318+
})
319+
);
320+
}
321+
322+
#[test]
323+
fn runtime_keyword_custom_runtime() {
324+
let input = quote! { runtime(crate::CustomRuntime) };
325+
let config = parse_config(input);
326+
327+
assert_eq!(
328+
config.backend(),
329+
Backend::RuntimeOnly(RuntimeOnly {
330+
sandbox: syn::parse_quote! { crate::CustomRuntime },
331+
client: syn::parse_quote! { ::ink_runtime::RuntimeClient },
332+
})
333+
);
334+
}
335+
201336
#[test]
202337
fn config_works_backend_node() {
203338
let input = quote! {
204339
backend(node),
205340
};
206-
let config =
207-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
341+
let config = parse_config(input);
208342

209343
assert_eq!(config.backend(), Backend::Node(Node::Auto));
210344

@@ -236,8 +370,7 @@ mod tests {
236370
let input = quote! {
237371
backend(node(auto)),
238372
};
239-
let config =
240-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
373+
let config = parse_config(input);
241374

242375
assert_eq!(config.backend(), Backend::Node(Node::Auto));
243376
}
@@ -247,8 +380,7 @@ mod tests {
247380
let input = quote! {
248381
backend(node(url = "ws://0.0.0.0:9999")),
249382
};
250-
let config =
251-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
383+
let config = parse_config(input);
252384

253385
match config.backend() {
254386
Backend::Node(node_config) => {
@@ -277,8 +409,7 @@ mod tests {
277409
let input = quote! {
278410
replace_test_attr = "#[quickcheck]"
279411
};
280-
let config =
281-
E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
412+
let config = parse_config(input);
282413

283414
assert_eq!(config.replace_test_attr(), Some("#[quickcheck]".to_owned()));
284415
}

crates/e2e/macro/src/ir.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
// limitations under the License.
1414

1515
use crate::config::E2EConfig;
16-
use darling::{
17-
FromMeta,
18-
ast::NestedMeta,
19-
};
2016
use proc_macro2::TokenStream as TokenStream2;
2117

2218
/// The End-to-End test with all required information.
@@ -38,7 +34,7 @@ impl InkE2ETest {
3834
/// Returns `Ok` if the test matches all requirements for an
3935
/// ink! E2E test definition.
4036
pub fn new(attrs: TokenStream2, input: TokenStream2) -> Result<Self, syn::Error> {
41-
let e2e_config = E2EConfig::from_list(&NestedMeta::parse_meta_list(attrs)?)?;
37+
let e2e_config = E2EConfig::from_attr_tokens(attrs)?;
4238
let item_fn = syn::parse2::<syn::ItemFn>(input)?;
4339
let e2e_fn = E2EFn::from(item_fn);
4440
Ok(Self {

crates/e2e/macro/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,15 @@ use syn::Result;
6060
/// ```
6161
/// type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
6262
///
63-
/// #[ink_runtime::test(backend(runtime_only(sandbox = ink_runtime::DefaultRuntime, client = ink_runtime::RuntimeClient)))]
64-
/// async fn runtime_call_works() -> E2EResult<()> {
63+
/// #[ink_e2e::test(runtime)]
64+
/// async fn runtime_call_works(mut client: Client) -> E2EResult<()> {
6565
/// // ...
6666
/// }
6767
/// ```
6868
///
69+
/// This defaults to `ink_runtime::DefaultRuntime` together with the built-in
70+
/// `ink_runtime::RuntimeClient`.
71+
///
6972
/// In this configuration the test will not run against a node that is running in the
7073
/// background, but against an in-process slimmed down `pallet-revive` execution
7174
/// environment.
@@ -74,6 +77,15 @@ use syn::Result;
7477
/// in our documentation for more details.
7578
/// For a full example [see here](https://github.com/use-ink/ink-examples/tree/v5.x.x/e2e-runtime-only-backend).
7679
///
80+
/// You can also provide a custom runtime:
81+
///
82+
/// ```
83+
/// #[ink_e2e::test(runtime(crate::CustomRuntime))]
84+
/// async fn runtime_call_works(mut client: Client) -> E2EResult<()> {
85+
/// // ...
86+
/// }
87+
/// ```
88+
///
7789
/// # Example
7890
///
7991
/// ```

crates/runtime/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ pub mod preset {
853853
/// with a mock network of relay chain and parachains.
854854
///
855855
/// ```no_compile
856-
/// #[ink_e2e::test(backend(runtime_only(sandbox = MockNetworkRuntime, client = ink_runtime::RuntimeClient)))]
856+
/// #[ink_e2e::test(runtime(MockNetworkRuntime))]
857857
/// async fn my_test<Client: E2EBackend>(mut client: Client) -> E2EResult<()> {
858858
/// // ...
859859
/// }

integration-tests/internal/e2e-runtime-only-backend/lib.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,8 @@ pub mod flipper {
5656
/// - flip the flipper
5757
/// - get the flipper's value
5858
/// - assert that the value is `true`
59-
#[ink_runtime::test(backend(runtime_only(
60-
sandbox = ink_runtime::DefaultRuntime,
61-
client = ink_runtime::RuntimeClient
62-
)))]
63-
async fn it_works<Client: E2EBackend>(mut client: Client) -> E2EResult<()> {
59+
#[ink_e2e::test(runtime)]
60+
async fn it_works(mut client: Client) -> E2EResult<()> {
6461
// given
6562
const INITIAL_VALUE: bool = false;
6663
let mut constructor = FlipperRef::new(INITIAL_VALUE);
@@ -98,10 +95,7 @@ pub mod flipper {
9895
/// - transfer some funds to the contract using runtime call
9996
/// - get the contract's balance again
10097
/// - assert that the contract's balance increased by the transferred amount
101-
#[ink_runtime::test(backend(runtime_only(
102-
sandbox = ink_runtime::DefaultRuntime,
103-
client = ink_runtime::RuntimeClient
104-
)))]
98+
#[ink_e2e::test(runtime)]
10599
async fn runtime_call_works() -> E2EResult<()> {
106100
// given
107101
let mut constructor = FlipperRef::new(false);
@@ -155,11 +149,8 @@ pub mod flipper {
155149
}
156150

157151
/// Just instantiate a contract using non-default runtime.
158-
#[ink_runtime::test(backend(runtime_only(
159-
sandbox = ink_runtime::DefaultRuntime,
160-
client = ink_runtime::RuntimeClient
161-
)))]
162-
async fn custom_runtime<Client: E2EBackend>(mut client: Client) -> E2EResult<()> {
152+
#[ink_e2e::test(runtime)]
153+
async fn custom_runtime(mut client: Client) -> E2EResult<()> {
163154
client
164155
.instantiate(
165156
"e2e-runtime-only-backend",

0 commit comments

Comments
 (0)