Add test for issue 177 (#183)

This commit is contained in:
Mike Voronov 2021-11-29 18:35:11 +03:00 committed by GitHub
parent cf278bbd4c
commit c5c9aefa37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 346 additions and 57 deletions

View File

@ -51,7 +51,7 @@ thread_local!(static SET_VARIABLES_VM: RefCell<TestRunner> = RefCell::new({
String::from("blueprint") => json!(blueprint),
);
create_avm(set_variables_call_service(variables_mapping), "set_variables")
create_avm(set_variables_call_service(variables_mapping, VariableOptionSource::Argument(0)), "set_variables")
}));
fn create_service_benchmark() -> Result<RawAVMOutcome, String> {

View File

@ -18,7 +18,6 @@ use air_test_utils::prelude::*;
use fstrings::f;
use fstrings::format_args_f;
use std::collections::HashSet;
#[test]
fn ap_with_scalars() {
@ -186,37 +185,3 @@ fn ap_with_dst_stream() {
assert_eq!(actual_trace, expected_state);
assert!(result.next_peer_pks.is_empty());
}
#[test]
fn par_ap_behaviour() {
let client_id = "client_id";
let relay_id = "relay_id";
let variable_setter_id = "variable_setter_id";
let mut client = create_avm(unit_call_service(), client_id);
let mut relay = create_avm(unit_call_service(), relay_id);
let mut variable_setter = create_avm(unit_call_service(), variable_setter_id);
let script = f!(r#"
(par
(call "{variable_setter_id}" ("peer" "timeout") [] join_it)
(seq
(par
(call "{relay_id}" ("peer" "timeout") [join_it] $result)
(ap "fast_result" $result) ;; ap doesn't affect the subtree_complete flag
)
(call "{client_id}" ("op" "return") [$result.$[0]])
)
)
"#);
let mut client_result_1 = checked_call_vm!(client, "", &script, "", "");
let actual_next_peers: HashSet<_> = client_result_1.next_peer_pks.drain(..).collect();
let expected_next_peers: HashSet<_> = maplit::hashset!(relay_id.to_string(), variable_setter_id.to_string());
assert_eq!(actual_next_peers, expected_next_peers);
let setter_result = checked_call_vm!(variable_setter, "", &script, "", client_result_1.data.clone());
assert!(setter_result.next_peer_pks.is_empty());
let relay_result = checked_call_vm!(relay, "", script, "", client_result_1.data);
assert!(relay_result.next_peer_pks.is_empty());
}

View File

@ -29,7 +29,10 @@ fn new_with_global_streams_seq() {
"1".to_string() => json!(1),
"2".to_string() => json!(2),
};
let mut set_variable_vm = create_avm(set_variables_call_service(variables_mapping), set_variable_peer_id);
let mut set_variable_vm = create_avm(
set_variables_call_service(variables_mapping, VariableOptionSource::Argument(0)),
set_variable_peer_id,
);
let script = format!(
r#"

View File

@ -106,7 +106,10 @@ fn create_service() {
"blueprint".to_string() => blueprint.clone(),
);
let mut set_variables_vm = create_avm(set_variables_call_service(variables_mapping), "set_variables");
let mut set_variables_vm = create_avm(
set_variables_call_service(variables_mapping, VariableOptionSource::Argument(0)),
"set_variables",
);
let add_module_response = "add_module response";
let add_blueprint_response = "add_blueprint response";

View File

@ -186,7 +186,10 @@ fn fold_merge() {
"stream_1".to_string() => json!(["peer_0", "peer_1", "peer_2", "peer_3"]),
"stream_2".to_string() => json!(["peer_4", "peer_5", "peer_6"]),
};
let mut set_variable_vm = create_avm(set_variables_call_service(variables), set_variable_vm_id);
let mut set_variable_vm = create_avm(
set_variables_call_service(variables, VariableOptionSource::Argument(0)),
set_variable_vm_id,
);
let script = format!(
include_str!("./scripts/inner_folds_v1.clj"),

View File

@ -34,7 +34,7 @@ fn dont_wait_on_json_path() {
"status".to_string() => status,
);
let set_variables_call_service = set_variables_call_service(variables);
let set_variables_call_service = set_variables_call_service(variables, VariableOptionSource::Argument(0));
let set_variable_peer_id = "set_variable";
let mut set_variable_vm = create_avm(set_variables_call_service, set_variable_peer_id);
@ -148,7 +148,7 @@ fn dont_wait_on_json_path_on_scalars() {
"object".to_string() => object,
);
let set_variables_call_service = set_variables_call_service(variables);
let set_variables_call_service = set_variables_call_service(variables, VariableOptionSource::Argument(0));
let set_variable_peer_id = "set_variable";
let mut set_variable_vm = create_avm(set_variables_call_service, set_variable_peer_id);

View File

@ -21,8 +21,6 @@ mod dashboard;
mod data_merge;
mod empty_array;
mod flattening;
mod issue_137;
mod issue_180;
mod join;
mod join_behaviour;
mod json_path;

View File

@ -25,7 +25,7 @@ fn network_explore() {
"client".to_string() => json!(client_id),
);
let client_call_service = set_variables_call_service(set_variables_state);
let client_call_service = set_variables_call_service(set_variables_state, VariableOptionSource::Argument(0));
let mut client = create_avm(client_call_service, client_id);
let client_1_id = "client_1_id";

View File

@ -163,7 +163,10 @@ fn fold_early_exit() {
"stream_4".to_string() => json!(["d1", "d2"]),
);
let mut variables_setter = create_avm(set_variables_call_service(variables), variables_setter_id);
let mut variables_setter = create_avm(
set_variables_call_service(variables, VariableOptionSource::Argument(0)),
variables_setter_id,
);
let mut stream_setter = create_avm(echo_call_service(), stream_setter_id);
let mut fold_executor = create_avm(unit_call_service(), fold_executor_id);
let mut error_trigger = create_avm(fallible_call_service("error"), error_trigger_id);
@ -254,7 +257,10 @@ fn fold_par_early_exit() {
"stream_4".to_string() => json!(["d1", "d2"]),
);
let mut variables_setter = create_avm(set_variables_call_service(variables), variables_setter_id);
let mut variables_setter = create_avm(
set_variables_call_service(variables, VariableOptionSource::Argument(0)),
variables_setter_id,
);
let mut stream_setter = create_avm(echo_call_service(), stream_setter_id);
let mut fold_executor = create_avm(unit_call_service(), fold_executor_id);
let mut error_trigger = create_avm(fallible_call_service("error"), error_trigger_id);

View File

@ -17,7 +17,7 @@
use air_test_utils::prelude::*;
#[test]
// test for github.com/fluencelabs/aquavm/issues/137
// https://github.com/fluencelabs/aquavm/issues/137
fn issue_137() {
let initiator_id = "initiator_id";
let mut initiator = create_avm(unit_call_service(), initiator_id);

View File

@ -0,0 +1,152 @@
/*
* 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 air_test_utils::prelude::*;
use std::collections::HashMap;
use serde_json::json;
#[test]
// https://github.com/fluencelabs/aquavm/issues/177
fn issue_177() {
let client_peer_id = "12D3KooWMMcNVt5AsiisAHbkfyZWKHufB2dkHCY5pUqZ6AQgEVK6";
let relay_peer_id = "12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e";
let variables = maplit::hashmap! {
"-relay-".to_string() => json!(relay_peer_id),
"noop".to_string() => json!([]),
"string_to_parse_iter".to_string() => json!("CovLVG4fQcqVPcweSGV5ANQ8NQ2hJnVQrFJJPyQvdKmMDDNDuYYveDy4ncnmDbsvRFA5FcG"),
"neighborhood".to_string() => json!(["12D3KooWGzNvhSDsgFoHwpWHAyPf1kcTYCGeRBPfznL8J6qdyu2H","12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB","12D3KooWBSdm6TkqnEFrgBuSkpVE3dR1kr6952DsWQRNwJZjFZBv","12D3KooWKnRcsTpYx9axkJ6d69LPfpPXrkVLe96skuPTAo76LLVH","12D3KooWHCJbJKGDfCgHSoCuK9q4STyRnVveqLoXAPBbXHTZx9Cv","12D3KooWMhVpgfQxBLkQkJed8VFNvgN4iE6MD7xCybb1ZYWW2Gtz","12D3KooWF7gjXhQ4LaKj6j7ntxsPpGk34psdQicN2KNfBi9bFKXg","12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb","12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9","12D3KooWHk9BjDQBUqnavciRPhAYFvqKBe4ZiPPvde7vDaqgn5er","12D3KooWDcpWuyrMTDinqNgmXAuRdfd2mTdY9VoXZSAet2pDzh6r","12D3KooWCKCeqLPSgMnDjyFsJuWqREDtKNHx1JEBiwaMXhCLNTRb","12D3KooWMigkP4jkVyufq5JnDJL6nXvyjeaDNpRfEZqQhsG3sYCU","12D3KooWB9P1xmV3c7ZPpBemovbwCiRRTKd3Kq2jsVPQN4ZukDfy","12D3KooWAKNos2KogexTXhrkMZzFYpLHuWJ4PgoAhurSAv7o5CWA","12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr","12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA","12D3KooWEFFCZnar1cUJQ3rMWjvPQg6yMV2aXWs2DkJNSRbduBWn","12D3KooWHBG9oaVx4i3vi6c1rSBUm7MLBmyGmmbHoZ23pmjDCnvK","12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5"]),
};
let mut client = create_avm(
set_variables_call_service(variables.clone(), VariableOptionSource::FunctionName),
client_peer_id,
);
let mut relay = create_avm(
set_variables_call_service(variables, VariableOptionSource::FunctionName),
relay_peer_id,
);
let script = include_str!("scripts/issue_177.clj");
// client 1: demand result for (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
let client_result_1 = client
.runner
.call(script, "", "", client_peer_id, HashMap::new())
.expect("call should be success");
let expected_call_requests = maplit::hashmap! {
1 => CallRequestParams::new("getDataSrv", "-relay-", vec![], vec![]),
};
assert_eq!(client_result_1.call_requests, expected_call_requests);
let call_results = maplit::hashmap! {
1 => CallServiceResult::ok(json!("12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e"))
};
// client 2: send result to the specified relay
let client_result_2 = client
.runner
.call(script, client_result_1.data, "", client_peer_id, call_results)
.expect("call should be success");
assert!(client_result_2.call_requests.is_empty());
assert_eq!(client_result_2.next_peer_pks, vec![relay_peer_id.to_string()]);
// relay 1: execute one time (without providing call results) on the relay and them send back to the client
let relay_result_1 = relay
.runner
.call(script, "", client_result_2.data.clone(), client_peer_id, HashMap::new())
.expect("call should be success");
let expected_call_requests = maplit::hashmap! {
1 => CallRequestParams::new("op", "noop", vec![], vec![]),
};
assert_eq!(relay_result_1.call_requests, expected_call_requests);
assert!(relay_result_1.next_peer_pks.is_empty());
// relay 2:
let call_results = maplit::hashmap! {
1 => CallServiceResult::ok(json!(""))
};
let relay_result_2 = relay
.runner
.call(script, relay_result_1.data.clone(), "", client_peer_id, call_results)
.expect("call should be success");
assert!(relay_result_2.next_peer_pks.is_empty());
// relay 3:
let call_results = maplit::hashmap! {
2 => CallServiceResult::ok(json!("CovLVG4fQcqVPcweSGV5ANQ8NQ2hJnVQrFJJPyQvdKmMDDNDuYYveDy4ncnmDbsvRFA5FcG"))
};
let relay_result_3 = relay
.runner
.call(script, relay_result_2.data.clone(), "", client_peer_id, call_results)
.expect("call should be success");
assert!(relay_result_3.next_peer_pks.is_empty());
// relay 4:
let call_results = maplit::hashmap! {
3 => CallServiceResult::ok(json!(["12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb","12D3KooWF7gjXhQ4LaKj6j7ntxsPpGk34psdQicN2KNfBi9bFKXg","12D3KooWBSdm6TkqnEFrgBuSkpVE3dR1kr6952DsWQRNwJZjFZBv","12D3KooWKnRcsTpYx9axkJ6d69LPfpPXrkVLe96skuPTAo76LLVH","12D3KooWEFFCZnar1cUJQ3rMWjvPQg6yMV2aXWs2DkJNSRbduBWn","12D3KooWMhVpgfQxBLkQkJed8VFNvgN4iE6MD7xCybb1ZYWW2Gtz","12D3KooWGzNvhSDsgFoHwpWHAyPf1kcTYCGeRBPfznL8J6qdyu2H","12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB","12D3KooWCKCeqLPSgMnDjyFsJuWqREDtKNHx1JEBiwaMXhCLNTRb","12D3KooWHBG9oaVx4i3vi6c1rSBUm7MLBmyGmmbHoZ23pmjDCnvK","12D3KooWB9P1xmV3c7ZPpBemovbwCiRRTKd3Kq2jsVPQN4ZukDfy","12D3KooWAKNos2KogexTXhrkMZzFYpLHuWJ4PgoAhurSAv7o5CWA","12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9","12D3KooWHk9BjDQBUqnavciRPhAYFvqKBe4ZiPPvde7vDaqgn5er","12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr","12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA","12D3KooWHCJbJKGDfCgHSoCuK9q4STyRnVveqLoXAPBbXHTZx9Cv","12D3KooWMigkP4jkVyufq5JnDJL6nXvyjeaDNpRfEZqQhsG3sYCU","12D3KooWDcpWuyrMTDinqNgmXAuRdfd2mTdY9VoXZSAet2pDzh6r","12D3KooWJd3HaMJ1rpLY1kQvcjRPEvnDwcXrH8mJvk7ypcZXqXGE"]))
};
let relay_result_4 = relay
.runner
.call(script, relay_result_3.data.clone(), "", client_peer_id, call_results)
.expect("call should be success");
// client 4: receive result from the relay
// demand result for (call %init_peer_id% ("op" "noop") [])
let client_result_3 = client
.runner
.call(
script,
client_result_2.data,
relay_result_4.data.clone(),
client_peer_id,
HashMap::new(),
)
.expect("call should be success");
let expected_call_requests = maplit::hashmap! {
2 => CallRequestParams::new("op", "noop", vec![], vec![])
};
assert_eq!(client_result_3.call_requests, expected_call_requests);
let call_results = maplit::hashmap! {
2 => CallServiceResult::ok(json!(""))
};
// client 5: (call %init_peer_id% ("op" "identity") [$res.$.[19]!]) joined
// demand a result for (call %init_peer_id% ("peer" "timeout") [1000 "timeout"])
let client_result_4 = client
.runner
.call(script, client_result_3.data, "", client_peer_id, call_results)
.expect("call should be success");
let expected_call_requests = maplit::hashmap! {
3 => CallRequestParams::new("peer", "timeout", vec![json!(1000u64), json!("timeout")], vec![
vec![SecurityTetraplet::new("12D3KooWMMcNVt5AsiisAHbkfyZWKHufB2dkHCY5pUqZ6AQgEVK6", "", "", "")],
vec![SecurityTetraplet::new("12D3KooWMMcNVt5AsiisAHbkfyZWKHufB2dkHCY5pUqZ6AQgEVK6", "", "", "")],
])
};
assert_eq!(client_result_4.call_requests, expected_call_requests);
let call_results = maplit::hashmap! {
3 => CallServiceResult::ok(json!(""))
};
// timeout requests provided
let client_result_5 = client
.runner
.call(script, client_result_4.data, "", client_peer_id, call_results);
// before patch the interpreter crashed here
assert!(client_result_5.is_ok());
}

View File

@ -0,0 +1,56 @@
/*
* 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 air_test_utils::prelude::*;
use fstrings::f;
use fstrings::format_args_f;
use std::collections::HashSet;
#[test]
// https://github.com/fluencelabs/aquavm/issues/178
fn par_ap_behaviour() {
let client_id = "client_id";
let relay_id = "relay_id";
let variable_setter_id = "variable_setter_id";
let mut client = create_avm(unit_call_service(), client_id);
let mut relay = create_avm(unit_call_service(), relay_id);
let mut variable_setter = create_avm(unit_call_service(), variable_setter_id);
let script = f!(r#"
(par
(call "{variable_setter_id}" ("peer" "timeout") [] join_it)
(seq
(par
(call "{relay_id}" ("peer" "timeout") [join_it] $result)
(ap "fast_result" $result) ;; ap doesn't affect the subtree_complete flag
)
(call "{client_id}" ("op" "return") [$result.$[0]])
)
)
"#);
let mut client_result_1 = checked_call_vm!(client, "", &script, "", "");
let actual_next_peers: HashSet<_> = client_result_1.next_peer_pks.drain(..).collect();
let expected_next_peers: HashSet<_> = maplit::hashset!(relay_id.to_string(), variable_setter_id.to_string());
assert_eq!(actual_next_peers, expected_next_peers);
let setter_result = checked_call_vm!(variable_setter, "", &script, "", client_result_1.data.clone());
assert!(setter_result.next_peer_pks.is_empty());
let relay_result = checked_call_vm!(relay, "", script, "", client_result_1.data);
assert!(relay_result.next_peer_pks.is_empty());
}

View File

@ -0,0 +1,20 @@
/*
* 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.
*/
mod issue_137;
mod issue_177;
mod issue_178;
mod issue_180;

View File

@ -0,0 +1,53 @@
(xor
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(new $res
(seq
(seq
(seq
(call -relay- ("op" "noop") [])
(xor
(seq
(call "12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e" ("op" "string_to_b58") ["12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e"] k)
(par
(seq
(call "12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e" ("kad" "neighborhood") [k [] []] nodes)
(call %init_peer_id% ("op" "noop") [])
)
(seq
(fold nodes n
(par
(seq
(xor
(call n ("peer" "timestamp_ms") [] $res)
(seq
(call -relay- ("op" "noop") [])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(call %init_peer_id% ("op" "noop") [])
)
(next n)
)
)
(call %init_peer_id% ("op" "noop") [])
)
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
)
(par
(call %init_peer_id% ("op" "identity") [$res.$.[19]!])
(call %init_peer_id% ("peer" "timeout") [1000 "timeout"])
)
)
(call %init_peer_id% ("op" "identity") [$res] res-fix)
)
)
)
(call %init_peer_id% ("--after-callback-srv-service--" "print-and-stop") [res-fix nodes])
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3])
)

View File

@ -17,3 +17,4 @@
// https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html
mod instructions;
mod integration;
mod issues;

View File

@ -45,14 +45,14 @@ pub struct CallRequestParams {
impl CallRequestParams {
pub fn new(
service_id: String,
function_name: String,
service_id: impl Into<String>,
function_name: impl Into<String>,
arguments: Vec<JValue>,
tetraplets: Vec<Vec<SecurityTetraplet>>,
) -> Self {
Self {
service_id,
function_name,
service_id: service_id.into(),
function_name: function_name.into(),
arguments,
tetraplets,
}

View File

@ -39,6 +39,20 @@ pub struct SecurityTetraplet {
}
impl SecurityTetraplet {
pub fn new(
peer_pk: impl Into<String>,
service_id: impl Into<String>,
function_name: impl Into<String>,
json_path: impl Into<String>,
) -> Self {
Self {
peer_pk: peer_pk.into(),
service_id: service_id.into(),
function_name: function_name.into(),
json_path: json_path.into(),
}
}
/// Create a tetraplet for string literals defined in the script
/// such as variable here `(call ("" "") "" ["variable_1"])`.
pub fn literal_tetraplet(init_peer_id: String) -> Self {

View File

@ -35,13 +35,28 @@ pub fn set_variable_call_service(json: JValue) -> CallServiceClosure {
Box::new(move |_| -> CallServiceResult { CallServiceResult::ok(json.clone()) })
}
/// Manages which source will be used to choose a variable.
pub enum VariableOptionSource {
// i-th argument
Argument(usize),
FunctionName,
ServiceName,
}
pub fn set_variables_call_service(
variables_mapping: HashMap<String, JValue>,
variable_source: VariableOptionSource,
) -> CallServiceClosure {
Box::new(move |mut params| -> CallServiceResult {
let var_name = match params.arguments.pop() {
Some(JValue::String(name)) => name,
_ => "default".to_string(),
use VariableOptionSource::*;
Box::new(move |params| -> CallServiceResult {
let var_name = match variable_source {
Argument(id) => match params.arguments.get(id) {
Some(JValue::String(name)) => name.to_string(),
_ => "default".to_string(),
},
FunctionName => params.function_name,
ServiceName => params.service_id,
};
variables_mapping.get(&var_name).map_or_else(

View File

@ -22,8 +22,8 @@ use std::collections::HashSet;
use std::path::PathBuf;
pub struct TestRunner {
runner: AVMRunner,
call_service: CallServiceClosure,
pub runner: AVMRunner,
pub call_service: CallServiceClosure,
}
impl TestRunner {