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:
raftedproc 2023-07-14 21:46:28 +03:00 committed by GitHub
parent d5a3f768af
commit d195152320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 280 additions and 11 deletions

View File

@ -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(),
}
}

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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,);
}

View File

@ -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);
}

View File

@ -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));
}