11mod  common; 
22
3+ use  base64:: Engine ; 
34use  serde_json:: json; 
45
6+ const  MAX_INPUT_SIZE :  usize  = rivet_util:: file_size:: mebibytes ( 4 )  as  usize ; 
7+ 
58// MARK: Basic 
69#[ test]  
710fn  create_actor_valid_namespace ( )  { 
@@ -169,13 +172,14 @@ fn create_actor_specific_datacenter() {
169172		let  actor_id = common:: create_actor_with_options ( 
170173			common:: CreateActorOptions  { 
171174				namespace :  namespace. clone ( ) , 
172- 				datacenter :  Some ( "dc-2" . to_string ( ) ) , 
173175				..Default :: default ( ) 
174176			} , 
175- 			ctx. leader_dc ( ) . guard_port ( ) , 
177+ 			ctx. get_dc ( 2 ) . guard_port ( ) , 
176178		) 
177179		. await ; 
178180
181+ 		common:: wait_for_actor_propagation ( & "foo" ,  1 ) . await ; 
182+ 
179183		assert ! ( !actor_id. is_empty( ) ,  "Actor ID should not be empty" ) ; 
180184
181185		let  actor =
@@ -196,7 +200,6 @@ fn create_actor_current_datacenter() {
196200		let  actor_id = common:: create_actor_with_options ( 
197201			common:: CreateActorOptions  { 
198202				namespace :  namespace. clone ( ) , 
199- 				datacenter :  None , 
200203				..Default :: default ( ) 
201204			} , 
202205			ctx. leader_dc ( ) . guard_port ( ) , 
@@ -223,42 +226,31 @@ fn create_actor_non_existent_namespace() {
223226	} ) ; 
224227} 
225228
226- #[ test]  
227- #[ should_panic( expected = "Failed to create actor" ) ]  
228- fn  create_actor_invalid_datacenter ( )  { 
229- 	common:: run ( common:: TestOpts :: new ( 1 ) ,  |ctx| async  move  { 
230- 		let  ( namespace,  _,  _runner)  =
231- 			common:: setup_test_namespace_with_runner ( ctx. leader_dc ( ) ) . await ; 
232- 
233- 		common:: create_actor_with_options ( 
234- 			common:: CreateActorOptions  { 
235- 				namespace :  namespace. clone ( ) , 
236- 				datacenter :  Some ( "invalid-dc" . to_string ( ) ) , 
237- 				..Default :: default ( ) 
238- 			} , 
239- 			ctx. leader_dc ( ) . guard_port ( ) , 
240- 		) 
241- 		. await ; 
242- 	} ) ; 
243- } 
244- 
245229#[ test]  
246230fn  create_actor_malformed_input ( )  { 
247231	common:: run ( common:: TestOpts :: new ( 1 ) ,  |ctx| async  move  { 
248232		let  ( namespace,  _,  _runner)  =
249233			common:: setup_test_namespace_with_runner ( ctx. leader_dc ( ) ) . await ; 
250234
251- 		let  actor_id = common:: create_actor_with_options ( 
252- 			common:: CreateActorOptions  { 
253- 				namespace :  namespace. clone ( ) , 
254- 				input :  Some ( "not-valid-base64!@#$%" . to_string ( ) ) , 
255- 				..Default :: default ( ) 
256- 			} , 
257- 			ctx. leader_dc ( ) . guard_port ( ) , 
258- 		) 
259- 		. await ; 
235+ 		let  client = reqwest:: Client :: new ( ) ; 
236+ 		let  response = client
237+ 			. post ( & format ! ( 
238+ 				"http://127.0.0.1:{}/actors?namespace={}" , 
239+ 				ctx. leader_dc( ) . guard_port( ) , 
240+ 				namespace
241+ 			) ) 
242+ 			. json ( & serde_json:: json!( { 
243+ 				"name" :  "test" , 
244+ 				"input" :  "not-valid-base64!@#$%" , 
245+ 			} ) ) 
246+ 			. send ( ) 
247+ 			. await 
248+ 			. expect ( "Failed to send request" ) ; 
260249
261- 		assert ! ( !actor_id. is_empty( ) ,  "Actor ID should not be empty" ) ; 
250+ 		assert ! ( 
251+ 			!response. status( ) . is_success( ) , 
252+ 			"Should fail with invalid base64 input" 
253+ 		) ; 
262254	} ) ; 
263255} 
264256
@@ -269,17 +261,17 @@ fn create_actor_remote_datacenter_verify() {
269261		let  ( namespace,  _,  _runner)  =
270262			common:: setup_test_namespace_with_runner ( ctx. leader_dc ( ) ) . await ; 
271263
264+ 		// common::wait_for_actor_propagation(&"", 1).await; 
272265		let  actor_id = common:: create_actor_with_options ( 
273266			common:: CreateActorOptions  { 
274267				namespace :  namespace. clone ( ) , 
275- 				datacenter :  Some ( "dc-2" . to_string ( ) ) , 
276268				..Default :: default ( ) 
277269			} , 
278- 			ctx. leader_dc ( ) . guard_port ( ) , 
270+ 			ctx. get_dc ( 2 ) . guard_port ( ) , 
279271		) 
280272		. await ; 
281273
282- 		common:: wait_for_actor_propagation ( & actor_id,  1 ) . await ; 
274+ 		//  common::wait_for_actor_propagation(&actor_id, 1).await;
283275
284276		let  actor =
285277			common:: assert_actor_exists ( & actor_id,  & namespace,  ctx. get_dc ( 2 ) . guard_port ( ) ) . await ; 
@@ -290,6 +282,34 @@ fn create_actor_remote_datacenter_verify() {
290282	} ) ; 
291283} 
292284
285+ // MARK: Namespace validation 
286+ #[ test]  
287+ fn  create_actor_namespace_validation ( )  { 
288+ 	common:: run ( common:: TestOpts :: new ( 1 ) ,  |ctx| async  move  { 
289+ 		let  non_existent_ns = "non-existent-namespace" ; 
290+ 		let  api_port = ctx. leader_dc ( ) . guard_port ( ) ; 
291+ 		let  client = reqwest:: Client :: new ( ) ; 
292+ 
293+ 		// POST /actors 
294+ 		let  response = client
295+ 			. post ( & format ! ( 
296+ 				"http://127.0.0.1:{}/actors?namespace={}" , 
297+ 				api_port,  non_existent_ns
298+ 			) ) 
299+ 			. json ( & json ! ( { 
300+ 				"name" :  "test" , 
301+ 				"key" :  "key" , 
302+ 			} ) ) 
303+ 			. send ( ) 
304+ 			. await 
305+ 			. expect ( "Failed to send request" ) ; 
306+ 		assert ! ( 
307+ 			!response. status( ) . is_success( ) , 
308+ 			"POST /actors should fail with non-existent namespace" 
309+ 		) ; 
310+ 	} ) ; 
311+ } 
312+ 
293313// MARK: Edge cases 
294314
295315#[ test]  
@@ -353,15 +373,70 @@ fn empty_strings_for_required_parameters() {
353373	} ) ; 
354374} 
355375
376+ 
377+ #[ test]  
378+ fn  test_long_strings_for_input ( )  { 
379+ 	common:: run ( common:: TestOpts :: new ( 1 ) ,  |ctx| async  move  { 
380+ 		let  ( namespace,  _,  _runner)  =
381+ 			common:: setup_test_namespace_with_runner ( ctx. leader_dc ( ) ) . await ; 
382+ 
383+ 		let  client = reqwest:: Client :: new ( ) ; 
384+ 
385+ 		// Test different base64 encoded inputs 
386+ 		let  large_string = "A" . repeat ( MAX_INPUT_SIZE  + 1 ) ; 
387+ 		let  base64_tests = vec ! [ 
388+ 			( "normal" ,  "AAAA" ,  true ) , 
389+ 			( "very-large" ,  rivet_util:: safe_slice( & large_string,  0 ,  MAX_INPUT_SIZE -1 ) ,  true ) ,  // Within bounds 
390+ 			( "too-large" ,  & large_string,  false ) ,  // Out of bounds base64 string 
391+ 		] ; 
392+ 
393+ 		for  ( name,  base64_input,  should_work)  in  base64_tests { 
394+ 			let  response = client
395+ 				. post ( & format ! ( 
396+ 					"http://127.0.0.1:{}/actors?namespace={}" , 
397+ 					ctx. leader_dc( ) . guard_port( ) , 
398+ 					namespace
399+ 				) ) 
400+ 				. json ( & json ! ( { 
401+ 					"name" :  format!( "base64-{}" ,  name) , 
402+ 					"input" :  base64_input, 
403+ 					"runner_name_selector" :  "foo" , 
404+ 					"crash_policy" :  "destroy" , 
405+ 				} ) ) 
406+ 				. send ( ) 
407+ 				. await 
408+ 				. expect ( & format ! ( "Failed to send request for {}" ,  name) ) ; 
409+ 
410+ 			if  should_work && base64:: engine:: general_purpose:: STANDARD . decode ( base64_input) . is_ok ( )  { 
411+ 				// Valid base64 should work 
412+ 				assert ! ( 
413+ 					response. status( ) . is_success( ) , 
414+ 					"Valid base64 '{}' should succeed, but instead got {}" , 
415+ 					name, 
416+ 					response. text( ) . await . unwrap( ) 
417+ 				) ; 
418+ 			}  else  { 
419+ 				// Invalid base64 should fail 
420+ 				assert ! ( 
421+ 					!response. status( ) . is_success( ) , 
422+ 					"Invalid base64 '{}' should fail" , 
423+ 					name
424+ 				) ; 
425+ 			} 
426+ 		} 
427+ 	} ) ; 
428+ } 
429+ 
430+ 
356431#[ test]  
357432fn  very_long_strings_for_names_and_key ( )  { 
358433	common:: run ( common:: TestOpts :: new ( 1 ) ,  |ctx| async  move  { 
359434		let  ( namespace,  _,  _runner)  =
360435			common:: setup_test_namespace_with_runner ( ctx. leader_dc ( ) ) . await ; 
361436
362- 		// Create very long  name and key (should work up to reasonable limits ) 
363- 		let  long_name = "a" . repeat ( 255 ) ;  // 255  chars should be acceptable 
364- 		let  long_key = "k" . repeat ( 255 ) ; 
437+ 		// Create name and key with exactly 32 chars (should work ) 
438+ 		let  long_name = "a" . repeat ( 32 ) ;  // 32  chars should be acceptable 
439+ 		let  long_key = "k" . repeat ( 32 ) ; 
365440
366441		let  actor_id = common:: create_actor_with_options ( 
367442			common:: CreateActorOptions  { 
@@ -380,8 +455,8 @@ fn very_long_strings_for_names_and_key() {
380455		assert_eq ! ( actor[ "actor" ] [ "name" ] ,  long_name) ; 
381456		assert_eq ! ( actor[ "actor" ] [ "key" ] ,  long_key) ; 
382457
383- 		// Try extremely long name  (should fail) 
384- 		let  too_long_name = "a" . repeat ( 1000 ) ; 
458+ 		// Try name with 33 chars  (should fail) 
459+ 		let  too_long_name = "a" . repeat ( 33 ) ; 
385460		let  client = reqwest:: Client :: new ( ) ; 
386461		let  response = client
387462			. post ( & format ! ( 
@@ -398,12 +473,33 @@ fn very_long_strings_for_names_and_key() {
398473			. expect ( "Failed to send request" ) ; 
399474		assert ! ( 
400475			!response. status( ) . is_success( ) , 
401- 			"Should fail with extremely long name" 
476+ 			"Should fail with 33-character name" 
477+ 		) ; 
478+ 
479+ 		// Try key with 33 chars (should fail) 
480+ 		let  too_long_key = "k" . repeat ( 33 ) ; 
481+ 		let  response = client
482+ 			. post ( & format ! ( 
483+ 				"http://127.0.0.1:{}/actors?namespace={}" , 
484+ 				ctx. leader_dc( ) . guard_port( ) , 
485+ 				namespace
486+ 			) ) 
487+ 			. json ( & json ! ( { 
488+ 				"name" :  "test" , 
489+ 				"key" :  too_long_key, 
490+ 			} ) ) 
491+ 			. send ( ) 
492+ 			. await 
493+ 			. expect ( "Failed to send request" ) ; 
494+ 		assert ! ( 
495+ 			!response. status( ) . is_success( ) , 
496+ 			"Should fail with 33-character key" 
402497		) ; 
403498	} ) ; 
404499} 
405500
406501#[ test]  
502+ #[ ignore]  
407503fn  special_characters_in_names_and_keys ( )  { 
408504	common:: run ( common:: TestOpts :: new ( 1 ) ,  |ctx| async  move  { 
409505		let  ( namespace,  _,  _runner)  =
@@ -522,3 +618,120 @@ fn maximum_limits_32_actor_ids_in_list() {
522618		) ; 
523619	} ) ; 
524620} 
621+ 
622+ // MARK: Key collision tests 
623+ 
624+ #[ test]  
625+ fn  create_destroy_create_destroy_same_key_single_dc ( )  { 
626+ 	common:: run ( common:: TestOpts :: new ( 2 ) ,  |ctx| async  move  { 
627+ 		create_destroy_create_destroy_same_key_inner ( ctx. leader_dc ( ) ,  ctx. leader_dc ( ) ) . await ; 
628+ 	} ) ; 
629+ } 
630+ 
631+ #[ test]  
632+ #[ ignore]  
633+ fn  create_destroy_create_destroy_same_key_multi_dc ( )  { 
634+ 	common:: run ( common:: TestOpts :: new ( 2 ) ,  |ctx| async  move  { 
635+ 		create_destroy_create_destroy_same_key_inner ( ctx. get_dc ( 2 ) ,  ctx. get_dc ( 2 ) ) . await ; 
636+ 	} ) ; 
637+ } 
638+ 
639+ #[ test]  
640+ #[ ignore]  
641+ fn  create_destroy_create_destroy_same_key_different_dc ( )  { 
642+ 	common:: run ( common:: TestOpts :: new ( 2 ) ,  |ctx| async  move  { 
643+ 		create_destroy_create_destroy_same_key_inner ( ctx. leader_dc ( ) ,  ctx. get_dc ( 2 ) ) . await ; 
644+ 	} ) ; 
645+ } 
646+ 
647+ async  fn  create_destroy_create_destroy_same_key_inner ( 
648+ 	target_dc1 :  & common:: TestDatacenter , 
649+ 	target_dc2 :  & common:: TestDatacenter , 
650+ )  { 
651+ 	let  ( namespace,  _,  runner)  = common:: setup_test_namespace_with_runner ( target_dc1) . await ; 
652+ 	let  key = rand:: random :: < u16 > ( ) . to_string ( ) ; 
653+ 
654+ 	// First create/destroy cycle 
655+ 	let  actor_id1 = common:: create_actor_with_options ( 
656+ 		common:: CreateActorOptions  { 
657+ 			namespace :  namespace. clone ( ) , 
658+ 			key :  Some ( key. clone ( ) ) , 
659+ 			..Default :: default ( ) 
660+ 		} , 
661+ 		target_dc1. guard_port ( ) , 
662+ 	) 
663+ 	. await ; 
664+ 
665+ 	common:: assert_actor_in_dc ( & actor_id1,  target_dc1. config . dc_label ( ) ) . await ; 
666+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
667+ 
668+ 	// Destroy first actor 
669+ 	tracing:: info!( ?actor_id1,  "destroying first actor" ) ; 
670+ 	common:: destroy_actor ( & actor_id1,  & namespace,  target_dc1. guard_port ( ) ) . await ; 
671+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
672+ 
673+ 	// Second create/destroy cycle with same key 
674+ 	let  actor_id2 = common:: create_actor_with_options ( 
675+ 		common:: CreateActorOptions  { 
676+ 			namespace :  namespace. clone ( ) , 
677+ 			key :  Some ( key. clone ( ) ) , 
678+ 			..Default :: default ( ) 
679+ 		} , 
680+ 		target_dc2. guard_port ( ) , 
681+ 	) 
682+ 	. await ; 
683+ 
684+ 	assert_ne ! ( actor_id1,  actor_id2,  "same actor id after first cycle" ) ; 
685+ 	common:: assert_actor_in_dc ( & actor_id2,  target_dc1. config . dc_label ( ) ) . await ; 
686+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
687+ 
688+ 	// Destroy second actor 
689+ 	tracing:: info!( ?actor_id2,  "destroying second actor" ) ; 
690+ 	common:: destroy_actor ( & actor_id2,  & namespace,  target_dc2. guard_port ( ) ) . await ; 
691+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
692+ 
693+ 	// Third create/destroy cycle with same key 
694+ 	let  actor_id3 = common:: create_actor_with_options ( 
695+ 		common:: CreateActorOptions  { 
696+ 			namespace :  namespace. clone ( ) , 
697+ 			key :  Some ( key. clone ( ) ) , 
698+ 			..Default :: default ( ) 
699+ 		} , 
700+ 		target_dc1. guard_port ( ) , 
701+ 	) 
702+ 	. await ; 
703+ 
704+ 	assert_ne ! ( actor_id1,  actor_id3,  "same actor id after second cycle (vs first)" ) ; 
705+ 	assert_ne ! ( actor_id2,  actor_id3,  "same actor id after second cycle (vs second)" ) ; 
706+ 	common:: assert_actor_in_dc ( & actor_id3,  target_dc1. config . dc_label ( ) ) . await ; 
707+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
708+ 
709+ 	// Destroy third actor 
710+ 	tracing:: info!( ?actor_id3,  "destroying third actor" ) ; 
711+ 	common:: destroy_actor ( & actor_id3,  & namespace,  target_dc1. guard_port ( ) ) . await ; 
712+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
713+ 
714+ 	// Fourth create/destroy cycle with same key 
715+ 	let  actor_id4 = common:: create_actor_with_options ( 
716+ 		common:: CreateActorOptions  { 
717+ 			namespace :  namespace. clone ( ) , 
718+ 			key :  Some ( key. clone ( ) ) , 
719+ 			..Default :: default ( ) 
720+ 		} , 
721+ 		target_dc2. guard_port ( ) , 
722+ 	) 
723+ 	. await ; 
724+ 
725+ 	assert_ne ! ( actor_id1,  actor_id4,  "same actor id after third cycle (vs first)" ) ; 
726+ 	assert_ne ! ( actor_id2,  actor_id4,  "same actor id after third cycle (vs second)" ) ; 
727+ 	assert_ne ! ( actor_id3,  actor_id4,  "same actor id after third cycle (vs third)" ) ; 
728+ 	common:: assert_actor_in_dc ( & actor_id4,  target_dc1. config . dc_label ( ) ) . await ; 
729+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
730+ 
731+ 	// Final destroy 
732+ 	tracing:: info!( ?actor_id4,  "destroying fourth actor" ) ; 
733+ 	common:: destroy_actor ( & actor_id4,  & namespace,  target_dc2. guard_port ( ) ) . await ; 
734+ 	tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ; 
735+ 
736+ 	runner. shutdown ( ) . await ; 
737+ } 
0 commit comments