mirror of
https://github.com/fluencelabs/aquavm
synced 2025-04-24 23:02:16 +00:00
feat(execution-engine)!: unfefined %last_error% now returns an empty … (#628)
feat(execution-engine)!: %last_eror%.$.message and $.error_code now return an empty string and 0 correspondingly [fixes VM-313]
This commit is contained in:
parent
d5a3f768af
commit
d195152320
@ -21,6 +21,7 @@ use crate::JValue;
|
||||
use air_interpreter_data::Provenance;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -28,6 +29,8 @@ pub const ERROR_CODE_FIELD_NAME: &str = "error_code";
|
||||
pub const MESSAGE_FIELD_NAME: &str = "message";
|
||||
pub const INSTRUCTION_FIELD_NAME: &str = "instruction";
|
||||
pub const PEER_ID_FIELD_NAME: &str = "peer_id";
|
||||
pub const NO_ERROR_MESSAGE: &str = "";
|
||||
pub const NO_ERROR_ERROR_CODE: i64 = 0;
|
||||
|
||||
/// This struct is intended to track the last arisen error.
|
||||
/// LastError is essentially a scalar value with support of lambda expressions.
|
||||
@ -112,3 +115,18 @@ fn ensure_jvalue_is_string(
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_error_last_error_object() -> JValue {
|
||||
json!({
|
||||
ERROR_CODE_FIELD_NAME: NO_ERROR_ERROR_CODE,
|
||||
MESSAGE_FIELD_NAME: NO_ERROR_MESSAGE,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn no_error_last_error() -> LastError {
|
||||
LastError {
|
||||
error: Rc::new(no_error_last_error_object()),
|
||||
tetraplet: None,
|
||||
provenance: Provenance::literal(),
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
use air_interpreter_data::Provenance;
|
||||
|
||||
use super::last_error_definition::error_from_raw_fields;
|
||||
use super::no_error_last_error;
|
||||
use super::LastError;
|
||||
use crate::execution_step::LastErrorAffectable;
|
||||
use crate::execution_step::RcSecurityTetraplet;
|
||||
@ -104,11 +105,7 @@ impl LastErrorDescriptor {
|
||||
|
||||
impl Default for LastErrorDescriptor {
|
||||
fn default() -> Self {
|
||||
let last_error = LastError {
|
||||
error: Rc::new(JValue::Null),
|
||||
tetraplet: None,
|
||||
provenance: Provenance::literal(),
|
||||
};
|
||||
let last_error = no_error_last_error();
|
||||
|
||||
Self {
|
||||
last_error,
|
||||
|
@ -19,11 +19,14 @@ mod last_error_definition;
|
||||
mod last_error_descriptor;
|
||||
|
||||
pub use errors::LastErrorObjectError;
|
||||
pub use last_error_definition::no_error_last_error;
|
||||
pub use last_error_definition::no_error_last_error_object;
|
||||
pub use last_error_definition::LastError;
|
||||
pub use last_error_definition::ERROR_CODE_FIELD_NAME;
|
||||
pub use last_error_definition::INSTRUCTION_FIELD_NAME;
|
||||
pub use last_error_definition::MESSAGE_FIELD_NAME;
|
||||
pub use last_error_definition::PEER_ID_FIELD_NAME;
|
||||
pub use last_error_definition::NO_ERROR_ERROR_CODE;
|
||||
pub use last_error_definition::NO_ERROR_MESSAGE;
|
||||
|
||||
pub(crate) use last_error_definition::check_error_object;
|
||||
pub(crate) use last_error_definition::error_from_raw_fields;
|
||||
|
@ -37,8 +37,12 @@ pub use air_interpreter_interface::RunParameters;
|
||||
pub use air_interpreter_interface::INTERPRETER_SUCCESS;
|
||||
pub use execution_step::execution_context::errors::unsupported_map_key_type;
|
||||
pub use execution_step::execution_context::errors::StreamMapError;
|
||||
pub use execution_step::execution_context::no_error_last_error;
|
||||
pub use execution_step::execution_context::no_error_last_error_object;
|
||||
pub use execution_step::execution_context::ExecutionCidState;
|
||||
pub use execution_step::execution_context::LastError;
|
||||
pub use execution_step::execution_context::NO_ERROR_ERROR_CODE;
|
||||
pub use execution_step::execution_context::NO_ERROR_MESSAGE;
|
||||
pub use execution_step::CatchableError;
|
||||
pub use execution_step::ExecutionError;
|
||||
pub use execution_step::LambdaError;
|
||||
|
@ -14,11 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use air::no_error_last_error_object;
|
||||
use air::CatchableError;
|
||||
use air::ExecutionCidState;
|
||||
use air::ExecutionError;
|
||||
use air::LambdaError;
|
||||
use air::LastErrorObjectError;
|
||||
use air::SecurityTetraplet;
|
||||
use air::NO_ERROR_ERROR_CODE;
|
||||
use air::NO_ERROR_MESSAGE;
|
||||
use air_test_framework::AirScriptExecutor;
|
||||
use air_test_utils::prelude::*;
|
||||
|
||||
use std::cell::RefCell;
|
||||
@ -119,7 +124,7 @@ fn not_clear_last_error_in_match() {
|
||||
let _ = checked_call_vm!(local_vm, <_>::default(), &script, "", result.data);
|
||||
|
||||
let actual_value = (*args.borrow()).as_ref().unwrap().clone();
|
||||
assert_eq!(actual_value, JValue::Null);
|
||||
assert_eq!(actual_value, no_error_last_error_object(),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -154,7 +159,7 @@ fn not_clear_last_error_in_mismatch() {
|
||||
let _ = checked_call_vm!(local_vm, <_>::default(), &script, "", result.data);
|
||||
|
||||
let actual_value = (*args.borrow()).as_ref().unwrap().clone();
|
||||
assert_eq!(actual_value, JValue::Null);
|
||||
assert_eq!(actual_value, no_error_last_error_object(),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -236,7 +241,7 @@ fn non_initialized_last_error() {
|
||||
let _ = checked_call_vm!(vm, test_params.clone(), script, "", "");
|
||||
|
||||
let actual_value = (*args.borrow()).as_ref().unwrap().clone();
|
||||
assert_eq!(actual_value, JValue::Null);
|
||||
assert_eq!(actual_value, no_error_last_error_object(),);
|
||||
|
||||
let actual_tetraplets = (*tetraplets.borrow()).as_ref().unwrap().clone();
|
||||
assert_eq!(
|
||||
@ -492,3 +497,59 @@ fn last_error_with_match() {
|
||||
let trace = trace_from_result(&result);
|
||||
assert_eq!(trace.len(), 2); // if match works there will be 2 calls in a resulted trace
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undefined_last_error_errcode() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(call "{local_peer_id}" ("test" "error_code") [%last_error%.$.error_code] scalar) ; behaviour = echo
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let actual_trace = trace_from_result(&result.last().unwrap());
|
||||
let mut cid_state = ExecutionCidState::new();
|
||||
let errcode_lambda_output = json!(NO_ERROR_ERROR_CODE);
|
||||
|
||||
let expected_trace = ExecutionTrace::from(vec![scalar_tracked!(
|
||||
errcode_lambda_output.clone(),
|
||||
cid_state,
|
||||
peer = local_peer_id,
|
||||
service = "test..0",
|
||||
function = "error_code",
|
||||
args = vec![errcode_lambda_output]
|
||||
)]);
|
||||
assert_eq!(actual_trace, expected_trace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undefined_last_error_msg_errcode() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(call "{local_peer_id}" ("test" "message") [%last_error%.$.message] scalar1) ; behaviour = echo
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let actual_trace = trace_from_result(&result.last().unwrap());
|
||||
let mut cid_state = ExecutionCidState::new();
|
||||
let message_lambda_output = json!(NO_ERROR_MESSAGE);
|
||||
|
||||
let expected_trace = ExecutionTrace::from(vec![scalar_tracked!(
|
||||
message_lambda_output.clone(),
|
||||
cid_state,
|
||||
peer = local_peer_id,
|
||||
service = "test..0",
|
||||
function = "message",
|
||||
args = vec![message_lambda_output]
|
||||
)]);
|
||||
assert_eq!(actual_trace, expected_trace);
|
||||
}
|
||||
|
@ -14,7 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use air::no_error_last_error_object;
|
||||
use air::ExecutionCidState;
|
||||
use air_test_framework::AirScriptExecutor;
|
||||
use air_test_utils::prelude::*;
|
||||
|
||||
use std::cell::RefCell;
|
||||
@ -196,13 +198,17 @@ fn ap_with_last_error() {
|
||||
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
|
||||
"values": [
|
||||
{
|
||||
"result": null,
|
||||
"result": no_error_last_error_object(),
|
||||
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
|
||||
"trace_pos": 0
|
||||
}
|
||||
]
|
||||
})),
|
||||
unused!(json!([null]), peer = vm_1_peer_id, args = [json!([null])]),
|
||||
unused!(
|
||||
json!([no_error_last_error_object()]),
|
||||
peer = vm_1_peer_id,
|
||||
args = [no_error_last_error_object()]
|
||||
),
|
||||
];
|
||||
|
||||
assert_eq!(actual_trace, expected_state);
|
||||
@ -552,3 +558,44 @@ fn ap_stream_map() {
|
||||
]);
|
||||
assert_eq!(actual_trace, expected_state);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ap_stream_map_with_undefined_last_error() {
|
||||
let vm_1_peer_id = "vm_1_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(seq
|
||||
(ap ("key" %last_error%) %map)
|
||||
(fold %map i
|
||||
(seq
|
||||
(call "{vm_1_peer_id}" ("m" "f") [i.$.value]) ; behaviour = echo
|
||||
(next i)
|
||||
)
|
||||
)
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(vm_1_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(vm_1_peer_id).unwrap();
|
||||
let actual_trace = trace_from_result(&result.last().unwrap());
|
||||
|
||||
let expected_state = vec![
|
||||
executed_state::ap(0),
|
||||
executed_state::fold(vec![subtrace_lore(
|
||||
0,
|
||||
SubTraceDesc::new(2.into(), 1),
|
||||
SubTraceDesc::new(3.into(), 0),
|
||||
)]),
|
||||
unused!(
|
||||
no_error_last_error_object(),
|
||||
peer = vm_1_peer_id,
|
||||
service = "m",
|
||||
function = "f",
|
||||
args = [no_error_last_error_object()]
|
||||
),
|
||||
];
|
||||
|
||||
assert_eq!(actual_trace, expected_state,);
|
||||
}
|
||||
|
@ -15,6 +15,10 @@
|
||||
*/
|
||||
|
||||
use air::CatchableError;
|
||||
use air::ExecutionCidState;
|
||||
use air::NO_ERROR_ERROR_CODE;
|
||||
use air::NO_ERROR_MESSAGE;
|
||||
use air_test_framework::AirScriptExecutor;
|
||||
use air_test_utils::prelude::*;
|
||||
|
||||
#[test]
|
||||
@ -383,3 +387,65 @@ fn issue_165() {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_with_undefined_last_error_errcode() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(xor
|
||||
(match 1 2 (null))
|
||||
(call "local_peer_id" ("test" "error_code") [%last_error%.$.error_code] scalar) ; behaviour = echo
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let actual_trace = trace_from_result(&result.last().unwrap());
|
||||
let mut cid_state = ExecutionCidState::new();
|
||||
let errcode_lambda_output = json!(NO_ERROR_ERROR_CODE);
|
||||
|
||||
let expected_trace = ExecutionTrace::from(vec![scalar_tracked!(
|
||||
errcode_lambda_output.clone(),
|
||||
cid_state,
|
||||
peer = local_peer_id,
|
||||
service = "test..0",
|
||||
function = "error_code",
|
||||
args = vec![errcode_lambda_output]
|
||||
)]);
|
||||
assert_eq!(actual_trace, expected_trace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_with_undefined_last_error_message() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(xor
|
||||
(match 1 2 (null))
|
||||
(call "local_peer_id" ("test" "message") [%last_error%.$.message] scalar) ; behaviour = echo
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let actual_trace = trace_from_result(&result.last().unwrap());
|
||||
let mut cid_state = ExecutionCidState::new();
|
||||
let message_lambda_output = json!(NO_ERROR_MESSAGE);
|
||||
|
||||
let expected_trace = ExecutionTrace::from(vec![scalar_tracked!(
|
||||
message_lambda_output.clone(),
|
||||
cid_state,
|
||||
peer = local_peer_id,
|
||||
service = "test..0",
|
||||
function = "message",
|
||||
args = vec![message_lambda_output]
|
||||
)]);
|
||||
assert_eq!(actual_trace, expected_trace);
|
||||
}
|
||||
|
@ -14,10 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use air::no_error_last_error_object;
|
||||
use air::unsupported_map_key_type;
|
||||
use air::CatchableError;
|
||||
use air::LambdaError;
|
||||
|
||||
use air_test_framework::AirScriptExecutor;
|
||||
use air_test_utils::prelude::*;
|
||||
|
||||
#[test]
|
||||
@ -587,3 +589,74 @@ fn unsupported_map_keytype() {
|
||||
let expected_error = CatchableError::StreamMapError(unsupported_map_key_type(map_name));
|
||||
assert!(check_error(&result, expected_error));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undefined_last_error_functor() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(xor
|
||||
(match 1 2
|
||||
(null)
|
||||
)
|
||||
(call "local_peer_id" ("test" "error_code") [%last_error%.length] scalar)
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let expected_error = CatchableError::LengthFunctorAppliedToNotArray(no_error_last_error_object());
|
||||
assert!(check_error(&result.last().unwrap(), expected_error));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undefined_last_error_instruction() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(xor
|
||||
(match 1 2
|
||||
(null)
|
||||
)
|
||||
(call "local_peer_id" ("test" "instruction") [%last_error%.$.instruction] scalar)
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let expected_error = CatchableError::LambdaApplierError(LambdaError::ValueNotContainSuchField {
|
||||
value: no_error_last_error_object(),
|
||||
field_name: "instruction".to_string(),
|
||||
});
|
||||
assert!(check_error(&&result.last().unwrap(), expected_error));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undefined_last_error_peer_id() {
|
||||
let local_peer_id = "local_peer_id";
|
||||
let script = format!(
|
||||
r#"
|
||||
(xor
|
||||
(match 1 2
|
||||
(null)
|
||||
)
|
||||
(call "local_peer_id" ("test" "peer_id") [%last_error%.$.peer_id] scalar)
|
||||
)
|
||||
"#
|
||||
);
|
||||
let executor = AirScriptExecutor::from_annotated(TestRunParameters::from_init_peer_id(local_peer_id), &script)
|
||||
.expect("invalid test AIR script");
|
||||
let result = executor.execute_all(local_peer_id).unwrap();
|
||||
|
||||
let expected_error = CatchableError::LambdaApplierError(LambdaError::ValueNotContainSuchField {
|
||||
value: no_error_last_error_object(),
|
||||
field_name: "peer_id".to_string(),
|
||||
});
|
||||
assert!(check_error(&&result.last().unwrap(), expected_error));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user