@@ -284,19 +284,30 @@ async fn multi_args_serializes_as_multiple_payloads() {
284284/// A codec that XORs payload data with a key and tracks encode/decode operations.
285285struct XorCodec {
286286 key : u8 ,
287+ gate_on_metadata : bool ,
287288 encode_count : AtomicUsize ,
288289 decode_count : AtomicUsize ,
289290}
290291
291292impl XorCodec {
292293 fn new ( key : u8 ) -> Self {
293294 Self {
295+ gate_on_metadata : true ,
294296 key,
295297 encode_count : AtomicUsize :: new ( 0 ) ,
296298 decode_count : AtomicUsize :: new ( 0 ) ,
297299 }
298300 }
299301
302+ fn new_with_metadata_gate ( key : u8 , gate_on_metadata : bool ) -> Self {
303+ Self {
304+ key,
305+ gate_on_metadata,
306+ encode_count : AtomicUsize :: new ( 0 ) ,
307+ decode_count : AtomicUsize :: new ( 0 ) ,
308+ }
309+ }
310+
300311 fn encode_count ( & self ) -> usize {
301312 self . encode_count . load ( Ordering :: SeqCst )
302313 }
@@ -316,12 +327,15 @@ impl PayloadCodec for XorCodec {
316327 eprintln ! ( "XorCodec::encode called with {} payloads" , count) ;
317328 self . encode_count . fetch_add ( count, Ordering :: SeqCst ) ;
318329 let key = self . key ;
330+ let gate_on_metadata = self . gate_on_metadata ;
319331 async move {
320332 payloads
321333 . into_iter ( )
322334 . map ( |mut p| {
323335 p. data = p. data . iter ( ) . map ( |b| b ^ key) . collect ( ) ;
324- p. metadata . insert ( "xor_encoded" . to_string ( ) , vec ! [ key] ) ;
336+ if gate_on_metadata {
337+ p. metadata . insert ( "xor_encoded" . to_string ( ) , vec ! [ key] ) ;
338+ }
325339 p
326340 } )
327341 . collect ( )
@@ -338,11 +352,12 @@ impl PayloadCodec for XorCodec {
338352 eprintln ! ( "XorCodec::decode called with {} payloads" , count) ;
339353 self . decode_count . fetch_add ( count, Ordering :: SeqCst ) ;
340354 let key = self . key ;
355+ let gate_on_metadata = self . gate_on_metadata ;
341356 async move {
342357 payloads
343358 . into_iter ( )
344359 . map ( |mut p| {
345- if p. metadata . remove ( "xor_encoded" ) . is_some ( ) {
360+ if !gate_on_metadata || p. metadata . remove ( "xor_encoded" ) . is_some ( ) {
346361 p. data = p. data . iter ( ) . map ( |b| b ^ key) . collect ( ) ;
347362 }
348363 p
@@ -464,6 +479,77 @@ async fn describe_decodes_workflow_payload_fields() {
464479 desc. memo( ) . unwrap( ) . fields[ "tracked" ] ,
465480 "codec-describe" . as_json_payload( ) . unwrap( )
466481 ) ;
482+ let raw_user_metadata = desc
483+ . raw_description
484+ . execution_config
485+ . as_ref ( )
486+ . and_then ( |cfg| cfg. user_metadata . as_ref ( ) )
487+ . expect ( "describe response should include user metadata" ) ;
488+ assert_eq ! (
489+ raw_user_metadata. summary,
490+ Some ( "codec summary" . as_json_payload( ) . unwrap( ) )
491+ ) ;
492+ assert_eq ! (
493+ raw_user_metadata. details,
494+ Some ( "codec details" . as_json_payload( ) . unwrap( ) )
495+ ) ;
496+ assert_eq ! ( desc. static_summary( ) , Some ( "codec summary" ) ) ;
497+ assert_eq ! ( desc. static_details( ) , Some ( "codec details" ) ) ;
498+ }
499+
500+ #[ tokio:: test]
501+ async fn describe_decodes_user_metadata_with_ungated_xor_codec ( ) {
502+ let wf_name = DescribeDataConverterWorkflow :: name ( ) ;
503+ let codec = Arc :: new ( XorCodec :: new_with_metadata_gate ( 0x42 , false ) ) ;
504+
505+ let connection = get_integ_connection ( None ) . await ;
506+ let data_converter = DataConverter :: new (
507+ PayloadConverter :: default ( ) ,
508+ DefaultFailureConverter ,
509+ codec. clone ( ) ,
510+ ) ;
511+ let client_opts = ClientOptions :: new ( integ_namespace ( ) )
512+ . data_converter ( data_converter)
513+ . build ( ) ;
514+ let client = Client :: new ( connection, client_opts) . unwrap ( ) ;
515+
516+ let mut starter = CoreWfStarter :: new_with_overrides ( wf_name, None , Some ( client) ) ;
517+ starter. sdk_config . register_activities ( TestActivities ) ;
518+ starter. sdk_config . task_types = WorkerTaskTypes :: all ( ) ;
519+ starter
520+ . sdk_config
521+ . register_workflow :: < DescribeDataConverterWorkflow > ( ) ;
522+ let wf_id = starter. get_task_queue ( ) . to_owned ( ) ;
523+ let mut worker = starter. worker ( ) . await ;
524+
525+ let handle = worker
526+ . submit_workflow (
527+ DescribeDataConverterWorkflow :: run,
528+ TrackedWrapper ( TrackedValue :: new ( "codec-describe" . to_string ( ) ) ) ,
529+ WorkflowStartOptions :: new ( starter. get_task_queue ( ) , wf_id)
530+ . static_summary ( "codec summary" )
531+ . static_details ( "codec details" )
532+ . build ( ) ,
533+ )
534+ . await
535+ . unwrap ( ) ;
536+ worker. run_until_done ( ) . await . unwrap ( ) ;
537+
538+ let decode_count_before = codec. decode_count ( ) ;
539+ let desc = handle
540+ . describe ( WorkflowDescribeOptions :: default ( ) )
541+ . await
542+ . unwrap ( ) ;
543+
544+ assert ! (
545+ codec. decode_count( ) > decode_count_before,
546+ "Describe should have decoded response payloads"
547+ ) ;
548+ assert_eq ! (
549+ desc. memo( ) . unwrap( ) . fields[ "tracked" ] ,
550+ "codec-describe" . as_json_payload( ) . unwrap( )
551+ ) ;
552+ // Making sure codec isn't used when decoding user metadata
467553 assert_eq ! ( desc. static_summary( ) , Some ( "codec summary" ) ) ;
468554 assert_eq ! ( desc. static_details( ) , Some ( "codec details" ) ) ;
469555}
0 commit comments