Remove test sdk (#67)

This commit is contained in:
Valery Antopol 2021-10-07 20:04:54 +03:00 committed by GitHub
parent 13c0f59d89
commit 2bd0c63a93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 55 additions and 4959 deletions

View File

@ -18,11 +18,10 @@ jobs:
rustup target add wasm32-wasi
rustup component add rustfmt
rustup component add clippy
cargo fmt --all -- --check --color always
(cd sdk; cargo build -v --target wasm32-wasi --all-features)
(cd sdk; cargo clippy -v --target wasm32-wasi)
(cd sdk-test; cargo build)
cargo fmt --all -- --check --color always
cargo build -v --target wasm32-wasi --all-features
cargo clippy -v --target wasm32-wasi
(cd crates/marine-macro-impl; cargo test)
TARGET=wasm32-wasi cargo test -v --all-features

1419
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,43 @@
[package]
name = "marine-rs-sdk"
version = "0.6.14" # remember to update html_root_url
description = "Fluence backend SDK for developing backend applications for the Fluence network"
documentation = "https://docs.rs/fluence"
repository = "https://github.com/fluencelabs/marine-rs-sdk"
authors = ["Fluence Labs"]
keywords = ["fluence", "marine", "sdk", "webassembly"]
categories = ["api-bindings", "wasm"]
license = "Apache-2.0"
edition = "2018"
[package.metadata.docs.rs]
all-features = true
[lib]
path = "src/lib.rs"
doctest = false
[dependencies]
marine-macro = { path = "crates/marine-macro", version = "=0.6.14" }
marine-rs-sdk-main = { path = "crates/main", version = "=0.6.14" }
marine-timestamp-macro = { path = "crates/timestamp-macro", version = "=0.6.14" }
serde = { version = "1.0.118", features = ["derive"]}
[dev-dependencies]
trybuild = "1.0"
[features]
# Print some internal logs by log_utf8_string
debug = ["marine-rs-sdk-main/debug"]
# Enable logger (this will cause log_utf8_string to appear in imports)
logger = ["marine-rs-sdk-main/logger"]
[workspace]
members = [
"crates/main",
"crates/marine-macro",
"crates/marine-macro-impl",
"crates/marine-test-macro",
"crates/marine-test-macro-impl",
"crates/timestamp-macro",
"sdk",
"sdk-test"
]
"crates/main",
"crates/marine-macro",
"crates/marine-macro-impl",
"crates/timestamp-macro",
]

View File

@ -1,4 +1,4 @@
![crates.io version](https://img.shields.io/crates/v/fluence?color=green)
[![crates.io version](https://img.shields.io/crates/v/marine-rs-sdk?color=green)](https://crates.io/crates/marine-rs-sdk)
## Marine Rust SDK

View File

@ -1,29 +0,0 @@
[package]
name = "marine-test-macro-impl"
version = "0.3.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"
repository = "https://github.com/fluencelabs/marine-rs-sdk/tree/master/crates/marine-test-macro-impl"
authors = ["Fluence Labs"]
keywords = ["fluence", "marine", "sdk", "webassembly", "procedural_macros"]
categories = ["api-bindings", "wasm", "development-tools::testing"]
license = "Apache-2.0"
[package.metadata.docs.rs]
all-features = true
[dependencies]
fluence-app-service = { version = "0.9.0", features = ["raw-module-api"] }
marine-it-parser = "0.6.5"
itertools = "0.10.1"
darling = "0.12.2"
quote = "1.0.9"
proc-macro2 = "1.0.26"
proc-macro-error = { version = "1.0.4", default-features = false }
syn = { version = '1.0.64', features = ['full'] }
thiserror = "1.0.24"
static_assertions = "1.1.0"
[dev-dependencies]
marine-macro-testing-utils = {path = "../macro-testing-utils"}

View File

@ -1,56 +0,0 @@
/*
* Copyright 2020 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.
*/
use darling::FromMeta;
use std::collections::HashMap;
/// Describes attributes of `marine_test` macro.
#[derive(Debug, Clone)]
pub(crate) enum MTestAttributes {
SingleService(ServiceDescription),
MultipleServices(HashMap<String, ServiceDescription>),
}
#[derive(Debug, Default, Clone, FromMeta)]
pub(crate) struct ServiceDescription {
/// Path to a config file of a tested service.
pub(crate) config_path: String,
/// Path to compiled modules of a service.
#[darling(default)]
pub(crate) modules_dir: Option<String>,
}
impl FromMeta for MTestAttributes {
fn from_list(items: &[syn::NestedMeta]) -> darling::Result<Self> {
let single_service = ServiceDescription::from_list(items);
let multiple_services = HashMap::<String, ServiceDescription>::from_list(items);
match (single_service, multiple_services) {
(Ok(modules), Err(_)) => Ok(Self::SingleService(modules)),
(Err(_), Ok(services)) if !services.is_empty() => Ok(Self::MultipleServices(services)),
(Err(_), Ok(_)) => Err(darling::Error::custom(
r#"Need to specify "config_path" and "modules_dir" or several named services with these fields "#,
)),
(Err(error_single), Err(error_multiple)) => Err(darling::error::Error::multiple(vec![
error_single,
error_multiple,
])),
(Ok(_), Ok(_)) => Err(darling::Error::custom(
"internal sdk error: marine_test attributes are ambiguous",
)),
}
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright 2020 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.
*/
use marine_it_parser::ITParserError;
use fluence_app_service::AppServiceError;
use darling::Error as DarlingError;
use syn::Error as SynError;
use thiserror::Error as ThisError;
use std::path::PathBuf;
#[derive(Debug, ThisError)]
pub enum TestGeneratorError {
#[error("Can't load Wasm modules into Marine: {0}")]
ITParserError(#[from] ITParserError),
#[error("{0}")]
CorruptedITSection(#[from] CorruptedITSection),
#[error("{0}")]
SynError(#[from] SynError),
#[error("Can't load Wasm modules from the provided config: {0}")]
ConfigLoadError(#[from] AppServiceError),
#[error("{0}")]
AttributesError(#[from] DarlingError),
#[error(
"neither modules_dir attribute specified nor service config contains modules_dir, please specify one of them"
)]
ModulesDirUnspecified,
#[error("a Wasm file compiled with newer version of sdk that supports multi-value")]
ManyFnOutputsUnsupported,
#[error("{0} is invalid UTF8 path")]
InvalidUTF8Path(PathBuf),
#[error(r#"a "self" argument found and it is not supported in test function"#)]
UnexpectedSelf,
#[error("Duplicate module: {0}")]
DuplicateModuleName(String),
#[error("No modules loaded for a service")]
NoModulesInService,
}
#[derive(Debug, ThisError)]
pub enum CorruptedITSection {
#[error("record with {0} is absent in embedded IT section")]
AbsentRecord(u64),
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2020 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.
*/
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
#![warn(rust_2018_idioms)]
#![recursion_limit = "1024"]
mod attributes;
mod errors;
mod marine_test;
pub use marine_test::marine_test_impl;
pub use errors::TestGeneratorError;
pub(crate) type TResult<T> = std::result::Result<T, TestGeneratorError>;

View File

@ -1,110 +0,0 @@
/*
* 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.
*/
use crate::{TResult, TestGeneratorError};
use fluence_app_service::TomlAppServiceConfig;
use marine_it_parser::module_it_interface;
use marine_it_parser::it_interface::IModuleInterface;
use std::path::{PathBuf, Path};
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct Module<'m> {
pub name: &'m str,
pub interface: IModuleInterface,
}
impl<'m> Module<'m> {
fn new(name: &'m str, interface: IModuleInterface) -> Self {
Self { name, interface }
}
}
pub(crate) struct ConfigWrapper {
pub config: TomlAppServiceConfig,
pub resolved_modules_dir: PathBuf,
}
pub(crate) fn load_config(
config_path: &str,
modules_dir: Option<String>,
file_path: &Path,
) -> TResult<ConfigWrapper> {
let config_path_buf = file_path.join(&config_path);
let marine_config = TomlAppServiceConfig::load(&config_path_buf)?;
let modules_dir = match resolve_modules_dir(&marine_config, modules_dir) {
Some(modules_dir) => modules_dir,
None => return Err(TestGeneratorError::ModulesDirUnspecified),
};
Ok(ConfigWrapper {
config: marine_config,
resolved_modules_dir: modules_dir,
})
}
/// Returns all modules the provided config consists of.
pub(super) fn collect_modules<'config>(
config: &'config TomlAppServiceConfig,
modules_dir: &Path,
) -> TResult<Vec<Module<'config>>> {
let module_paths = collect_module_paths(config, &modules_dir);
module_paths
.into_iter()
.map(|(name, path)| module_it_interface(path).map(|interface| Module::new(name, interface)))
.collect::<Result<Vec<_>, _>>()
.map_err(Into::into)
}
fn collect_module_paths<'config>(
config: &'config TomlAppServiceConfig,
modules_dir: &Path,
) -> Vec<(&'config str, PathBuf)> {
config
.toml_faas_config
.module
.iter()
.map(|m| {
let module_file_name = m.file_name.as_ref().unwrap_or(&m.name);
let module_file_name = PathBuf::from(module_file_name);
// TODO: is it correct to always have .wasm extension?
let module_path = modules_dir.join(module_file_name).with_extension("wasm");
(m.name.as_str(), module_path)
})
.collect::<Vec<_>>()
}
/// Tries to determine a dir with compiled Wasm modules according to the following rules:
/// - if the modules_dir attribute is specified (by user) it will be chosen,
/// - otherwise if modules_dir is specified in AppService config it will be chosen,
/// - otherwise None will be returned.
pub(super) fn resolve_modules_dir(
config: &TomlAppServiceConfig,
modules_dir: Option<String>,
) -> Option<PathBuf> {
match modules_dir {
Some(modules_dir) => Some(PathBuf::from(modules_dir)),
None => config
.toml_faas_config
.modules_dir
.as_ref()
.map(PathBuf::from),
}
}

View File

@ -1,245 +0,0 @@
/*
* 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.
*/
use crate::attributes::{MTestAttributes, ServiceDescription};
use crate::marine_test;
use crate::marine_test::{config_utils, token_stream_generator};
use crate::TestGeneratorError;
use crate::TResult;
use std::path::PathBuf;
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
///```ignore
/// #[marine_test(
/// config_path = "/path/to/service/config/Config.toml",
/// modules_dir = "/path/to/modules/dir"
/// )]
/// fn test() {
/// let result = greeting.greeting("John".to_string());
/// assert_eq(result.as_str(), "Hi, John!");
/// }
/// ```
///
/// the following glue code would be generated:
///```ignore
/// // (0)
/// pub mod __m_generated_greeting {
/// struct MGeneratedStructgreeting {
/// marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>>,
/// }
///
/// impl MGeneratedStructgreeting {
/// pub fn new(marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>>) -> Self {
/// Self { marine }
/// }
///
/// 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
/// .as_ref
/// .borrow_mut()
/// .call_with_module_name("greeting", "greeting", arguments, <_>::default())
/// .expect("call to Marine failed");
/// let result: String = marine_rs_sdk_test::internal::serde_json::from_value(result)
/// .expect("the default deserializer shouldn't fail");
/// result
/// }
/// }
///}
/// // (1)
/// 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 __m_generated_marine_config = marine_rs_sdk_test::internal::TomlAppServiceConfig::load("/path/to/greeting/Config.toml".to_string())
/// .unwrap_or_else(|e| {
/// panic!(
/// "app service located at `{}` config can't be loaded: {}",
/// "/path/to/greeting/Config.toml", e
/// )
/// });
///
/// __m_generated_marine_config.service_base_dir = Some("/path/to/tmp".to_string());
///
/// let marine = marine_rs_sdk_test::internal::AppService::new_with_empty_facade(
/// __m_generated_marine_config,
/// "3640e972-92e3-47cb-b95f-4e3c5bcf0f14",
/// 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));
///
/// // (2)
///
/// let mut greeting = __m_generated_greeting::MGeneratedStructgreeting::new(marine);
///
/// // (3)
///
/// let result = greeting.greeting("John".to_string());
/// assert_eq(result.as_str(), "Hi, John!");
///
/// // (4)
///```
///
/// Example code above corresponds to the macro definition in the following way:
/// [(0), (1)] - module_definitions*
/// [(1), (2)] - app_service_ctor
/// [(2), (3)] - module_ctors*
/// [(3), (4)] - original_block
pub(super) fn generate_test_glue_code(
func_item: syn::ItemFn,
attrs: MTestAttributes,
test_file_path: PathBuf,
) -> TResult<TokenStream> {
match attrs {
MTestAttributes::MultipleServices(services) => {
generate_test_glue_code_multiple_services(func_item, services, test_file_path)
}
MTestAttributes::SingleService(service) => {
generate_test_glue_code_single_service(func_item, service, test_file_path)
}
}
}
fn generate_test_glue_code_single_service(
func_item: syn::ItemFn,
service: ServiceDescription,
test_file_path: PathBuf,
) -> TResult<TokenStream> {
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);
let module_interfaces =
config_utils::collect_modules(&config_wrapper.config, &modules_dir_test_relative)?;
let linked_modules = marine_test::modules_linker::link_modules(
module_interfaces
.iter()
.map(|module| (module.name, &module.interface)),
)?;
let module_definitions = token_stream_generator::generate_module_definitions(
module_interfaces.iter(),
&linked_modules,
)?;
let original_block = func_item.block;
let signature = func_item.sig;
let name = &signature.ident;
let inputs = &signature.inputs;
let arg_names = generate_arg_names(inputs.iter())?;
let module_ctors = generate_module_ctors(inputs.iter())?;
let app_service_ctor = token_stream_generator::generate_app_service_ctor(
&service.config_path,
&config_wrapper.resolved_modules_dir,
)?;
let glue_code = quote! {
#[test]
fn #name() {
// definitions for wasm modules specified in config
pub mod marine_test_env {
#(#module_definitions)*
}
// AppService constructor and instantiation to implicit `marine` variable
#app_service_ctor
// constructors of all modules of the tested service
#(#module_ctors)*
fn test_func(#inputs) {
#(let mut #arg_names = #arg_names;)*
// original test function as is
#original_block
}
test_func(#(#arg_names,)*)
}
};
Ok(glue_code)
}
fn generate_test_glue_code_multiple_services(
func_item: syn::ItemFn,
services: HashMap<String, ServiceDescription>,
test_file_path: PathBuf,
) -> TResult<TokenStream> {
let service_definitions =
token_stream_generator::generate_service_definitions(services, &test_file_path)?;
let original_block = func_item.block;
let signature = func_item.sig;
let name = &signature.ident;
let glue_code = quote! {
#[test]
fn #name() {
// definitions for services specified in attributes
pub mod marine_test_env {
#(#service_definitions)*
}
fn test_func() {
#original_block
}
test_func()
}
};
Ok(glue_code)
}
fn generate_module_ctors<'inputs>(
inputs: impl Iterator<Item = &'inputs FnArg>,
) -> TResult<Vec<TokenStream>> {
inputs
.map(|x| -> TResult<_> {
match x {
FnArg::Receiver(_) => Err(TestGeneratorError::UnexpectedSelf),
FnArg::Typed(x) => {
let pat = &x.pat;
let ty = &x.ty;
Ok(quote! {let mut #pat = #ty::new(marine.clone());})
}
}
})
.collect::<TResult<_>>()
}
fn generate_arg_names<'inputs>(
inputs: impl Iterator<Item = &'inputs FnArg>,
) -> TResult<Vec<TokenStream>> {
inputs
.map(|x| -> TResult<_> {
match x {
FnArg::Receiver(_) => Err(TestGeneratorError::UnexpectedSelf),
FnArg::Typed(x) => Ok(x.pat.to_token_stream()),
}
})
.collect::<TResult<_>>()
}

View File

@ -1,40 +0,0 @@
/*
* 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.
*/
use crate::attributes::MTestAttributes;
use crate::TResult;
use crate::marine_test::glue_code_generator::generate_test_glue_code;
use proc_macro2::TokenStream;
use darling::FromMeta;
use syn::parse::Parser;
use std::path::PathBuf;
pub fn marine_test_impl(
attrs: TokenStream,
input: TokenStream,
file_path: PathBuf,
) -> TResult<TokenStream> {
// from https://github.com/dtolnay/syn/issues/788
let parser = syn::punctuated::Punctuated::<syn::NestedMeta, syn::Token![,]>::parse_terminated;
let attrs = parser.parse2(attrs)?;
let attrs: Vec<syn::NestedMeta> = attrs.into_iter().collect();
let attrs = MTestAttributes::from_list(&attrs)?;
let func_item = syn::parse2::<syn::ItemFn>(input)?;
generate_test_glue_code(func_item, attrs, file_path)
}

View File

@ -1,24 +0,0 @@
/*
* 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.
*/
mod config_utils;
mod marine_test_impl;
mod glue_code_generator;
mod token_stream_generator;
mod utils;
mod modules_linker;
pub use marine_test_impl::marine_test_impl;

View File

@ -1,195 +0,0 @@
/*
* 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.
*/
use crate::{TResult, TestGeneratorError};
use marine_it_parser::it_interface::{IRecordTypes, IModuleInterface};
use marine_it_parser::it_interface::it::{IType, IRecordType};
use itertools::zip;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hasher;
use std::rc::Rc;
use static_assertions::const_assert;
pub(super) fn link_modules<'modules>(
modules: impl ExactSizeIterator<Item = (&'modules str, &'modules IModuleInterface)>,
) -> TResult<LinkedModules<'modules>> {
let mut all_record_types = HashMap::<IRecordTypeClosed<'_>, &str>::new();
let mut linked_modules = HashMap::<&str, LinkedModule<'_>>::new();
for (name, interface) in modules {
let mut linking_module = LinkedModule::default();
for record_type in interface.record_types.values() {
let record_type_ex =
IRecordTypeClosed::new(record_type.clone(), &interface.record_types);
let entry = match all_record_types.get(&record_type_ex) {
Some(owner_module) => RecordEntry::Use(UseDescription {
from: owner_module,
name: &record_type.name,
}),
None => {
all_record_types.insert(record_type_ex.clone(), name);
RecordEntry::Declare(record_type_ex)
}
};
linking_module.records.push(entry);
}
if linked_modules.insert(name, linking_module).is_some() {
return Err(TestGeneratorError::DuplicateModuleName(name.to_string()));
}
}
Ok(linked_modules)
}
struct ITypeClosed<'r> {
ty: &'r IType,
records: &'r IRecordTypes,
}
impl<'r> ITypeClosed<'r> {
fn new(ty: &'r IType, records: &'r IRecordTypes) -> Self {
Self { ty, records }
}
}
impl PartialEq for ITypeClosed<'_> {
fn eq(&self, other: &Self) -> bool {
use IType::*;
// check if new variants require special handling in the match below
#[allow(unused)]
const LAST_VERIFIED_ITYPE_SIZE: usize = 17;
const_assert!(IType::VARIANT_COUNT == LAST_VERIFIED_ITYPE_SIZE);
match (&self.ty, &other.ty) {
(Array(self_ty), Array(other_ty)) => {
ITypeClosed::new(self_ty, self.records) == ITypeClosed::new(other_ty, other.records)
}
(Record(self_record), Record(other_record)) => {
let self_record = self.records.get(self_record);
let other_record = other.records.get(other_record);
// ID from Record(ID) potentially may not be in .records, if it happens comparision is always FALSE
match (self_record, other_record) {
(None, _) => false,
(_, None) => false,
(Some(self_record), Some(other_record)) => {
IRecordTypeClosed::new(self_record.clone(), self.records)
== IRecordTypeClosed::new(other_record.clone(), other.records)
}
}
}
(lhs, rhs) if lhs == rhs => true,
_ => false,
}
}
}
#[derive(Clone)]
pub struct IRecordTypeClosed<'r> {
pub record_type: Rc<IRecordType>,
pub records: &'r IRecordTypes,
}
impl<'r> IRecordTypeClosed<'r> {
fn new(record_type: Rc<IRecordType>, records: &'r IRecordTypes) -> Self {
Self {
record_type,
records,
}
}
}
impl PartialEq for IRecordTypeClosed<'_> {
fn eq(&self, other: &Self) -> bool {
let names_are_equal = self.record_type.name == other.record_type.name;
names_are_equal && fields_are_equal(self, other)
}
}
fn fields_are_equal(lhs: &IRecordTypeClosed<'_>, rhs: &IRecordTypeClosed<'_>) -> bool {
let same_fields_count = lhs.record_type.fields.len() == rhs.record_type.fields.len();
same_fields_count
&& zip(lhs.record_type.fields.iter(), rhs.record_type.fields.iter()).all(
|(lhs_field, rhs_field)| -> bool {
lhs_field.name == rhs_field.name
&& ITypeClosed::new(&lhs_field.ty, lhs.records)
== ITypeClosed::new(&rhs_field.ty, rhs.records)
},
)
}
impl PartialOrd for IRecordTypeClosed<'_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for IRecordTypeClosed<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.record_type.name.cmp(&other.record_type.name)
}
}
impl Eq for IRecordTypeClosed<'_> {}
impl std::hash::Hash for IRecordTypeClosed<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.record_type.name.hash(state);
}
}
pub type LinkedModules<'r> = HashMap<&'r str, LinkedModule<'r>>;
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct UseDescription<'r> {
pub from: &'r str,
pub name: &'r str,
}
#[derive(PartialEq, Eq)]
pub enum RecordEntry<'r> {
Use(UseDescription<'r>),
Declare(IRecordTypeClosed<'r>),
}
impl PartialOrd for RecordEntry<'_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RecordEntry<'_> {
fn cmp(&self, other: &Self) -> Ordering {
use RecordEntry::*;
match (self, other) {
(Use(_), Declare(_)) => Ordering::Less,
(Declare(_), Use(_)) => Ordering::Greater,
(Use(lhs), Use(rhs)) => lhs.cmp(rhs),
(Declare(lhs), Declare(rhs)) => lhs.record_type.name.cmp(&rhs.record_type.name),
}
}
}
#[derive(Default)]
pub struct LinkedModule<'all> {
pub records: Vec<RecordEntry<'all>>,
}

View File

@ -1,125 +0,0 @@
/*
* 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.
*/
mod methods_generator;
mod methods_generator_utils;
mod record_type_generator;
mod service_generator;
mod service_generation_utils;
use crate::marine_test::config_utils::Module;
use crate::marine_test::modules_linker::{LinkedModule, LinkedModules, UseDescription};
use crate::marine_test::utils;
use crate::TResult;
pub(super) use service_generator::generate_service_definitions;
pub(super) use service_generation_utils::generate_app_service_ctor;
use proc_macro2::TokenStream;
use quote::quote;
use crate::marine_test::utils::new_ident;
/// Generates definitions of modules and records of this modules.
/// F.e. for the greeting service the following definitions would be generated:
///```ignore
/// pub mod __m_generated_greeting {
/// struct MGeneratedStructgreeting {
/// marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>>,
/// }
///
/// impl MGeneratedStructgreeting {
/// pub fn new(marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>>) -> Self {
/// Self { marine }
/// }
///
/// 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
/// .as_ref
/// .borrow_mut()
/// .call_with_module_name("greeting", "greeting", arguments, <_>::default())
/// .expect("call to Marine failed");
/// let result: String = marine_rs_sdk_test::internal::serde_json::from_value(result)
/// .expect("the default deserializer shouldn't fail");
/// result
/// }
/// }
/// }
///```
pub(super) fn generate_module_definitions<'i>(
modules: impl ExactSizeIterator<Item = &'i Module<'i>>,
linked_modules: &'i LinkedModules<'_>,
) -> TResult<Vec<TokenStream>> {
modules
.into_iter()
.map(|value| {
// linked_modules are built from modules, so unwrap is safe
let content = generate_module_definition(
value,
linked_modules.get(&value.name).unwrap(),
module_import_generator,
)?;
let module_ident = new_ident(&value.name)?;
Ok(quote! {
pub mod #module_ident {
#content
}
})
})
.collect::<TResult<Vec<_>>>()
}
fn generate_module_definition(
module: &Module<'_>,
linked_module: &'_ LinkedModule<'_>,
import_generator: fn(info: &UseDescription<'_>) -> TResult<TokenStream>,
) -> TResult<TokenStream> {
let struct_ident = utils::new_ident("ModuleInterface")?;
let module_records = record_type_generator::generate_records(linked_module, import_generator)?;
let module_functions = methods_generator::generate_module_methods(
module.name,
module.interface.function_signatures.iter(),
&module.interface.record_types,
)?;
let module_definition = quote! {
#(#module_records)*
pub struct #struct_ident {
marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >,
}
impl #struct_ident {
pub fn new(marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >) -> Self {
Self { marine }
}
}
impl #struct_ident {
#(#module_functions)*
}
};
Ok(module_definition)
}
fn module_import_generator(info: &UseDescription<'_>) -> TResult<TokenStream> {
let from_module_ident = utils::new_ident(info.from)?;
let record_name_ident = utils::new_ident(info.name)?;
Ok(quote! {pub use super::#from_module_ident::#record_name_ident;})
}

View File

@ -1,71 +0,0 @@
/*
* 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.
*/
use super::methods_generator_utils::*;
use crate::TResult;
use marine_it_parser::it_interface::IFunctionSignature;
use marine_it_parser::it_interface::IRecordTypes;
use itertools::Itertools;
pub(super) fn generate_module_methods<'m, 'r>(
module_name: &str,
method_signatures: impl ExactSizeIterator<Item = &'m IFunctionSignature>,
records: &'r IRecordTypes,
) -> TResult<Vec<proc_macro2::TokenStream>> {
use CallParametersSettings::*;
let methods_count = 2 * method_signatures.len();
method_signatures
.sorted_by(|lhs, rhs| lhs.name.cmp(&rhs.name))
.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)?;
methods.push(default_cp);
methods.push(user_cp);
Ok(methods)
},
)
}
pub fn generate_facade_methods<'m, 'r>(
method_signatures: impl ExactSizeIterator<Item = &'m IFunctionSignature>,
records: &'r IRecordTypes,
) -> TResult<Vec<proc_macro2::TokenStream>> {
use CallParametersSettings::*;
let methods_count = 2 * method_signatures.len();
method_signatures
.sorted_by(|lhs, rhs| lhs.name.cmp(&rhs.name))
.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)?;
methods.push(default_cp);
methods.push(user_cp);
Ok(methods)
},
)
}

View File

@ -1,245 +0,0 @@
/*
* 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.
*/
use crate::marine_test::utils::new_ident;
use crate::marine_test::utils::itype_to_tokens;
use crate::TResult;
use marine_it_parser::it_interface::it::IType;
use marine_it_parser::it_interface::it::IFunctionArg;
use marine_it_parser::it_interface::IRecordTypes;
use marine_it_parser::it_interface::IFunctionSignature;
use proc_macro2::TokenStream;
use quote::quote;
#[derive(Clone, Copy)]
pub(super) enum CallParametersSettings {
Default,
UserDefined,
}
pub(super) fn generate_module_method(
module_name: &str,
signature: &IFunctionSignature,
cp_setting: CallParametersSettings,
records: &IRecordTypes,
) -> TResult<TokenStream> {
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 (cp, func_name) = generate_call_parameters(&cp_setting, signature)?;
let module_method = quote! {
pub fn #func_name(&mut self, #(#arguments),* #cp) #output_type {
#mcall
}
};
Ok(module_method)
}
pub(super) fn generate_module_method_forward(
signature: &IFunctionSignature,
cp_setting: CallParametersSettings,
records: &IRecordTypes,
) -> TResult<TokenStream> {
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 (cp, func_name) = generate_call_parameters(&cp_setting, signature)?;
let module_method = quote! {
pub fn #func_name(&mut self, #(#arguments),* #cp) #output_type {
#mcall
}
};
Ok(module_method)
}
fn generate_marine_call(
module_name: &str,
cp_settings: CallParametersSettings,
method_signature: &IFunctionSignature,
records: &IRecordTypes,
) -> TResult<TokenStream> {
let args = method_signature.arguments.iter().map(|a| a.name.as_str());
let convert_arguments = generate_arguments_converter(args)?;
let output_type = get_output_type(&method_signature.outputs)?;
let set_result = generate_set_result(&output_type);
let function_call = generate_function_call(module_name, &method_signature.name, cp_settings);
let convert_result_to_output_type = generate_convert_to_output(&output_type, records)?;
let ret = generate_ret(&output_type);
let function_call = quote! {
use std::ops::DerefMut;
#convert_arguments
#set_result #function_call
#convert_result_to_output_type
#ret
};
Ok(function_call)
}
fn generate_forward_call(
cp_settings: CallParametersSettings,
method_signature: &IFunctionSignature,
) -> TResult<TokenStream> {
let mut args = method_signature
.arguments
.iter()
.map(|a| new_ident(a.name.as_str()))
.collect::<TResult<Vec<syn::Ident>>>()?;
let method_name = if let CallParametersSettings::UserDefined = cp_settings {
args.push(new_ident("cp")?);
new_ident(format!("{}_cp", method_signature.name.as_str()).as_str())?
} else {
new_ident(method_signature.name.as_str())?
};
let function_call = quote! {
self.__facade.#method_name(#(#args,)*)
};
Ok(function_call)
}
/// Generates type convertor to json because of AppService receives them in json.
fn generate_arguments_converter<'a>(
args: impl ExactSizeIterator<Item = &'a str>,
) -> TResult<TokenStream> {
let arg_idents: Vec<syn::Ident> = args.map(new_ident).collect::<Result<_, _>>()?;
let args_converter = quote! { let arguments = marine_rs_sdk_test::internal::serde_json::json!([#(#arg_idents),*]); };
Ok(args_converter)
}
fn generate_function_call(
module_name: &str,
method_name: &str,
cp_setting: CallParametersSettings,
) -> TokenStream {
let cp = match cp_setting {
CallParametersSettings::Default => quote! { <_>::default() },
CallParametersSettings::UserDefined => quote! { cp },
};
quote! { self.marine.as_ref().borrow_mut().call_module(#module_name, #method_name, arguments, #cp).expect("call to Marine failed"); }
}
fn generate_set_result(output_type: &Option<&IType>) -> TokenStream {
match output_type {
Some(_) => quote! { let result = },
None => TokenStream::new(),
}
}
fn generate_convert_to_output(
output_type: &Option<&IType>,
records: &IRecordTypes,
) -> TResult<TokenStream> {
let result_stream = match output_type {
Some(ty) => {
let ty = itype_to_tokens(ty, records)?;
quote! {
let result: #ty = marine_rs_sdk_test::internal::serde_json::from_value(result).expect("the default deserializer shouldn't fail");
}
}
None => TokenStream::new(),
};
Ok(result_stream)
}
fn generate_ret(output_type: &Option<&IType>) -> TokenStream {
match output_type {
Some(_) => quote! { result },
None => TokenStream::new(),
}
}
fn generate_arguments<'a, 'r>(
arguments: impl ExactSizeIterator<Item = &'a IFunctionArg>,
records: &'r IRecordTypes,
) -> TResult<Vec<TokenStream>> {
arguments
.map(|argument| -> TResult<_> {
let arg_name = new_ident(&argument.name)?;
let arg_type = itype_to_tokens(&argument.ty, records)?;
let arg = quote! { #arg_name: #arg_type };
Ok(arg)
})
.collect::<TResult<Vec<_>>>()
}
fn generate_output_type(output_types: &[IType], records: &IRecordTypes) -> TResult<TokenStream> {
let output_type = get_output_type(output_types)?;
match output_type {
None => Ok(TokenStream::new()),
Some(ty) => {
let output_type = itype_to_tokens(&ty, records)?;
let output_type = quote! { -> #output_type };
Ok(output_type)
}
}
}
fn get_output_type(output_types: &[IType]) -> TResult<Option<&IType>> {
use crate::TestGeneratorError::ManyFnOutputsUnsupported;
match output_types.len() {
0 => Ok(None),
1 => Ok(Some(&output_types[0])),
_ => Err(ManyFnOutputsUnsupported),
}
}
fn generate_call_parameters(
cp_setting: &CallParametersSettings,
signature: &IFunctionSignature,
) -> TResult<(TokenStream, syn::Ident)> {
match cp_setting {
CallParametersSettings::Default => {
let func_name = new_ident(&signature.name)?;
Ok((TokenStream::new(), func_name))
}
CallParametersSettings::UserDefined => {
let maybe_comma = if signature.arguments.is_empty() {
TokenStream::new()
} else {
quote! { , }
};
let cp = quote! { #maybe_comma cp: marine_rs_sdk_test::CallParameters };
let func_name = format!("{}_cp", signature.name);
let func_name = new_ident(&func_name)?;
Ok((cp, func_name))
}
}
}

View File

@ -1,71 +0,0 @@
/*
* 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.
*/
use crate::marine_test::utils;
use crate::TResult;
use marine_it_parser::it_interface::it::IRecordFieldType;
use marine_it_parser::it_interface::IRecordTypes;
use proc_macro2::TokenStream;
use quote::quote;
use crate::marine_test::modules_linker::{LinkedModule, RecordEntry, UseDescription};
use itertools::Itertools;
pub(super) fn generate_records(
linked_module: &LinkedModule<'_>,
import_generator: fn(info: &UseDescription<'_>) -> TResult<TokenStream>,
) -> TResult<Vec<TokenStream>> {
linked_module.records
.iter()
.sorted()
.map(|record| -> TResult<_> {
use RecordEntry::*;
match record {
Use(use_info) => import_generator(use_info),
Declare(record) => {
let record_name_ident = utils::new_ident(&record.record_type.name)?;
let fields = prepare_field(record.record_type.fields.iter(), record.records)?;
Ok(quote! {
#[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 #record_name_ident {
#(pub #fields),*
}
})
}
}
})
.collect::<TResult<Vec<_>>>()
}
fn prepare_field<'f>(
fields: impl ExactSizeIterator<Item = &'f IRecordFieldType>,
records: &IRecordTypes,
) -> TResult<Vec<TokenStream>> {
fields
.map(|field| -> TResult<_> {
let field_name = utils::new_ident(&field.name)?;
let field_type = utils::itype_to_tokens(&field.ty, records)?;
let generated_field = quote! { #field_name: #field_type };
Ok(generated_field)
})
.collect::<TResult<Vec<_>>>()
}

View File

@ -1,204 +0,0 @@
use crate::TResult;
use crate::TestGeneratorError;
use crate::marine_test::config_utils::Module;
use crate::marine_test::utils::new_ident;
use crate::marine_test::{modules_linker, config_utils};
use crate::marine_test::modules_linker::{LinkedModule, UseDescription};
use super::service_generator::{ProcessedService, get_facace};
use proc_macro2::TokenStream;
use quote::quote;
use std::path::Path;
use itertools::Itertools;
pub(crate) fn generate_app_service_ctor(
config_path: &str,
modules_dir: &Path,
) -> TResult<TokenStream> {
let modules_dir = modules_dir
.to_str()
.ok_or_else(|| TestGeneratorError::InvalidUTF8Path(modules_dir.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();
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(file!()).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 _ = 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");
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));
};
Ok(service_ctor)
}
pub(super) fn generate_service_definition(
service: &ProcessedService,
test_file_path: &Path,
linked_facade: &LinkedModule<'_>,
) -> TResult<TokenStream> {
let modules_dir_test_relative = test_file_path.join(&service.config.resolved_modules_dir);
let modules =
config_utils::collect_modules(&service.config.config, &modules_dir_test_relative)?;
let linked_modules = modules_linker::link_modules(
modules
.iter()
.map(|module| (module.name, &module.interface)),
)?;
let service_mod = new_ident(&service.name)?;
let module_definitions = super::generate_module_definitions(modules.iter(), &linked_modules)?;
let facade = get_facace(&modules)?;
let facade_interface = super::methods_generator::generate_facade_methods(
facade.interface.function_signatures.iter(),
&facade.interface.record_types,
)?;
let facade_override =
super::generate_module_definition(facade, linked_facade, service_import_generator)?;
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 modules_type = generate_modules_type(&modules)?;
let service_definition = quote! {
pub mod #service_mod {
pub mod modules {
#(#module_definitions)*
}
pub mod #facade_override_ident {
#facade_override
}
#(#facade_structs)*
#modules_type
pub struct ServiceInterface {
pub modules: __GeneratedModules,
__facade: #facade_override_ident::ModuleInterface,
marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >
}
impl ServiceInterface {
pub fn new() -> Self {
#app_service_ctor
let modules = __GeneratedModules::new(marine.clone());
let __facade = #facade_override_ident::ModuleInterface::new(marine.clone());
Self {
marine,
modules,
__facade
}
}
#(#facade_interface)*
}
}
};
Ok(service_definition)
}
fn service_import_generator(info: &UseDescription<'_>) -> TResult<TokenStream> {
let from_module_ident = new_ident(info.from)?;
let record_name_ident = new_ident(info.name)?;
Ok(quote! {pub use super::super::#from_module_ident::#record_name_ident;})
}
fn generate_facade_structs(
module: &Module<'_>,
module_name: &syn::Ident,
) -> TResult<Vec<TokenStream>> {
module
.interface
.record_types
.iter()
.sorted_by_key(|(_, record)| &record.name)
.map(|(_, record)| -> TResult<TokenStream> {
let record_name = new_ident(&record.name)?;
let result = quote! {pub use #module_name::#record_name;};
Ok(result)
})
.collect::<TResult<Vec<TokenStream>>>()
}
fn generate_modules_type(module_interfaces: &[Module<'_>]) -> TResult<TokenStream> {
let fields = module_interfaces
.iter()
.map(|module| -> TResult<TokenStream> {
let name = new_ident(module.name)?;
Ok(quote! {pub #name: modules::#name::ModuleInterface})
})
.collect::<TResult<Vec<TokenStream>>>()?;
let ctors = module_interfaces
.iter()
.map(|module| -> TResult<TokenStream> {
let name = new_ident(module.name)?;
Ok(quote! {#name: modules::#name::ModuleInterface::new(marine.clone())})
})
.collect::<TResult<Vec<TokenStream>>>()?;
let ty = quote! {
pub struct __GeneratedModules {
#(#fields,)*
}
impl __GeneratedModules {
fn new(marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >) -> Self {
Self {
#(#ctors,)*
}
}
}
};
Ok(ty)
}

View File

@ -1,110 +0,0 @@
/*
* 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.
*/
use crate::attributes::{ServiceDescription};
use crate::TResult;
use crate::TestGeneratorError;
use crate::marine_test::config_utils::{Module, ConfigWrapper, load_config};
use crate::marine_test::{modules_linker, config_utils};
use crate::marine_test::modules_linker::LinkedModules;
use super::service_generation_utils::generate_service_definition;
use marine_it_parser::it_interface::IModuleInterface;
use proc_macro2::TokenStream;
use itertools::{Itertools, zip};
use std::path::Path;
use std::collections::HashMap;
pub(crate) fn generate_service_definitions(
services: HashMap<String, ServiceDescription>,
file_path: &Path,
) -> TResult<Vec<TokenStream>> {
let services = services
.into_iter()
.sorted_by(|lhs, rhs| lhs.0.cmp(&rhs.0)) // deterministic output required for tests
.map(|(name, service)| ProcessedService::new(service, name, file_path))
.collect::<TResult<Vec<ProcessedService>>>()?;
let service_modules = services
.iter()
.map(|service| {
let modules_dir_test_relative = file_path.join(&service.config.resolved_modules_dir);
let modules =
config_utils::collect_modules(&service.config.config, &modules_dir_test_relative)?;
Ok(modules)
})
.collect::<TResult<Vec<Vec<Module<'_>>>>>()?;
let link_info = link_services(zip(&services, &service_modules))?;
services
.iter()
.map(|service| -> TResult<TokenStream> {
// entry with service.name was added in link_services(...), so unwrap is safe
generate_service_definition(
&service,
file_path,
link_info.get::<str>(&service.name).unwrap(),
)
})
.collect::<TResult<Vec<TokenStream>>>()
}
pub(super) fn get_facace<'modules, 'm>(
modules: &'modules [Module<'m>],
) -> TResult<&'modules Module<'m>> {
match modules.last() {
Some(module) => Ok(module),
None => Err(TestGeneratorError::NoModulesInService),
}
}
pub(super) struct ProcessedService {
pub(super) config: ConfigWrapper,
pub(super) config_path: String,
pub(super) name: String,
}
impl ProcessedService {
pub(crate) fn new(
service: ServiceDescription,
name: String,
file_path: &Path,
) -> TResult<Self> {
let config_wrapper = load_config(&service.config_path, service.modules_dir, &file_path)?;
Ok(Self {
config: config_wrapper,
config_path: service.config_path,
name,
})
}
}
fn link_services<'modules>(
services: impl ExactSizeIterator<
Item = (&'modules ProcessedService, &'modules Vec<Module<'modules>>),
>,
) -> TResult<LinkedModules<'modules>> {
let facade_modules = services
.map(|(service, modules)| {
let facade = get_facace(modules)?;
Ok((service.name.as_str(), &facade.interface))
})
.collect::<TResult<Vec<(&str, &IModuleInterface)>>>()?;
modules_linker::link_modules(facade_modules.iter().copied())
}

View File

@ -1,62 +0,0 @@
/*
* 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.
*/
use crate::TResult;
use marine_it_parser::it_interface::IRecordTypes;
use marine_it_parser::it_interface::it::IType;
use proc_macro2::TokenStream;
use quote::quote;
pub(super) fn new_ident(ident_str: &str) -> TResult<syn::Ident> {
let ident_str = ident_str.replace('-', "_");
syn::parse_str::<syn::Ident>(&ident_str).map_err(Into::into)
}
pub(super) fn itype_to_tokens(itype: &IType, records: &IRecordTypes) -> TResult<TokenStream> {
let token_stream = match itype {
IType::Record(record_id) => {
let record = records
.get(record_id)
.ok_or_else(|| crate::errors::CorruptedITSection::AbsentRecord(*record_id))?;
let record_name = new_ident(&record.name)?;
let token_stream = quote! { #record_name };
token_stream
}
IType::Array(ty) => {
let inner_ty_token_stream = itype_to_tokens(ty, records)?;
let token_stream = quote! { Vec<#inner_ty_token_stream> };
token_stream
}
IType::String => quote! { String },
IType::ByteArray => quote! { Vec<u8> },
IType::Boolean => quote! { bool },
IType::S8 => quote! { i8 },
IType::S16 => quote! { i16 },
IType::S32 => quote! { i32 },
IType::S64 => quote! { i64 },
IType::U8 => quote! { u8 },
IType::U16 => quote! { u16 },
IType::U32 => quote! { u32 },
IType::U64 => quote! { u64 },
IType::I32 => quote! { i32 },
IType::I64 => quote! { i64 },
IType::F32 => quote! { f32 },
IType::F64 => quote! { f64 },
};
Ok(token_stream)
}

View File

@ -1,6 +0,0 @@
modules_dir = "artifacts/"
[[module]]
name = "greeting"
mem_pages_count = 1
logger_enabled = false

View File

@ -1,128 +0,0 @@
#[test]
fn empty_string() {
pub mod marine_test_env {
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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>, >,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,>
) -> Self {
Self { marine }
}
}
impl ModuleInterface {}
}
}
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(file!()).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 _ = module_path.pop();
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));
fn test_func() {
{}
}
test_func()
}

View File

@ -1,8 +0,0 @@
modules_dir = "artifacts/"
[[module]]
name = "greeting"
mem_pages_count = 1
logger_enabled = false
[module.mounted_binaries]
echo = "/usr/bin/curl"

View File

@ -1,167 +0,0 @@
#[test]
fn test() {
pub mod marine_test_env {
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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>, >,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self { marine }
}
}
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
.as_ref()
.borrow_mut()
.call_module("greeting", "download", arguments, <_>::default())
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn download_cp(
&mut self,
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
.as_ref()
.borrow_mut()
.call_module("greeting", "download", arguments, cp)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
}
}
}
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(file!()).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 _ = module_path.pop();
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 mut greeting = marine_test_env::greeting::ModuleInterface::new(marine.clone());
fn test_func(greeting: marine_test_env::greeting::ModuleInterface) {
let mut greeting = greeting;
{
let _ = greeting.download("duckduckgo.com");
}
}
test_func(greeting,)
}

View File

@ -1,3 +0,0 @@
fn test(greeting: marine_test_env::greeting::ModuleInterface) {
let _ = greeting.download("duckduckgo.com");
}

View File

@ -1,6 +0,0 @@
modules_dir = "artifacts/"
[[module]]
name = "greeting"
mem_pages_count = 50
logger_enabled = false

View File

@ -1,504 +0,0 @@
#[test]
fn test() {
pub mod marine_test_env {
pub mod empty_func {
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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>,
>,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> 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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>,
>,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> 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<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self {
greeting: modules::greeting::ModuleInterface::new(marine.clone()),
}
}
}
pub struct ServiceInterface {
pub modules: __GeneratedModules,
__facade: __facade_override::ModuleInterface,
marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >
}
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(file!()).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 _ = 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
.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 mounted_binary {
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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>,
>,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self { marine }
}
}
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
.as_ref()
.borrow_mut()
.call_module("greeting", "download", arguments, <_>::default())
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn download_cp(
&mut self,
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
.as_ref()
.borrow_mut()
.call_module("greeting", "download", arguments, cp)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
}
}
}
pub mod __facade_override {
pub use super::super::empty_func::CallParameters;
pub use super::super::empty_func::MountedBinaryResult;
pub use super::super::empty_func::MountedBinaryStringResult;
pub use super::super::empty_func::SecurityTetraplet;
pub struct ModuleInterface {
marine:
std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self { marine }
}
}
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
.as_ref()
.borrow_mut()
.call_module("greeting", "download", arguments, <_>::default())
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn download_cp(
&mut self,
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
.as_ref()
.borrow_mut()
.call_module("greeting", "download", arguments, cp)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
}
}
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<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self {
greeting: modules::greeting::ModuleInterface::new(marine.clone()),
}
}
}
pub struct ServiceInterface {
pub modules: __GeneratedModules,
__facade: __facade_override::ModuleInterface,
marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >
}
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(file!()).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 _ = 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
.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 fn download(&mut self, url: String) -> String {
self.__facade.download(url,)
}
pub fn download_cp(
&mut self,
url: String,
cp: marine_rs_sdk_test::CallParameters
) -> String {
self.__facade.download_cp(url, cp,)
}
}
}
}
fn test_func() {
{
let mut greeting = marine_test_env::greeting::ServiceInterface::new();
let _ = greeting.download("duckduckgo.com");
}
}
test_func()
}

View File

@ -1,4 +0,0 @@
fn test() {
let mut greeting = marine_test_env::greeting::ServiceInterface::new();
let _ = greeting.download("duckduckgo.com");
}

View File

@ -1,8 +0,0 @@
modules_dir = "artifacts/"
[[module]]
name = "greeting"
mem_pages_count = 50
logger_enabled = false
[module.mounted_binaries]
echo = "/usr/bin/curl"

View File

@ -1,6 +0,0 @@
modules_dir = "artifacts/"
[[module]]
name = "greeting"
mem_pages_count = 50
logger_enabled = false

View File

@ -1,242 +0,0 @@
#[test]
fn empty_test() {
pub mod marine_test_env {
pub mod empty_func {
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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>,
>,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> 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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>,
>,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> 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<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self {
greeting: modules::greeting::ModuleInterface::new(marine.clone()),
}
}
}
pub struct ServiceInterface {
pub modules: __GeneratedModules,
__facade: __facade_override::ModuleInterface,
marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >
}
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(file!()).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 _ = 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
.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
}
}
}
}
}
fn test_func() {
{}
}
test_func()
}

View File

@ -1,10 +0,0 @@
modules_dir = "artifacts/"
[[module]]
name = "greeting"
mem_pages_count = 1
logger_enabled = false
[[module]]
name = "call_parameters"
mem_pages_count = 1
logger_enabled = false

View File

@ -1,321 +0,0 @@
#[test]
fn empty_string() {
pub mod marine_test_env {
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<Vec<SecurityTetraplet>>
}
#[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<u8>,
pub stderr: Vec<u8>
}
#[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<marine_rs_sdk_test::internal::AppService>, >,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self { marine }
}
}
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
.as_ref()
.borrow_mut()
.call_module("greeting", "greeting", arguments, <_>::default())
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn greeting_cp(
&mut self,
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
.as_ref()
.borrow_mut()
.call_module("greeting", "greeting", arguments, cp)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
}
}
pub mod call_parameters {
pub use super::greeting::CallParameters;
pub use super::greeting::SecurityTetraplet;
pub struct ModuleInterface {
marine: std::rc::Rc<std::cell::RefCell<marine_rs_sdk_test::internal::AppService>, >,
}
impl ModuleInterface {
pub fn new(
marine: std::rc::Rc<
std::cell::RefCell<marine_rs_sdk_test::internal::AppService>,
>
) -> Self {
Self { marine }
}
}
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
.as_ref()
.borrow_mut()
.call_module(
"call_parameters",
"call_parameters",
arguments,
<_>::default()
)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn call_parameters_cp(
&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
.as_ref()
.borrow_mut()
.call_module("call_parameters", "call_parameters", arguments, cp)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
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
.as_ref()
.borrow_mut()
.call_module(
"call_parameters",
"return_string",
arguments,
<_>::default()
)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn return_string_cp(
&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
.as_ref()
.borrow_mut()
.call_module("call_parameters", "return_string", arguments, cp)
.expect("call to Marine failed");
let result: String =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn test_array_refs(&mut self, ) -> Vec<String> {
use std::ops::DerefMut;
let arguments = marine_rs_sdk_test::internal::serde_json::json!([]);
let result = self
.marine
.as_ref()
.borrow_mut()
.call_module(
"call_parameters",
"test_array_refs",
arguments,
<_>::default()
)
.expect("call to Marine failed");
let result: Vec<String> =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
pub fn test_array_refs_cp(
&mut self,
cp: marine_rs_sdk_test::CallParameters
) -> Vec<String> {
use std::ops::DerefMut;
let arguments = marine_rs_sdk_test::internal::serde_json::json!([]);
let result = self
.marine
.as_ref()
.borrow_mut()
.call_module("call_parameters", "test_array_refs", arguments, cp)
.expect("call to Marine failed");
let result: Vec<String> =
marine_rs_sdk_test::internal::serde_json::from_value(result)
.expect("the default deserializer shouldn't fail");
result
}
}
}
}
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(file!()).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 _ = module_path.pop();
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 mut greeting_m = marine_test_env::greeting::ModuleInterface::new(marine.clone());
let mut call_parameters_m =
marine_test_env::call_parameters::ModuleInterface::new(marine.clone());
fn test_func(
greeting_m: marine_test_env::greeting::ModuleInterface,
call_parameters_m: marine_test_env::call_parameters::ModuleInterface
) {
let mut greeting_m = greeting_m;
let mut call_parameters_m = call_parameters_m;
{
let init_peer_id = "init_peer_id";
let service_id = "service_id";
let service_creator_peer_id = "service_creator_peer_id";
let host_id = "host_id";
let particle_id = "particle_id";
let greeting = greeting_m.greeting("asd");
let mut tetraplet = SecurityTetraplet::default();
tetraplet.function_name = "some_func_name".to_string();
tetraplet.json_path = "some_json_path".to_string();
let tetraplets = vec![vec![tetraplet]];
let cp = CallParameters {
init_peer_id: init_peer_id.to_string(),
service_id: service_id.to_string(),
service_creator_peer_id: service_creator_peer_id.to_string(),
host_id: host_id.to_string(),
particle_id: particle_id.to_string(),
tetraplets: tetraplets.clone(),
};
let actual = call_parameters_m.call_parameters_cp(cp);
let expected = format!(
"{}\n{}\n{}\n{}\n{}\n{:?}",
init_peer_id, service_id, service_creator_peer_id, host_id, particle_id, tetraplets
);
assert_eq!(actual, expected);
}
}
test_func(greeting_m, call_parameters_m, )
}

View File

@ -1,29 +0,0 @@
fn empty_string(greeting_m: marine_test_env::greeting::ModuleInterface, call_parameters_m: marine_test_env::call_parameters::ModuleInterface) {
let init_peer_id = "init_peer_id";
let service_id = "service_id";
let service_creator_peer_id = "service_creator_peer_id";
let host_id = "host_id";
let particle_id = "particle_id";
let greeting = greeting_m.greeting("asd");
let mut tetraplet = SecurityTetraplet::default();
tetraplet.function_name = "some_func_name".to_string();
tetraplet.json_path = "some_json_path".to_string();
let tetraplets = vec![vec![tetraplet]];
let cp = CallParameters {
init_peer_id: init_peer_id.to_string(),
service_id: service_id.to_string(),
service_creator_peer_id: service_creator_peer_id.to_string(),
host_id: host_id.to_string(),
particle_id: particle_id.to_string(),
tetraplets: tetraplets.clone(),
};
let actual = call_parameters_m.call_parameters_cp(cp);
let expected = format!(
"{}\n{}\n{}\n{}\n{}\n{:?}",
init_peer_id, service_id, service_creator_peer_id, host_id, particle_id, tetraplets
);
assert_eq!(actual, expected);
}

View File

@ -1,86 +0,0 @@
/*
* 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.
*/
mod utils;
use utils::test_marine_test_token_streams;
use utils::TestServiceDescription;
use utils::test_marine_test_token_streams_multiservice;
#[test]
fn test_empty_func() {
assert!(test_marine_test_token_streams(
"tests/generation_tests/empty_func/marine_test.rs",
"tests/generation_tests/empty_func/expanded.rs",
"Config.toml",
"artifacts"
));
}
#[test]
fn test_mounted_binary() {
assert!(test_marine_test_token_streams(
"tests/generation_tests/mounted_binary/marine_test.rs",
"tests/generation_tests/mounted_binary/expanded.rs",
"Config.toml",
"artifacts"
));
}
#[test]
fn test_multiple_modules() {
assert!(test_marine_test_token_streams(
"tests/generation_tests/multiple_modules/marine_test.rs",
"tests/generation_tests/multiple_modules/expanded.rs",
"Config.toml",
"artifacts"
));
}
#[test]
fn test_multiservice_single() {
let descriptions = vec![TestServiceDescription {
modules_dir: "empty_func/artifacts",
config_path: "empty_func/Config.toml",
name: "empty_func",
}];
assert!(test_marine_test_token_streams_multiservice(
"tests/generation_tests/multi-service-single/marine_test.rs",
"tests/generation_tests/multi-service-single/expanded.rs",
descriptions
));
}
#[test]
fn test_multiservice_multiple() {
let descriptions = vec![
TestServiceDescription {
modules_dir: "empty_func/artifacts",
config_path: "empty_func/Config.toml",
name: "empty_func",
},
TestServiceDescription {
modules_dir: "mounted_binary/artifacts",
config_path: "mounted_binary/Config.toml",
name: "mounted_binary",
},
];
assert!(test_marine_test_token_streams_multiservice(
"tests/generation_tests/multi-service-multiple/marine_test.rs",
"tests/generation_tests/multi-service-multiple/expanded.rs",
descriptions
));
}

View File

@ -1,97 +0,0 @@
/*
* 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.
*/
use marine_test_macro_impl::marine_test_impl;
use marine_macro_testing_utils::{items_from_file, stream_from_file, to_syn_item};
use std::path::Path;
pub fn test_marine_test_token_streams<FP, EP>(
marine_path: FP,
expanded_path: EP,
config_path: &str,
modules_dir: &str,
) -> bool
where
FP: AsRef<Path>,
EP: AsRef<Path>,
{
let marine_item = stream_from_file(&marine_path);
let test_token_stream = quote::quote! { #marine_item };
let buf = marine_path.as_ref().to_path_buf();
let attrs = quote::quote! {
config_path = #config_path,
modules_dir = #modules_dir,
};
let marine_token_streams = marine_test_impl(
attrs,
test_token_stream,
buf.parent().unwrap().to_path_buf(),
)
.unwrap_or_else(|e| panic!("failed to apply the marine macro due {}", e));
let expanded_item = items_from_file(&expanded_path);
let marine_item = to_syn_item(marine_token_streams.clone());
marine_item == expanded_item
}
pub struct TestServiceDescription {
pub config_path: &'static str,
pub modules_dir: &'static str,
pub name: &'static str,
}
pub fn test_marine_test_token_streams_multiservice<FP, EP>(
marine_path: FP,
expanded_path: EP,
services: Vec<TestServiceDescription>,
) -> bool
where
FP: AsRef<Path>,
EP: AsRef<Path>,
{
let marine_item = stream_from_file(&marine_path);
let test_token_stream = quote::quote! { #marine_item };
let buf = marine_path.as_ref().to_path_buf();
let service_declarations = services
.iter()
.map(|desc| {
let config_path = desc.config_path;
let modules_dir = desc.modules_dir;
let name = syn::parse_str::<syn::Ident>(desc.name)?;
Ok(quote::quote! {#name(config_path = #config_path, modules_dir = #modules_dir)})
})
.collect::<Result<Vec<_>, syn::Error>>()
.unwrap_or_else(|e| panic!("failed to parse test arguments due to {}", e));
let attrs = quote::quote! {
#(#service_declarations,)*
};
let marine_token_streams = marine_test_impl(
attrs,
test_token_stream,
buf.parent().unwrap().to_path_buf(),
)
.unwrap_or_else(|e| panic!("failed to apply the marine macro due {}", e));
let expanded_item = items_from_file(&expanded_path);
let marine_item = to_syn_item(marine_token_streams.clone());
marine_item == expanded_item
}

View File

@ -1,26 +0,0 @@
[package]
name = "marine-test-macro"
version = "0.3.0" # remember to update html_root_url
edition = "2018"
description = "Definition of the `#[marine_test]` macro"
documentation = "https://docs.rs/fluence/marine-test-macro"
repository = "https://github.com/fluencelabs/marine-rs-sdk/tree/master/crates/marine-test-macro"
authors = ["Fluence Labs"]
keywords = ["fluence", "marine", "sdk", "webassembly", "procedural_macros"]
categories = ["api-bindings", "wasm", "development-tools::testing"]
license = "Apache-2.0"
[package.metadata.docs.rs]
all-features = true
[lib]
proc-macro = true
doctest = false
[dependencies]
marine-test-macro-impl = { path = "../marine-test-macro-impl", version = "=0.3.0" }
quote = "1.0.9"
proc-macro2 = "1.0.24"
proc-macro-error = { version = "1.0.4", default-features = false }
syn = { version = '1.0.64', features = ['full'] }

View File

@ -1,74 +0,0 @@
/*
* Copyright 2020 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/sdk-test-macro/0.3.0")]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
#![feature(proc_macro_span)]
#![warn(rust_2018_idioms)]
#![recursion_limit = "1024"]
use marine_test_macro_impl::marine_test_impl;
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use syn::spanned::Spanned;
/// This macro allows user to write tests for services in the following form:
///```rust
/// #[marine_test(config = "/path/to/Config.toml", modules_dir = "path/to/service/modules")]
/// fn test(greeting: marine_test_env::greeting::ModuleInterface) {
/// let service_result = greeting.greeting("John".to_string());
/// assert_eq!(&service_result, "Hi, name!");
/// }
///```
#[proc_macro_error]
#[proc_macro_attribute]
pub fn marine_test(attrs: TokenStream, input: TokenStream) -> TokenStream {
let attrs: proc_macro2::TokenStream = attrs.into();
let attrs_span = attrs.span();
// here it obtains a path to the current file where macro is applied
let mut file_path = proc_macro::Span::call_site().source_file().path();
let _ = file_path.pop();
match marine_test_impl(attrs, input.into(), file_path) {
Ok(stream) => stream.into(),
Err(e) => proc_macro_error::abort!(attrs_span, format!("{}", e)),
}
}
// deprecated macro for backwards compatibility
#[deprecated(since = "0.6.2", note = "please use the #[marine] macro instead")]
#[proc_macro_error]
#[proc_macro_attribute]
pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream {
let attrs: proc_macro2::TokenStream = attrs.into();
let attrs_span = attrs.span();
// here it obtains a path to the current file where macro is applied
let mut file_path = proc_macro::Span::call_site().source_file().path();
let _ = file_path.pop();
match marine_test_impl(attrs, input.into(), file_path) {
Ok(stream) => stream.into(),
Err(e) => proc_macro_error::abort!(attrs_span, format!("{}", e)),
}
}

View File

@ -1,9 +0,0 @@
## Version 0.3.0 (2021-10-04)
[PR 61](https://github.com/fluencelabs/marine-rs-sdk/pull/61):
Implemented the first part of [Issue 57](https://github.com/fluencelabs/marine-rs-sdk/issues/57): `marine_test` now can take several named services in attributes, then define interface to the services in `marine_test_env`.
## Version 0.2.0 (2021-09-01)
[PR 54](https://github.com/fluencelabs/marine-rs-sdk/pull/54):
- previously test function accessed module interfaces through externally defined variables, now module interfaces are passed as arguments.
- introduced generated module `marine_test_env` which provides interface for generated structs and functions.

View File

@ -1,29 +0,0 @@
[package]
name = "marine-rs-sdk-test"
version = "0.3.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/tree/master/fluence-test"
authors = ["Fluence Labs"]
keywords = ["fluence", "marine", "sdk", "webassembly", "test"]
categories = ["api-bindings", "wasm", "development-tools::testing"]
license = "Apache-2.0"
edition = "2018"
[package.metadata.docs.rs]
all-features = true
[lib]
path = "src/lib.rs"
doctest = false
[dev-dependencies]
trybuild = "1.0"
[dependencies]
marine-test-macro = { path = "../crates/marine-test-macro", version = "=0.3.0" }
fluence-app-service = { version = "0.9.0", features = ["raw-module-api"] }
serde = { version = "1.0.118", features = ["derive"] }
serde_json = "1.0.64"
uuid = { version = "0.8.2", features = ["v4"] }

View File

@ -1,45 +0,0 @@
/*
* Copyright 2020 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/sdk-test/0.3.0")]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
#![warn(rust_2018_idioms)]
pub use marine_test_macro::marine_test;
pub use marine_test_macro::fce_test;
pub use fluence_app_service::CallParameters;
pub use fluence_app_service::SecurityTetraplet;
/// These API functions are intended for internal usage in generated code.
/// Normally, you shouldn't use them.
pub mod internal {
pub use fluence_app_service::AppService;
pub use fluence_app_service::TomlAppServiceConfig;
pub use serde;
pub use serde_json;
pub use uuid::Uuid;
}

View File

@ -1,35 +0,0 @@
[package]
name = "marine-rs-sdk"
version = "0.6.14" # remember to update html_root_url
description = "Fluence backend SDK for developing backend applications for the Fluence network"
documentation = "https://docs.rs/fluence"
repository = "https://github.com/fluencelabs/marine-rs-sdk"
authors = ["Fluence Labs"]
keywords = ["fluence", "marine", "sdk", "webassembly"]
categories = ["api-bindings", "wasm"]
license = "Apache-2.0"
edition = "2018"
[package.metadata.docs.rs]
all-features = true
[lib]
path = "src/lib.rs"
doctest = false
[dependencies]
marine-macro = { path = "../crates/marine-macro", version = "=0.6.14" }
marine-rs-sdk-main = { path = "../crates/main", version = "=0.6.14" }
marine-timestamp-macro = { path = "../crates/timestamp-macro", version = "=0.6.14" }
serde = { version = "1.0.118", features = ["derive"]}
[dev-dependencies]
trybuild = "1.0"
[features]
# Print some internal logs by log_utf8_string
debug = ["marine-rs-sdk-main/debug"]
# Enable logger (this will cause log_utf8_string to appear in imports)
logger = ["marine-rs-sdk-main/logger"]