From 77e29d15d5538ade4df8b351c4519a8ffdd1f6c8 Mon Sep 17 00:00:00 2001 From: Valery Antopol Date: Mon, 18 Oct 2021 19:23:20 +0300 Subject: [PATCH] Add marine_test for mod and provide interface for build scripts (#10) --- Cargo.lock | 14 +- Cargo.toml | 8 +- crates/marine-build-rs-generator/Cargo.toml | 21 ++ crates/marine-build-rs-generator/src/lib.rs | 68 +++++ crates/marine-test-macro-impl/Cargo.toml | 2 +- .../marine-test-macro-impl/src/attributes.rs | 6 +- crates/marine-test-macro-impl/src/errors.rs | 6 + crates/marine-test-macro-impl/src/lib.rs | 2 + .../src/marine_test/config_utils.rs | 2 +- .../src/marine_test/glue_code_generator.rs | 95 +++++-- .../src/marine_test/marine_test_impl.rs | 16 +- .../src/marine_test/mod.rs | 1 + .../src/marine_test/token_stream_generator.rs | 2 +- .../methods_generator.rs | 9 +- .../methods_generator_utils.rs | 8 +- .../service_generation_utils.rs | 17 +- .../service_generator.rs | 9 +- .../generation_tests/empty_func/expanded.rs | 3 +- .../mounted_binary/expanded.rs | 5 +- .../multi-service-empty_mod/Config.toml | 6 + .../artifacts/greeting.wasm | Bin 0 -> 56806 bytes .../multi-service-empty_mod/expanded.rs | 241 ++++++++++++++++++ .../multi-service-empty_mod/marine_test.rs | 7 + .../multi-service-multiple/expanded.rs | 10 +- .../multi-service-single/expanded.rs | 3 +- .../multiple_modules/expanded.rs | 11 +- .../tests/generation_tests_runner.rs | 14 + crates/marine-test-macro/Cargo.toml | 4 +- crates/marine-test-macro/src/lib.rs | 2 +- src/lib.rs | 6 +- 30 files changed, 516 insertions(+), 82 deletions(-) create mode 100644 crates/marine-build-rs-generator/Cargo.toml create mode 100644 crates/marine-build-rs-generator/src/lib.rs create mode 100644 crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/Config.toml create mode 100755 crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/artifacts/greeting.wasm create mode 100644 crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/expanded.rs create mode 100644 crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/marine_test.rs diff --git a/Cargo.lock b/Cargo.lock index 68f7ec9..e995a55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -661,6 +661,13 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "marine-build-rs-generator" +version = "0.4.0" +dependencies = [ + "marine-test-macro-impl", +] + [[package]] name = "marine-it-generator" version = "0.5.3" @@ -801,9 +808,10 @@ dependencies = [ [[package]] name = "marine-rs-sdk-test" -version = "0.3.0" +version = "0.4.0" dependencies = [ "fluence-app-service", + "marine-build-rs-generator", "marine-test-macro", "serde", "serde_json", @@ -843,7 +851,7 @@ dependencies = [ [[package]] name = "marine-test-macro" -version = "0.3.0" +version = "0.4.0" dependencies = [ "marine-test-macro-impl", "proc-macro-error", @@ -854,7 +862,7 @@ dependencies = [ [[package]] name = "marine-test-macro-impl" -version = "0.3.0" +version = "0.4.0" dependencies = [ "darling", "fluence-app-service", diff --git a/Cargo.toml b/Cargo.toml index 4f3d6bb..e20d203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "marine-rs-sdk-test" -version = "0.3.0" # remember to update html_root_url +version = "0.4.0" # remember to update html_root_url description = "Backend SDK that allows testing modules for the Marine runtime" documentation = "https://docs.rs/marine-rs-sdk-test" repository = "https://github.com/fluencelabs/marine-rs-sdk-test" @@ -21,7 +21,8 @@ doctest = false trybuild = "1.0" [dependencies] -marine-test-macro = { path = "crates/marine-test-macro", version = "=0.3.0" } +marine-test-macro = { path = "crates/marine-test-macro", version = "=0.4.0" } +marine-build-rs-generator = { path = "crates/marine-build-rs-generator", version = "=0.4.0" } fluence-app-service = { version = "0.9.0", features = ["raw-module-api"] } serde = { version = "1.0.118", features = ["derive"] } @@ -32,4 +33,5 @@ uuid = { version = "0.8.2", features = ["v4"] } members = [ "crates/marine-test-macro", "crates/marine-test-macro-impl", - ] \ No newline at end of file + "crates/marine-build-rs-generator", + ] diff --git a/crates/marine-build-rs-generator/Cargo.toml b/crates/marine-build-rs-generator/Cargo.toml new file mode 100644 index 0000000..ef7ce21 --- /dev/null +++ b/crates/marine-build-rs-generator/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "marine-build-rs-generator" +version = "0.4.0" # remember to update html_root_url +edition = "2018" +description = "Tools for generating marine_test_env in build scripts" +documentation = "https://docs.rs/marine-build-rs-generator" +repository = "https://github.com/fluencelabs/marine-rs-sdk-test/tree/master/crates/marine-build-rs-generator" +authors = ["Fluence Labs"] +keywords = ["fluence", "marine", "sdk", "webassembly"] +categories = ["api-bindings", "wasm", "development-tools::testing"] +license = "Apache-2.0" + +[package.metadata.docs.rs] +all-features = true + +[lib] +doctest = false + +[dependencies] +marine-test-macro-impl = { path = "../marine-test-macro-impl", version = "=0.4.0" } + diff --git a/crates/marine-build-rs-generator/src/lib.rs b/crates/marine-build-rs-generator/src/lib.rs new file mode 100644 index 0000000..be1dc18 --- /dev/null +++ b/crates/marine-build-rs-generator/src/lib.rs @@ -0,0 +1,68 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * 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. + */ + +#![doc(html_root_url = "https://docs.rs/marine-build-rs-generator/0.4.0")] +#![deny( + dead_code, + nonstandard_style, + unused_imports, + unused_mut, + unused_variables, + unused_unsafe, + unreachable_patterns +)] +#![warn(rust_2018_idioms)] +#![recursion_limit = "1024"] + +use marine_test_macro_impl::generate_marine_test_env_impl; +pub use marine_test_macro_impl::ServiceDescription; + +use std::path::{PathBuf, Path}; +use std::{fs, env}; + +pub fn generate_marine_test_env( + services: impl IntoIterator, + filename: &str, + build_rs_file_path: &str, +) { + // build_rs_file_path expected to be obtained from file!() macro, which returns path with filename, + // but underlying code expects path without filename, so we are removing last part + let mut build_rs_file_path = PathBuf::from(build_rs_file_path); + let _ = build_rs_file_path.pop(); + + match generate_marine_test_env_impl(services, &build_rs_file_path) { + Ok(stream) => { + let out_dir = env::var_os("OUT_DIR") + .expect("cannot write marine_test_env: OUT_DIR env var must be set"); + let dest_path = Path::new(&out_dir).join(filename); + + match fs::write(dest_path, stream.to_string()) { + Ok(result) => result, + Err(e) => { + std::panic::panic_any(format!("cannot write marine_test_env on disk: {}", e)) + } + } + } + Err(error) => std::panic::panic_any(format!("marine_test_env generation error: {}", error)), + } +} + +#[macro_export] +macro_rules! include_test_env { + ($filename:expr) => { + include!(concat!(env!("OUT_DIR"), $filename)); + }; +} diff --git a/crates/marine-test-macro-impl/Cargo.toml b/crates/marine-test-macro-impl/Cargo.toml index 3d96b6d..154c97c 100644 --- a/crates/marine-test-macro-impl/Cargo.toml +++ b/crates/marine-test-macro-impl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "marine-test-macro-impl" -version = "0.3.0" # remember to update html_root_url +version = "0.4.0" # remember to update html_root_url edition = "2018" description = "Implementation of the `#[marine_test]` macro" documentation = "https://docs.rs/fluence/marine-test-macro-impl" diff --git a/crates/marine-test-macro-impl/src/attributes.rs b/crates/marine-test-macro-impl/src/attributes.rs index 17a83f9..3ef993d 100644 --- a/crates/marine-test-macro-impl/src/attributes.rs +++ b/crates/marine-test-macro-impl/src/attributes.rs @@ -25,13 +25,13 @@ pub(crate) enum MTestAttributes { } #[derive(Debug, Default, Clone, FromMeta)] -pub(crate) struct ServiceDescription { +pub struct ServiceDescription { /// Path to a config file of a tested service. - pub(crate) config_path: String, + pub config_path: String, /// Path to compiled modules of a service. #[darling(default)] - pub(crate) modules_dir: Option, + pub modules_dir: Option, } impl FromMeta for MTestAttributes { diff --git a/crates/marine-test-macro-impl/src/errors.rs b/crates/marine-test-macro-impl/src/errors.rs index 48402db..9c9361f 100644 --- a/crates/marine-test-macro-impl/src/errors.rs +++ b/crates/marine-test-macro-impl/src/errors.rs @@ -59,6 +59,12 @@ pub enum TestGeneratorError { #[error("No modules loaded for a service")] NoModulesInService, + + #[error("Multi-service variant must be applied to a mod or fn")] + ExpectedModOrFn, + + #[error("Single-service variant must be applied to a fn")] + ExpectedFn, } #[derive(Debug, ThisError)] diff --git a/crates/marine-test-macro-impl/src/lib.rs b/crates/marine-test-macro-impl/src/lib.rs index ae3d902..5992850 100644 --- a/crates/marine-test-macro-impl/src/lib.rs +++ b/crates/marine-test-macro-impl/src/lib.rs @@ -31,6 +31,8 @@ mod errors; mod marine_test; pub use marine_test::marine_test_impl; +pub use marine_test::generate_marine_test_env_impl; pub use errors::TestGeneratorError; +pub use attributes::ServiceDescription; pub(crate) type TResult = std::result::Result; diff --git a/crates/marine-test-macro-impl/src/marine_test/config_utils.rs b/crates/marine-test-macro-impl/src/marine_test/config_utils.rs index 7300ba7..6061335 100644 --- a/crates/marine-test-macro-impl/src/marine_test/config_utils.rs +++ b/crates/marine-test-macro-impl/src/marine_test/config_utils.rs @@ -63,7 +63,7 @@ pub(super) fn collect_modules<'config>( config: &'config TomlAppServiceConfig, modules_dir: &Path, ) -> TResult>> { - let module_paths = collect_module_paths(config, &modules_dir); + let module_paths = collect_module_paths(config, modules_dir); module_paths .into_iter() diff --git a/crates/marine-test-macro-impl/src/marine_test/glue_code_generator.rs b/crates/marine-test-macro-impl/src/marine_test/glue_code_generator.rs index efc6ca7..72c0ce8 100644 --- a/crates/marine-test-macro-impl/src/marine_test/glue_code_generator.rs +++ b/crates/marine-test-macro-impl/src/marine_test/glue_code_generator.rs @@ -20,13 +20,12 @@ use crate::marine_test::{config_utils, token_stream_generator}; use crate::TestGeneratorError; use crate::TResult; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use proc_macro2::TokenStream; use quote::quote; use quote::ToTokens; use syn::FnArg; -use std::collections::HashMap; /// Generates glue code for tests. /// F.e. for this test for the greeting service @@ -113,25 +112,30 @@ use std::collections::HashMap; /// [(2), (3)] - module_ctors* /// [(3), (4)] - original_block pub(super) fn generate_test_glue_code( - func_item: syn::ItemFn, + item: syn::Item, attrs: MTestAttributes, test_file_path: PathBuf, ) -> TResult { match attrs { MTestAttributes::MultipleServices(services) => { - generate_test_glue_code_multiple_services(func_item, services, test_file_path) + generate_test_glue_code_multiple_services(item, services, test_file_path) } MTestAttributes::SingleService(service) => { - generate_test_glue_code_single_service(func_item, service, test_file_path) + generate_test_glue_code_single_service(item, service, test_file_path) } } } fn generate_test_glue_code_single_service( - func_item: syn::ItemFn, + item: syn::Item, service: ServiceDescription, test_file_path: PathBuf, ) -> TResult { + let func_item = match item { + syn::Item::Fn(func_item) => func_item, + _ => return Err(TestGeneratorError::ExpectedFn), + }; + let config_wrapper = config_utils::load_config(&service.config_path, service.modules_dir, &test_file_path)?; let modules_dir_test_relative = test_file_path.join(&config_wrapper.resolved_modules_dir); @@ -157,6 +161,7 @@ fn generate_test_glue_code_single_service( let app_service_ctor = token_stream_generator::generate_app_service_ctor( &service.config_path, &config_wrapper.resolved_modules_dir, + &test_file_path, )?; let glue_code = quote! { #[test] @@ -185,23 +190,81 @@ fn generate_test_glue_code_single_service( } fn generate_test_glue_code_multiple_services( - func_item: syn::ItemFn, - services: HashMap, + item: syn::Item, + services: impl IntoIterator, test_file_path: PathBuf, ) -> TResult { - let service_definitions = - token_stream_generator::generate_service_definitions(services, &test_file_path)?; + let service_definitions = token_stream_generator::generate_service_definitions( + services, + &test_file_path, + &test_file_path, + )?; + let marine_test_env = quote! { + pub mod marine_test_env { + #(#service_definitions)* + } + }; + + let glue_code = match item { + syn::Item::Fn(func_item) => wrap_fn_multiservice(func_item, marine_test_env), + syn::Item::Mod(mod_item) => wrap_mod_multiservice(mod_item, marine_test_env), + _ => return Err(TestGeneratorError::ExpectedModOrFn), + }; + + Ok(glue_code) +} + +pub(super) fn generate_marine_test_env_for_build_script( + services: impl IntoIterator, + build_rs_file_path: &Path, +) -> TResult { + let current_file_path = Path::new("."); + let service_definitions = token_stream_generator::generate_service_definitions( + services, + current_file_path, + build_rs_file_path, + )?; + + let marine_test_env = quote! { + #[allow(dead_code)] + pub mod marine_test_env { + #(#service_definitions)* + } + }; + + Ok(marine_test_env) +} + +fn wrap_mod_multiservice(mod_item: syn::ItemMod, marine_test_env: TokenStream) -> TokenStream { + let mod_content = mod_item + .content + .map_or(TokenStream::default(), |(_, items)| { + quote! {#(#items)*} + }); + + let mod_ident = mod_item.ident; + let mod_vis = mod_item.vis; + let mod_attrib = mod_item.attrs; + quote! { + #(#mod_attrib)* + #mod_vis mod #mod_ident { + #marine_test_env + + #mod_content + } + } +} + +fn wrap_fn_multiservice(func_item: syn::ItemFn, marine_test_env: TokenStream) -> TokenStream { let original_block = func_item.block; let signature = func_item.sig; let name = &signature.ident; - let glue_code = quote! { + quote! { #[test] fn #name() { // definitions for services specified in attributes - pub mod marine_test_env { - #(#service_definitions)* - } + #marine_test_env fn test_func() { #original_block @@ -209,9 +272,7 @@ fn generate_test_glue_code_multiple_services( test_func() } - }; - - Ok(glue_code) + } } fn generate_module_ctors<'inputs>( diff --git a/crates/marine-test-macro-impl/src/marine_test/marine_test_impl.rs b/crates/marine-test-macro-impl/src/marine_test/marine_test_impl.rs index 832fc5a..c81aff9 100644 --- a/crates/marine-test-macro-impl/src/marine_test/marine_test_impl.rs +++ b/crates/marine-test-macro-impl/src/marine_test/marine_test_impl.rs @@ -14,14 +14,15 @@ * limitations under the License. */ -use crate::attributes::MTestAttributes; +use crate::attributes::{MTestAttributes, ServiceDescription}; use crate::TResult; use crate::marine_test::glue_code_generator::generate_test_glue_code; +use crate::marine_test::glue_code_generator::generate_marine_test_env_for_build_script; use proc_macro2::TokenStream; use darling::FromMeta; use syn::parse::Parser; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; pub fn marine_test_impl( attrs: TokenStream, @@ -34,7 +35,14 @@ pub fn marine_test_impl( let attrs: Vec = attrs.into_iter().collect(); let attrs = MTestAttributes::from_list(&attrs)?; - let func_item = syn::parse2::(input)?; + let item = syn::parse2::(input)?; - generate_test_glue_code(func_item, attrs, file_path) + generate_test_glue_code(item, attrs, file_path) +} + +pub fn generate_marine_test_env_impl( + services: impl IntoIterator, + build_rs_file_path: &Path, +) -> TResult { + generate_marine_test_env_for_build_script(services, build_rs_file_path) } diff --git a/crates/marine-test-macro-impl/src/marine_test/mod.rs b/crates/marine-test-macro-impl/src/marine_test/mod.rs index 7ca8eb2..68e3cec 100644 --- a/crates/marine-test-macro-impl/src/marine_test/mod.rs +++ b/crates/marine-test-macro-impl/src/marine_test/mod.rs @@ -22,3 +22,4 @@ mod utils; mod modules_linker; pub use marine_test_impl::marine_test_impl; +pub use marine_test_impl::generate_marine_test_env_impl; diff --git a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator.rs b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator.rs index 5396301..245b6b7 100644 --- a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator.rs +++ b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator.rs @@ -74,7 +74,7 @@ pub(super) fn generate_module_definitions<'i>( linked_modules.get(&value.name).unwrap(), module_import_generator, )?; - let module_ident = new_ident(&value.name)?; + let module_ident = new_ident(value.name)?; Ok(quote! { pub mod #module_ident { #content diff --git a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator.rs b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator.rs index c458958..3f085d5 100644 --- a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator.rs +++ b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator.rs @@ -35,9 +35,8 @@ pub(super) fn generate_module_methods<'m, 'r>( .try_fold::<_, _, TResult<_>>( Vec::with_capacity(methods_count), |mut methods, signature| { - let default_cp = generate_module_method(module_name, &signature, Default, records)?; - let user_cp = - generate_module_method(module_name, &signature, UserDefined, records)?; + let default_cp = generate_module_method(module_name, signature, Default, records)?; + let user_cp = generate_module_method(module_name, signature, UserDefined, records)?; methods.push(default_cp); methods.push(user_cp); @@ -59,8 +58,8 @@ pub fn generate_facade_methods<'m, 'r>( .try_fold::<_, _, TResult<_>>( Vec::with_capacity(methods_count), |mut methods, signature| { - let default_cp = generate_module_method_forward(&signature, Default, records)?; - let user_cp = generate_module_method_forward(&signature, UserDefined, records)?; + let default_cp = generate_module_method_forward(signature, Default, records)?; + let user_cp = generate_module_method_forward(signature, UserDefined, records)?; methods.push(default_cp); methods.push(user_cp); diff --git a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator_utils.rs b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator_utils.rs index 91def5c..03aebd4 100644 --- a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator_utils.rs +++ b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/methods_generator_utils.rs @@ -40,7 +40,7 @@ pub(super) fn generate_module_method( ) -> TResult { let arguments = generate_arguments(signature.arguments.iter(), records)?; let output_type = generate_output_type(&signature.outputs, records)?; - let mcall = generate_marine_call(module_name, cp_setting, &signature, records)?; + let mcall = generate_marine_call(module_name, cp_setting, signature, records)?; let (cp, func_name) = generate_call_parameters(&cp_setting, signature)?; @@ -60,7 +60,7 @@ pub(super) fn generate_module_method_forward( ) -> TResult { let arguments = generate_arguments(signature.arguments.iter(), records)?; let output_type = generate_output_type(&signature.outputs, records)?; - let mcall = generate_forward_call(cp_setting, &signature)?; + let mcall = generate_forward_call(cp_setting, signature)?; let (cp, func_name) = generate_call_parameters(&cp_setting, signature)?; @@ -89,8 +89,6 @@ fn generate_marine_call( let ret = generate_ret(&output_type); let function_call = quote! { - use std::ops::DerefMut; - #convert_arguments #set_result #function_call @@ -202,7 +200,7 @@ fn generate_output_type(output_types: &[IType], records: &IRecordTypes) -> TResu match output_type { None => Ok(TokenStream::new()), Some(ty) => { - let output_type = itype_to_tokens(&ty, records)?; + let output_type = itype_to_tokens(ty, records)?; let output_type = quote! { -> #output_type }; Ok(output_type) diff --git a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generation_utils.rs b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generation_utils.rs index 6d09490..ea58979 100644 --- a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generation_utils.rs +++ b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generation_utils.rs @@ -15,11 +15,16 @@ use itertools::Itertools; pub(crate) fn generate_app_service_ctor( config_path: &str, modules_dir: &Path, + test_file_path: &Path, ) -> TResult { let modules_dir = modules_dir .to_str() .ok_or_else(|| TestGeneratorError::InvalidUTF8Path(modules_dir.to_path_buf()))?; + let test_file_path = test_file_path + .to_str() + .ok_or_else(|| TestGeneratorError::InvalidUTF8Path(test_file_path.to_path_buf()))?; + let service_ctor = quote! { let tmp_dir = std::env::temp_dir(); let service_id = marine_rs_sdk_test::internal::Uuid::new_v4().to_string(); @@ -29,7 +34,7 @@ pub(crate) fn generate_app_service_ctor( std::fs::create_dir(&tmp_dir).expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new(#test_file_path).components(); let mut truncated_file_path = Vec::new(); loop { @@ -53,8 +58,6 @@ pub(crate) fn generate_app_service_ctor( module_path.push(path); } - let _ = module_path.pop(); - let config_path = module_path.join(#config_path); let modules_dir = module_path.join(#modules_dir); let modules_dir = modules_dir.to_str().expect("modules_dir contains invalid UTF8 string"); @@ -77,6 +80,7 @@ pub(super) fn generate_service_definition( service: &ProcessedService, test_file_path: &Path, linked_facade: &LinkedModule<'_>, + file_path_for_app_service: &Path, ) -> TResult { let modules_dir_test_relative = test_file_path.join(&service.config.resolved_modules_dir); let modules = @@ -102,8 +106,11 @@ pub(super) fn generate_service_definition( let facade_override_ident = new_ident("__facade_override")?; let facade_structs = generate_facade_structs(facade, &facade_override_ident)?; - let app_service_ctor = - generate_app_service_ctor(&service.config_path, &service.config.resolved_modules_dir)?; + let app_service_ctor = generate_app_service_ctor( + &service.config_path, + &service.config.resolved_modules_dir, + file_path_for_app_service, + )?; let modules_type = generate_modules_type(&modules)?; let service_definition = quote! { diff --git a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generator.rs b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generator.rs index ee2cf63..3a48a13 100644 --- a/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generator.rs +++ b/crates/marine-test-macro-impl/src/marine_test/token_stream_generator/service_generator.rs @@ -27,11 +27,11 @@ use proc_macro2::TokenStream; use itertools::{Itertools, zip}; use std::path::Path; -use std::collections::HashMap; pub(crate) fn generate_service_definitions( - services: HashMap, + services: impl IntoIterator, file_path: &Path, + file_path_for_app_service: &Path, ) -> TResult> { let services = services .into_iter() @@ -55,9 +55,10 @@ pub(crate) fn generate_service_definitions( .map(|service| -> TResult { // entry with service.name was added in link_services(...), so unwrap is safe generate_service_definition( - &service, + service, file_path, link_info.get::(&service.name).unwrap(), + file_path_for_app_service, ) }) .collect::>>() @@ -84,7 +85,7 @@ impl ProcessedService { name: String, file_path: &Path, ) -> TResult { - let config_wrapper = load_config(&service.config_path, service.modules_dir, &file_path)?; + let config_wrapper = load_config(&service.config_path, service.modules_dir, file_path)?; Ok(Self { config: config_wrapper, diff --git a/crates/marine-test-macro-impl/tests/generation_tests/empty_func/expanded.rs b/crates/marine-test-macro-impl/tests/generation_tests/empty_func/expanded.rs index e48e13b..f8dbd06 100644 --- a/crates/marine-test-macro-impl/tests/generation_tests/empty_func/expanded.rs +++ b/crates/marine-test-macro-impl/tests/generation_tests/empty_func/expanded.rs @@ -77,7 +77,7 @@ fn empty_string() { let tmp_dir = tmp_dir.to_string_lossy().to_string(); std::fs::create_dir(&tmp_dir).expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new("tests/generation_tests/empty_func").components(); let mut truncated_file_path = Vec::new(); loop { if module_path.ends_with(file_path.as_path()) { @@ -98,7 +98,6 @@ fn empty_string() { for path in truncated_file_path.iter().rev() { module_path.push(path); } - let _ = module_path.pop(); let config_path = module_path.join("Config.toml"); let modules_dir = module_path.join("artifacts"); let modules_dir = modules_dir diff --git a/crates/marine-test-macro-impl/tests/generation_tests/mounted_binary/expanded.rs b/crates/marine-test-macro-impl/tests/generation_tests/mounted_binary/expanded.rs index 4b23eb7..417daaf 100644 --- a/crates/marine-test-macro-impl/tests/generation_tests/mounted_binary/expanded.rs +++ b/crates/marine-test-macro-impl/tests/generation_tests/mounted_binary/expanded.rs @@ -71,7 +71,6 @@ fn test() { } impl ModuleInterface { pub fn download(&mut self, url: String) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([url]); let result = self .marine @@ -89,7 +88,6 @@ fn test() { url: String, cp: marine_rs_sdk_test::CallParameters ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([url]); let result = self .marine @@ -111,7 +109,7 @@ fn test() { let tmp_dir = tmp_dir.to_string_lossy().to_string(); std::fs::create_dir(&tmp_dir).expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new("tests/generation_tests/mounted_binary").components(); let mut truncated_file_path = Vec::new(); loop { if module_path.ends_with(file_path.as_path()) { @@ -132,7 +130,6 @@ fn test() { for path in truncated_file_path.iter().rev() { module_path.push(path); } - let _ = module_path.pop(); let config_path = module_path.join("Config.toml"); let modules_dir = module_path.join("artifacts"); let modules_dir = modules_dir diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/Config.toml b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/Config.toml new file mode 100644 index 0000000..2e740e3 --- /dev/null +++ b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/Config.toml @@ -0,0 +1,6 @@ +modules_dir = "artifacts/" + +[[module]] + name = "greeting" + mem_pages_count = 1 + logger_enabled = false diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/artifacts/greeting.wasm b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/artifacts/greeting.wasm new file mode 100755 index 0000000000000000000000000000000000000000..20cd5a21c399164aeb704b39ac9869f2c400597c GIT binary patch literal 56806 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 NAMoGXEjlm6{sp^<9NGW? literal 0 HcmV?d00001 diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/expanded.rs b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/expanded.rs new file mode 100644 index 0000000..c246dab --- /dev/null +++ b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/expanded.rs @@ -0,0 +1,241 @@ +#[attribute] +pub mod tests { + pub mod marine_test_env { + pub mod empty_mod { + pub mod modules { + pub mod greeting { + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct CallParameters { + pub init_peer_id: String, + pub service_id: String, + pub service_creator_peer_id: String, + pub host_id: String, + pub particle_id: String, + pub tetraplets: Vec> + } + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct MountedBinaryResult { + pub ret_code: i32, + pub error: String, + pub stdout: Vec, + pub stderr: Vec + } + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct MountedBinaryStringResult { + pub ret_code: i32, + pub error: String, + pub stdout: String, + pub stderr: String + } + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct SecurityTetraplet { + pub peer_pk: String, + pub service_id: String, + pub function_name: String, + pub json_path: String + } + pub struct ModuleInterface { + marine: std::rc::Rc< + std::cell::RefCell, + >, + } + impl ModuleInterface { + pub fn new( + marine: std::rc::Rc< + std::cell::RefCell, + > + ) -> Self { + Self { marine } + } + } + impl ModuleInterface {} + } + } + pub mod __facade_override { + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct CallParameters { + pub init_peer_id: String, + pub service_id: String, + pub service_creator_peer_id: String, + pub host_id: String, + pub particle_id: String, + pub tetraplets: Vec> + } + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct MountedBinaryResult { + pub ret_code: i32, + pub error: String, + pub stdout: Vec, + pub stderr: Vec + } + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct MountedBinaryStringResult { + pub ret_code: i32, + pub error: String, + pub stdout: String, + pub stderr: String + } + #[derive( + Clone, + Debug, + marine_rs_sdk_test :: internal :: serde :: Serialize, + marine_rs_sdk_test :: internal :: serde :: Deserialize + )] + #[serde(crate = "marine_rs_sdk_test::internal::serde")] + pub struct SecurityTetraplet { + pub peer_pk: String, + pub service_id: String, + pub function_name: String, + pub json_path: String + } + pub struct ModuleInterface { + marine: + std::rc::Rc, + >, + } + impl ModuleInterface { + pub fn new( + marine: std::rc::Rc< + std::cell::RefCell, + > + ) -> Self { + Self { marine } + } + } + impl ModuleInterface {} + } + pub use __facade_override::CallParameters; + pub use __facade_override::MountedBinaryResult; + pub use __facade_override::MountedBinaryStringResult; + pub use __facade_override::SecurityTetraplet; + pub struct __GeneratedModules { + pub greeting: modules::greeting::ModuleInterface, + } + impl __GeneratedModules { + fn new( + marine: std::rc::Rc< + std::cell::RefCell, + > + ) -> Self { + Self { + greeting: modules::greeting::ModuleInterface::new(marine.clone()), + } + } + } + pub struct ServiceInterface { + pub modules: __GeneratedModules, + __facade: __facade_override::ModuleInterface, + marine: std::rc::Rc, > + } + impl ServiceInterface { + pub fn new() -> Self { + let tmp_dir = std::env::temp_dir(); + let service_id = marine_rs_sdk_test::internal::Uuid::new_v4().to_string(); + let tmp_dir = tmp_dir.join(&service_id); + let tmp_dir = tmp_dir.to_string_lossy().to_string(); + std::fs::create_dir(&tmp_dir) + .expect("can't create a directory for service in tmp"); + let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut file_path = std::path::Path::new("tests/generation_tests/multi-service-empty_mod").components(); + let mut truncated_file_path = Vec::new(); + loop { + if module_path.ends_with(file_path.as_path()) { + break; + } + let (file_path_, remainder) = + match file_path.next_back().and_then(|p| match p { + std::path::Component::Normal(_) + | std::path::Component::CurDir + | std::path::Component::ParentDir => Some((file_path, p)), + _ => None, + }) { + Some(t) => t, + None => break, + }; + file_path = file_path_; + truncated_file_path.push(remainder); + } + for path in truncated_file_path.iter().rev() { + module_path.push(path); + } + let config_path = module_path.join("Config.toml"); + let modules_dir = module_path.join("artifacts"); + let modules_dir = modules_dir + .to_str() + .expect("modules_dir contains invalid UTF8 string"); + let mut __m_generated_marine_config = + marine_rs_sdk_test::internal::TomlAppServiceConfig::load(&config_path) + .unwrap_or_else(|e| + panic!( + "app service config located at `{:?}` can't be loaded: {}", + config_path, e + ) + ); + __m_generated_marine_config.service_base_dir = Some(tmp_dir); + __m_generated_marine_config.toml_faas_config.modules_dir = + Some(modules_dir.to_string()); + let marine = marine_rs_sdk_test::internal::AppService::new_with_empty_facade( + __m_generated_marine_config, + service_id, + std::collections::HashMap::new() + ) + .unwrap_or_else(|e| panic!("app service can't be created: {}", e)); + let marine = std::rc::Rc::new(std::cell::RefCell::new(marine)); + let modules = __GeneratedModules::new(marine.clone()); + let __facade = __facade_override::ModuleInterface::new(marine.clone()); + Self { + marine, + modules, + __facade + } + } + } + } + } + pub mod some_mod1; + pub mod some_mod2 {} + pub fn some_fn() {} + const SOME_CONST: i32 = 1; +} diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/marine_test.rs b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/marine_test.rs new file mode 100644 index 0000000..210ca77 --- /dev/null +++ b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-empty_mod/marine_test.rs @@ -0,0 +1,7 @@ +#[attribute] +pub mod tests { + pub mod some_mod1; + pub mod some_mod2 {} + pub fn some_fn() {} + const SOME_CONST: i32 = 1; +} diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-multiple/expanded.rs b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-multiple/expanded.rs index b9381a7..0e068d9 100644 --- a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-multiple/expanded.rs +++ b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-multiple/expanded.rs @@ -178,7 +178,7 @@ fn test() { std::fs::create_dir(&tmp_dir) .expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new("tests/generation_tests/multi-service-multiple").components(); let mut truncated_file_path = Vec::new(); loop { if module_path.ends_with(file_path.as_path()) { @@ -200,7 +200,6 @@ fn test() { for path in truncated_file_path.iter().rev() { module_path.push(path); } - let _ = module_path.pop(); let config_path = module_path.join("empty_func/Config.toml"); let modules_dir = module_path.join("empty_func/artifacts"); let modules_dir = modules_dir @@ -307,7 +306,6 @@ fn test() { } impl ModuleInterface { pub fn download(&mut self, url: String) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([url]); let result = self .marine @@ -325,7 +323,6 @@ fn test() { url: String, cp: marine_rs_sdk_test::CallParameters ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([url]); let result = self .marine @@ -362,7 +359,6 @@ fn test() { } impl ModuleInterface { pub fn download(&mut self, url: String) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([url]); let result = self .marine @@ -380,7 +376,6 @@ fn test() { url: String, cp: marine_rs_sdk_test::CallParameters ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([url]); let result = self .marine @@ -427,7 +422,7 @@ fn test() { std::fs::create_dir(&tmp_dir) .expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new("tests/generation_tests/multi-service-multiple").components(); let mut truncated_file_path = Vec::new(); loop { if module_path.ends_with(file_path.as_path()) { @@ -449,7 +444,6 @@ fn test() { for path in truncated_file_path.iter().rev() { module_path.push(path); } - let _ = module_path.pop(); let config_path = module_path.join("mounted_binary/Config.toml"); let modules_dir = module_path.join("mounted_binary/artifacts"); let modules_dir = modules_dir diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-single/expanded.rs b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-single/expanded.rs index 4c3c7cc..6f70cfa 100644 --- a/crates/marine-test-macro-impl/tests/generation_tests/multi-service-single/expanded.rs +++ b/crates/marine-test-macro-impl/tests/generation_tests/multi-service-single/expanded.rs @@ -178,7 +178,7 @@ fn empty_test() { std::fs::create_dir(&tmp_dir) .expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new("tests/generation_tests/multi-service-single").components(); let mut truncated_file_path = Vec::new(); loop { if module_path.ends_with(file_path.as_path()) { @@ -200,7 +200,6 @@ fn empty_test() { for path in truncated_file_path.iter().rev() { module_path.push(path); } - let _ = module_path.pop(); let config_path = module_path.join("empty_func/Config.toml"); let modules_dir = module_path.join("empty_func/artifacts"); let modules_dir = modules_dir diff --git a/crates/marine-test-macro-impl/tests/generation_tests/multiple_modules/expanded.rs b/crates/marine-test-macro-impl/tests/generation_tests/multiple_modules/expanded.rs index 7c0a886..57dea47 100644 --- a/crates/marine-test-macro-impl/tests/generation_tests/multiple_modules/expanded.rs +++ b/crates/marine-test-macro-impl/tests/generation_tests/multiple_modules/expanded.rs @@ -70,7 +70,6 @@ fn empty_string() { } impl ModuleInterface { pub fn greeting(&mut self, name: String) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([name]); let result = self .marine @@ -88,7 +87,6 @@ fn empty_string() { name: String, cp: marine_rs_sdk_test::CallParameters ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([name]); let result = self .marine @@ -120,7 +118,6 @@ fn empty_string() { } impl ModuleInterface { pub fn call_parameters(&mut self, ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([]); let result = self .marine @@ -142,7 +139,6 @@ fn empty_string() { &mut self, cp: marine_rs_sdk_test::CallParameters ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([]); let result = self .marine @@ -156,7 +152,6 @@ fn empty_string() { result } pub fn return_string(&mut self,) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([]); let result = self .marine @@ -178,7 +173,6 @@ fn empty_string() { &mut self, cp: marine_rs_sdk_test::CallParameters ) -> String { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([]); let result = self .marine @@ -192,7 +186,6 @@ fn empty_string() { result } pub fn test_array_refs(&mut self, ) -> Vec { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([]); let result = self .marine @@ -214,7 +207,6 @@ fn empty_string() { &mut self, cp: marine_rs_sdk_test::CallParameters ) -> Vec { - use std::ops::DerefMut; let arguments = marine_rs_sdk_test::internal::serde_json::json!([]); let result = self .marine @@ -236,7 +228,7 @@ fn empty_string() { let tmp_dir = tmp_dir.to_string_lossy().to_string(); std::fs::create_dir(&tmp_dir).expect("can't create a directory for service in tmp"); let mut module_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let mut file_path = std::path::Path::new(file!()).components(); + let mut file_path = std::path::Path::new("tests/generation_tests/multiple_modules").components(); let mut truncated_file_path = Vec::new(); loop { if module_path.ends_with(file_path.as_path()) { @@ -257,7 +249,6 @@ fn empty_string() { for path in truncated_file_path.iter().rev() { module_path.push(path); } - let _ = module_path.pop(); let config_path = module_path.join("Config.toml"); let modules_dir = module_path.join("artifacts"); let modules_dir = modules_dir diff --git a/crates/marine-test-macro-impl/tests/generation_tests_runner.rs b/crates/marine-test-macro-impl/tests/generation_tests_runner.rs index 53221ea..f3343b8 100644 --- a/crates/marine-test-macro-impl/tests/generation_tests_runner.rs +++ b/crates/marine-test-macro-impl/tests/generation_tests_runner.rs @@ -84,3 +84,17 @@ fn test_multiservice_multiple() { descriptions )); } + +#[test] +fn test_multiservice_empty_mod() { + let descriptions = vec![TestServiceDescription { + modules_dir: "artifacts", + config_path: "Config.toml", + name: "empty_mod", + }]; + assert!(test_marine_test_token_streams_multiservice( + "tests/generation_tests/multi-service-empty_mod/marine_test.rs", + "tests/generation_tests/multi-service-empty_mod/expanded.rs", + descriptions + )); +} diff --git a/crates/marine-test-macro/Cargo.toml b/crates/marine-test-macro/Cargo.toml index 74639a2..607b9cb 100644 --- a/crates/marine-test-macro/Cargo.toml +++ b/crates/marine-test-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "marine-test-macro" -version = "0.3.0" # remember to update html_root_url +version = "0.4.0" # remember to update html_root_url edition = "2018" description = "Definition of the `#[marine_test]` macro" documentation = "https://docs.rs/fluence/marine-test-macro" @@ -18,7 +18,7 @@ proc-macro = true doctest = false [dependencies] -marine-test-macro-impl = { path = "../marine-test-macro-impl", version = "=0.3.0" } +marine-test-macro-impl = { path = "../marine-test-macro-impl", version = "=0.4.0" } quote = "1.0.9" proc-macro2 = "1.0.24" diff --git a/crates/marine-test-macro/src/lib.rs b/crates/marine-test-macro/src/lib.rs index 4befd57..ebdf075 100644 --- a/crates/marine-test-macro/src/lib.rs +++ b/crates/marine-test-macro/src/lib.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/sdk-test-macro/0.3.0")] +#![doc(html_root_url = "https://docs.rs/marine-test-macro/0.4.0")] #![deny( dead_code, nonstandard_style, diff --git a/src/lib.rs b/src/lib.rs index 1d3b080..be328e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/sdk-test/0.3.0")] +#![doc(html_root_url = "https://docs.rs/marine-rs-sdk-test/0.4.0")] #![deny( dead_code, nonstandard_style, @@ -29,6 +29,10 @@ pub use marine_test_macro::marine_test; pub use marine_test_macro::fce_test; +pub use marine_build_rs_generator::generate_marine_test_env; +pub use marine_build_rs_generator::ServiceDescription; +pub use marine_build_rs_generator::include_test_env; + pub use fluence_app_service::CallParameters; pub use fluence_app_service::SecurityTetraplet;