1use crate::error::{ErrorCode, ErrorEnvelope};
6use serde_json::json;
7
8pub fn map_worker_error(worker_code: &str, message: &str) -> ErrorEnvelope {
12 let code = match worker_code {
13 "PROGRAM_NOT_OPEN" => ErrorCode::ProgramNotOpen,
14 "PROGRAM_NOT_FOUND" => ErrorCode::ProgramNotFound,
15 "NOT_A_FUNCTION" => ErrorCode::NotAFunction,
16 "AMBIGUOUS_SYMBOL" => ErrorCode::AmbiguousSymbol,
17 "INVALID_PARAMS" => ErrorCode::InvalidParams,
18 "DECOMPILE_TIMEOUT" => ErrorCode::DecompileTimeout,
19 "DECOMPILATION_FAILED" => ErrorCode::DecompilationFailed,
20 "FRAME_TOO_LARGE" => ErrorCode::FrameTooLarge,
21 "PARSE_ERROR" => ErrorCode::ParseError,
22 "WORKER_UNAVAILABLE" => ErrorCode::WorkerUnavailable,
23 "SYMBOL_NOT_FOUND" => ErrorCode::SymbolNotFound,
24 "VARIABLE_NOT_FOUND" => ErrorCode::VariableNotFound,
25 "DATATYPE_NOT_FOUND" => ErrorCode::DatatypeNotFound,
26 "AMBIGUOUS_DATATYPE" => ErrorCode::AmbiguousDatatype,
27 "ADDRESS_NOT_FOUND" => ErrorCode::AddressNotFound,
28 "RENAME_CONFLICT" => ErrorCode::RenameConflict,
29 "STATE_CONFLICT" => ErrorCode::StateConflict,
30 "TRANSACTION_FAILED" => ErrorCode::TransactionFailed,
31 unknown => {
32 return ErrorEnvelope::new(ErrorCode::WorkerUnavailable, message.to_string())
33 .with_details(json!({ "worker_code": unknown }));
34 }
35 };
36 ErrorEnvelope::new(code, message.to_string())
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
49 fn every_known_worker_code_maps_to_its_variant() {
50 let cases = [
51 ("PROGRAM_NOT_OPEN", ErrorCode::ProgramNotOpen),
52 ("PROGRAM_NOT_FOUND", ErrorCode::ProgramNotFound),
53 ("NOT_A_FUNCTION", ErrorCode::NotAFunction),
54 ("AMBIGUOUS_SYMBOL", ErrorCode::AmbiguousSymbol),
55 ("INVALID_PARAMS", ErrorCode::InvalidParams),
56 ("DECOMPILE_TIMEOUT", ErrorCode::DecompileTimeout),
57 ("DECOMPILATION_FAILED", ErrorCode::DecompilationFailed),
58 ("FRAME_TOO_LARGE", ErrorCode::FrameTooLarge),
59 ("PARSE_ERROR", ErrorCode::ParseError),
60 ("WORKER_UNAVAILABLE", ErrorCode::WorkerUnavailable),
61 ("SYMBOL_NOT_FOUND", ErrorCode::SymbolNotFound),
62 ("VARIABLE_NOT_FOUND", ErrorCode::VariableNotFound),
63 ("DATATYPE_NOT_FOUND", ErrorCode::DatatypeNotFound),
64 ("AMBIGUOUS_DATATYPE", ErrorCode::AmbiguousDatatype),
65 ("ADDRESS_NOT_FOUND", ErrorCode::AddressNotFound),
66 ("RENAME_CONFLICT", ErrorCode::RenameConflict),
67 ];
68 for (s, want) in cases {
69 assert_eq!(map_worker_error(s, "m").error.code, want, "code {s}");
70 }
71 }
72
73 #[test]
74 fn unknown_code_falls_back_and_preserves_raw_string() {
75 let env = map_worker_error("SOME_FUTURE_CODE", "boom");
76 assert_eq!(env.error.code, ErrorCode::WorkerUnavailable);
77 assert_eq!(env.error.message, "boom");
78 assert_eq!(
79 env.error.details.unwrap()["worker_code"],
80 "SOME_FUTURE_CODE"
81 );
82 }
83
84 #[test]
85 fn state_conflict_and_transaction_failed_map_to_typed_codes() {
86 use crate::error::ErrorCode;
87 assert_eq!(
88 super::map_worker_error("STATE_CONFLICT", "drift")
89 .error
90 .code,
91 ErrorCode::StateConflict
92 );
93 assert_eq!(
94 super::map_worker_error("TRANSACTION_FAILED", "rolled back")
95 .error
96 .code,
97 ErrorCode::TransactionFailed
98 );
99 }
100}