py_mcai_worker_sdk 1.1.3

AMQP Worker to listen and provide trait to process message
use crate::{helpers::*, parameters::*};
use mcai_worker_sdk::prelude::*;
use pyo3::{prelude::*, types::*};
use schemars::schema::InstanceType;
use serde_json::Value;
use std::collections::HashMap;

#[test]
pub fn test_py_err_to_string() {
  let gil = Python::acquire_gil();
  let py = gil.python();

  PyErr::new::<pyo3::exceptions::PyTypeError, _>("Error message").restore(py);
  let py_err = PyErr::fetch(py);

  let expected_message = "TypeError(\'Error message\'".to_string();
  assert!(py_err_to_string(py, py_err).contains(&expected_message));
}

#[test]
pub fn test_get_destination_paths() {
  let destination_paths = vec![
    "/path/to/destination/file_1".to_string(),
    "/path/to/destination/file_2".to_string(),
    "/path/to/destination/file_3".to_string(),
  ];
  let gil = Python::acquire_gil();
  let py = gil.python();

  let py_list = PyList::new(py, destination_paths.clone());
  let py_dict = PyDict::new(py);
  let result = py_dict.set_item("destination_paths", py_list);
  assert!(result.is_ok());

  let py_any: &PyAny = py_dict.into();

  let result = get_destination_paths(py_any);
  assert!(result.is_some());
  assert_eq!(destination_paths, result.unwrap());
}

#[test]
pub fn test_get_destination_paths_without_key() {
  let gil = Python::acquire_gil();
  let py = gil.python();

  let py_dict = PyDict::new(py);

  let py_any: &PyAny = py_dict.into();

  let result = get_destination_paths(py_any);
  assert!(result.is_none());
}

#[test]
pub fn test_get_destination_paths_without_list_value() {
  let gil = Python::acquire_gil();
  let py = gil.python();

  let py_dict = PyDict::new(py);
  let result = py_dict.set_item("destination_paths", "some_value");
  assert!(result.is_ok());

  let py_any: &PyAny = py_dict.into();

  let result = get_destination_paths(py_any);
  assert!(result.is_none());
}

#[test]
#[cfg(feature = "media")]
pub fn test_get_stream_indexes() {
  use crate::StreamDescriptorHandler;

  let gil = Python::acquire_gil();
  let py = gil.python();

  // whatever the type, since the vec is empty...
  let filter_list = PyList::new(py, Vec::<String>::new());
  let stream_indexes = vec![
    StreamDescriptorHandler::new_video_stream(0, filter_list),
    StreamDescriptorHandler::new_audio_stream(1, filter_list),
  ];

  let py_list: PyObject = stream_indexes.into_py(py);
  let py_any: &PyAny = py_list.cast_as(py).unwrap();

  let result = get_stream_descriptors(py_any);
  assert!(result.is_ok());
  let result = result.unwrap();
  assert_eq!(2, result.len());
}

#[test]
#[cfg(feature = "media")]
pub fn test_get_stream_indexes_without_list() {
  let gil = Python::acquire_gil();
  let py = gil.python();

  let py_string = PyString::new(py, "this_is_not_a_list!");
  let py_any: &PyAny = py_string.into();

  let expected_error = MessageError::RuntimeError(
    "unable to access init_process(..) python response: PyDowncastError { from: \'this_is_not_a_list!\', to: \"PyList\" }".to_string(),
  );

  let result = get_stream_descriptors(py_any);
  assert!(result.is_err());
  assert_eq!(expected_error, result.unwrap_err());
}

#[test]
pub fn test_get_instance_type_from_parameter() {
  assert_eq!(
    InstanceType::String,
    get_instance_type_from_parameter_type(&WorkerParameterType::String)
  );
  assert_eq!(
    InstanceType::Array,
    get_instance_type_from_parameter_type(&WorkerParameterType::ArrayOfStrings)
  );
  assert_eq!(
    InstanceType::Boolean,
    get_instance_type_from_parameter_type(&WorkerParameterType::Boolean)
  );
  assert_eq!(
    InstanceType::String,
    get_instance_type_from_parameter_type(&WorkerParameterType::Credential)
  );
  assert_eq!(
    InstanceType::Integer,
    get_instance_type_from_parameter_type(&WorkerParameterType::Integer)
  );
  assert_eq!(
    InstanceType::Object,
    get_instance_type_from_parameter_type(&WorkerParameterType::Requirements)
  );
}

#[test]
pub fn test_build_parameters() {
  let mut parameters = HashMap::<String, Value>::new();
  parameters.insert(
    "string_parameter".to_string(),
    Value::String("string_value".to_string()),
  );
  parameters.insert("null_parameter".to_string(), Value::Null);
  parameters.insert("boolean_parameter".to_string(), Value::Bool(true));
  parameters.insert(
    "number_parameter".to_string(),
    Value::Number(serde_json::Number::from(123)),
  );
  parameters.insert(
    "array_of_string_parameter".to_string(),
    Value::Array(vec![Value::String("string_value".to_string())]),
  );
  parameters.insert(
    "array_of_null_parameter".to_string(),
    Value::Array(vec![Value::Null]),
  );
  parameters.insert(
    "array_of_bool_parameter".to_string(),
    Value::Array(vec![Value::Bool(true)]),
  );
  parameters.insert(
    "array_of_number_parameter".to_string(),
    Value::Array(vec![Value::Number(serde_json::Number::from(123))]),
  );
  let worker_parameters = PythonWorkerParameters { parameters };

  let gil = Python::acquire_gil();
  let py = gil.python();

  let result = build_parameters(worker_parameters, py);
  assert!(result.is_ok());
  let py_parameters = result.unwrap();
  assert!(py_parameters.get_item("string_parameter").is_some());
  assert!(py_parameters.get_item("boolean_parameter").is_some());
  assert!(py_parameters.get_item("number_parameter").is_some());
  assert!(py_parameters
    .get_item("array_of_string_parameter")
    .is_some());
  assert!(py_parameters.get_item("array_of_null_parameter").is_some());
  assert!(py_parameters.get_item("array_of_bool_parameter").is_some());
  assert!(py_parameters
    .get_item("array_of_number_parameter")
    .is_some());
  assert!(py_parameters.get_item("null_parameter").is_none());
}

#[test]
pub fn test_build_parameters_with_object_value() {
  let mut parameters = HashMap::<String, Value>::new();
  let parameter_key = "object_parameter".to_string();
  parameters.insert(
    parameter_key.clone(),
    Value::Object(serde_json::Map::<String, Value>::new()),
  );
  let worker_parameters = PythonWorkerParameters { parameters };

  let gil = Python::acquire_gil();
  let py = gil.python();

  let result = build_parameters(worker_parameters, py);
  assert!(result.is_ok());

  let reference = PyDict::new(py);
  reference.set_item(parameter_key, PyDict::new(py)).unwrap();
  assert_eq!(
    core::cmp::Ordering::Equal,
    result.unwrap().compare(reference).unwrap()
  );
}

#[test]
pub fn test_build_parameters_for_requirements() {
  use serde_json::json;

  let mut parameters = HashMap::<String, Value>::new();
  let parameter_key = "requirements".to_string();

  let value = json!({
    "paths": []
  });

  parameters.insert(parameter_key.clone(), value);
  let worker_parameters = PythonWorkerParameters { parameters };

  let gil = Python::acquire_gil();
  let py = gil.python();

  let result = build_parameters(worker_parameters, py);
  assert!(result.is_ok());

  let reference = PyDict::new(py);
  let requirement_content = PyDict::new(py);
  requirement_content
    .set_item("paths", PyList::empty(py))
    .unwrap();
  reference
    .set_item(parameter_key, requirement_content)
    .unwrap();
  assert_eq!(
    core::cmp::Ordering::Equal,
    result.unwrap().compare(reference).unwrap()
  );
}

#[test]
pub fn test_build_parameters_with_array_of_array_value() {
  let mut parameters = HashMap::<String, Value>::new();
  let parameter_key = "array_of_array_parameter".to_string();
  parameters.insert(
    parameter_key.clone(),
    Value::Array(vec![Value::Array(vec![Value::Bool(true)])]),
  );
  let worker_parameters = PythonWorkerParameters { parameters };

  let gil = Python::acquire_gil();
  let py = gil.python();

  let result = build_parameters(worker_parameters, py);

  let reference = PyDict::new(py);
  let content = PyList::empty(py);
  let sub_content = PyList::empty(py);
  sub_content.append(PyBool::new(py, true)).unwrap();
  content.append(sub_content).unwrap();
  reference.set_item(parameter_key, content).unwrap();
  assert_eq!(
    core::cmp::Ordering::Equal,
    result.unwrap().compare(reference).unwrap()
  );
}

#[test]
pub fn test_build_parameters_with_array_of_object_value() {
  let mut parameters = HashMap::<String, Value>::new();
  let parameter_key = "array_of_object_parameter".to_string();
  parameters.insert(
    parameter_key.clone(),
    Value::Array(vec![Value::Object(serde_json::Map::<String, Value>::new())]),
  );
  let worker_parameters = PythonWorkerParameters { parameters };

  let gil = Python::acquire_gil();
  let py = gil.python();

  let result = build_parameters(worker_parameters, py);

  let reference = PyDict::new(py);
  let content = PyList::empty(py);
  content.append(PyDict::new(py)).unwrap();
  reference.set_item(parameter_key, content).unwrap();
  assert_eq!(
    core::cmp::Ordering::Equal,
    result.unwrap().compare(reference).unwrap()
  );
}