use heapless::{String, Vec};
use serde::{Deserialize, Serialize};
use super::{StatusDetails, MAX_JOB_ID_LEN, MAX_PENDING_JOBS, MAX_RUNNING_JOBS};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum JobStatus {
#[serde(rename = "QUEUED")]
Queued,
#[serde(rename = "IN_PROGRESS")]
InProgress,
#[serde(rename = "FAILED")]
Failed,
#[serde(rename = "SUCCEEDED")]
Succeeded,
#[serde(rename = "CANCELED")]
Canceled,
#[serde(rename = "REJECTED")]
Rejected,
#[serde(rename = "REMOVED")]
Removed,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub enum ErrorCode {
InvalidTopic,
InvalidJson,
InvalidRequest,
InvalidStateTransition,
ResourceNotFound,
VersionMismatch,
InternalError,
RequestThrottled,
TerminalStateReached,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct DescribeJobExecutionResponse<'a, J> {
#[serde(rename = "execution")]
pub execution: Option<JobExecution<'a, J>>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
#[serde(rename = "clientToken")]
pub client_token: Option<&'a str>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct GetPendingJobExecutionsResponse<'a> {
#[serde(rename = "inProgressJobs")]
#[serde(skip_serializing_if = "Option::is_none")]
pub in_progress_jobs: Option<Vec<JobExecutionSummary, MAX_RUNNING_JOBS>>,
#[serde(rename = "queuedJobs")]
#[serde(skip_serializing_if = "Option::is_none")]
pub queued_jobs: Option<Vec<JobExecutionSummary, MAX_PENDING_JOBS>>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
#[serde(rename = "clientToken")]
pub client_token: &'a str,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct JobExecution<'a, J> {
#[serde(rename = "approximateSecondsBeforeTimedOut")]
#[serde(skip_serializing_if = "Option::is_none")]
pub approximate_seconds_before_timed_out: Option<i64>,
#[serde(rename = "executionNumber")]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_number: Option<i64>,
#[serde(rename = "jobDocument")]
#[serde(skip_serializing_if = "Option::is_none")]
pub job_document: Option<J>,
#[serde(rename = "jobId")]
pub job_id: &'a str,
#[serde(rename = "lastUpdatedAt")]
pub last_updated_at: i64,
#[serde(rename = "queuedAt")]
pub queued_at: i64,
#[serde(rename = "startedAt")]
#[serde(skip_serializing_if = "Option::is_none")]
pub started_at: Option<i64>,
#[serde(rename = "status")]
pub status: JobStatus,
#[serde(rename = "statusDetails")]
#[serde(skip_serializing_if = "Option::is_none")]
pub status_details: Option<StatusDetails<'a>>,
#[serde(rename = "thingName")]
#[serde(skip_serializing_if = "Option::is_none")]
pub thing_name: Option<&'a str>,
#[serde(rename = "versionNumber")]
pub version_number: i64,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct JobExecutionState<'a> {
#[serde(rename = "status")]
pub status: JobStatus,
#[serde(rename = "statusDetails")]
#[serde(borrow)]
#[serde(skip_serializing_if = "Option::is_none")]
pub status_details: Option<StatusDetails<'a>>,
#[serde(rename = "versionNumber")]
pub version_number: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct JobExecutionSummary {
#[serde(rename = "executionNumber")]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_number: Option<i64>,
#[serde(rename = "jobId")]
#[serde(skip_serializing_if = "Option::is_none")]
pub job_id: Option<String<MAX_JOB_ID_LEN>>,
#[serde(rename = "lastUpdatedAt")]
#[serde(skip_serializing_if = "Option::is_none")]
pub last_updated_at: Option<i64>,
#[serde(rename = "queuedAt")]
#[serde(skip_serializing_if = "Option::is_none")]
pub queued_at: Option<i64>,
#[serde(rename = "startedAt")]
#[serde(skip_serializing_if = "Option::is_none")]
pub started_at: Option<i64>,
#[serde(rename = "versionNumber")]
#[serde(skip_serializing_if = "Option::is_none")]
pub version_number: Option<i64>,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct StartNextPendingJobExecutionResponse<'a, J> {
#[serde(rename = "execution")]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution: Option<JobExecution<'a, J>>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
#[serde(rename = "clientToken")]
pub client_token: &'a str,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct UpdateJobExecutionResponse<'a, J> {
#[serde(rename = "executionState")]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_state: Option<JobExecutionState<'a>>,
#[serde(rename = "jobDocument")]
#[serde(skip_serializing_if = "Option::is_none")]
pub job_document: Option<J>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
#[serde(rename = "clientToken")]
pub client_token: &'a str,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct JobExecutionsChanged {
#[serde(rename = "jobs")]
#[serde(skip_serializing_if = "Option::is_none")]
pub jobs: Option<Jobs>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct NextJobExecutionChanged<'a, J> {
#[serde(rename = "execution")]
#[serde(borrow)]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution: Option<JobExecution<'a, J>>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct Jobs {
#[serde(rename = "QUEUED")]
#[serde(skip_serializing_if = "Option::is_none")]
pub queued: Option<Vec<JobExecutionSummary, MAX_RUNNING_JOBS>>,
#[serde(rename = "IN_PROGRESS")]
#[serde(skip_serializing_if = "Option::is_none")]
pub in_progress: Option<Vec<JobExecutionSummary, MAX_RUNNING_JOBS>>,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct ErrorResponse<'a> {
code: ErrorCode,
message: &'a str,
#[serde(rename = "clientToken")]
#[serde(skip_serializing_if = "Option::is_none")]
pub client_token: Option<&'a str>,
#[serde(rename = "timestamp")]
pub timestamp: i64,
#[serde(rename = "executionState")]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_state: Option<JobExecutionState<'a>>,
}
#[cfg(test)]
mod test {
use super::*;
use heapless::Vec;
use serde_json_core::from_slice;
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct TestJob<'a> {
operation: &'a str,
somerandomkey: &'a str,
}
#[derive(Debug, PartialEq, Deserialize)]
pub enum JobDetails<'a> {
#[serde(rename = "test_job")]
#[serde(borrow)]
TestJob(TestJob<'a>),
#[serde(other)]
Unknown,
}
#[test]
fn deserialize_next_job_execution_changed() {
let payload = br#"
{
"timestamp": 1587471560,
"execution": {
"jobId": "mini",
"status": "QUEUED",
"queuedAt": 1587471559,
"lastUpdatedAt": 1587471559,
"versionNumber": 1,
"executionNumber": 1,
"jobDocument": {
"test_job": {
"operation": "test",
"somerandomkey": "random_value"
}
}
}
}
"#;
let (response, _) = from_slice::<NextJobExecutionChanged<JobDetails>>(payload).unwrap();
assert_eq!(
response,
NextJobExecutionChanged {
execution: Some(JobExecution {
execution_number: Some(1),
job_document: Some(JobDetails::TestJob(TestJob {
operation: "test",
somerandomkey: "random_value"
})),
job_id: "mini",
last_updated_at: 1587471559,
queued_at: 1587471559,
status: JobStatus::Queued,
version_number: 1,
approximate_seconds_before_timed_out: None,
status_details: None,
started_at: None,
thing_name: None,
}),
timestamp: 1587471560,
}
);
}
#[test]
fn deserialize_get_pending_job_executions_response() {
let payload = br#"{
"clientToken": "0:client_name",
"timestamp": 1587381778,
"inProgressJobs": []
}"#;
let (response, _) = from_slice::<GetPendingJobExecutionsResponse>(payload).unwrap();
assert_eq!(
response,
GetPendingJobExecutionsResponse {
in_progress_jobs: Some(Vec::<JobExecutionSummary, MAX_RUNNING_JOBS>::new()),
queued_jobs: None,
timestamp: 1587381778,
client_token: "0:client_name",
}
);
let payload = br#"{
"clientToken": "0:client_name",
"timestamp": 1587381778,
"inProgressJobs": [],
"queuedJobs": [
{
"executionNumber": 1,
"jobId": "test",
"lastUpdatedAt": 1587036256,
"queuedAt": 1587036256,
"versionNumber": 1
}
]
}"#;
let mut queued_jobs: Vec<JobExecutionSummary, MAX_PENDING_JOBS> = Vec::new();
queued_jobs
.push(JobExecutionSummary {
execution_number: Some(1),
job_id: Some(String::from("test")),
last_updated_at: Some(1587036256),
queued_at: Some(1587036256),
started_at: None,
version_number: Some(1),
})
.unwrap();
let (response, _) = from_slice::<GetPendingJobExecutionsResponse>(payload).unwrap();
assert_eq!(
response,
GetPendingJobExecutionsResponse {
in_progress_jobs: Some(Vec::<JobExecutionSummary, MAX_RUNNING_JOBS>::new()),
queued_jobs: Some(queued_jobs),
timestamp: 1587381778,
client_token: "0:client_name",
}
);
}
#[test]
fn deserialize_describe_job_execution_response() {
let payload = br#"{
"clientToken": "0:client_name",
"timestamp": 1587381778,
"execution": {
"jobId": "test",
"status": "QUEUED",
"queuedAt": 1587036256,
"lastUpdatedAt": 1587036256,
"versionNumber": 1,
"executionNumber": 1,
"jobDocument": {
"test_job": {
"operation": "test",
"somerandomkey": "random_value"
}
}
}
}"#;
let (response, _) =
from_slice::<DescribeJobExecutionResponse<JobDetails>>(payload).unwrap();
assert_eq!(
response,
DescribeJobExecutionResponse {
execution: Some(JobExecution {
execution_number: Some(1),
job_document: Some(JobDetails::TestJob(TestJob {
operation: "test",
somerandomkey: "random_value"
})),
job_id: "test",
last_updated_at: 1587036256,
queued_at: 1587036256,
status_details: None,
status: JobStatus::Queued,
version_number: 1,
approximate_seconds_before_timed_out: None,
started_at: None,
thing_name: None,
}),
timestamp: 1587381778,
client_token: Some("0:client_name"),
}
);
}
}