@@ -291,3 +291,134 @@ impl WorkerTuner for TunerHolder {
291291 self . nexus_supplier . clone ( )
292292 }
293293}
294+
295+ #[ cfg( test) ]
296+ mod tests {
297+ use super :: * ;
298+ use std:: time:: Duration ;
299+ use temporal_sdk_core_api:: worker:: { SlotMarkUsedContext , SlotReleaseContext , SlotReservationContext , SlotSupplierPermit } ;
300+
301+ struct TestSlotSupplier ;
302+ #[ async_trait:: async_trait]
303+ impl SlotSupplier for TestSlotSupplier {
304+ type SlotKind = NexusSlotKind ;
305+ async fn reserve_slot ( & self , _: & dyn SlotReservationContext ) -> SlotSupplierPermit {
306+ SlotSupplierPermit :: default ( )
307+ }
308+ fn try_reserve_slot ( & self , _: & dyn SlotReservationContext ) -> Option < SlotSupplierPermit > {
309+ Some ( SlotSupplierPermit :: default ( ) )
310+ }
311+ fn mark_slot_used ( & self , _: & dyn SlotMarkUsedContext < SlotKind = Self :: SlotKind > ) { }
312+ fn release_slot ( & self , _: & dyn SlotReleaseContext < SlotKind = Self :: SlotKind > ) { }
313+ }
314+
315+ #[ test]
316+ fn tuner_holder_options_nexus_fixed_size ( ) {
317+ let options = TunerHolderOptions {
318+ workflow_slot_options : None ,
319+ activity_slot_options : None ,
320+ local_activity_slot_options : None ,
321+ nexus_slot_options : Some ( SlotSupplierOptions :: FixedSize { slots : 50 } ) ,
322+ resource_based_options : None ,
323+ } ;
324+
325+ let tuner = options. build_tuner_holder ( ) . unwrap ( ) ;
326+ // The tuner is built successfully with fixed size nexus slots
327+ let _ = tuner. nexus_task_slot_supplier ( ) ;
328+ }
329+
330+ #[ test]
331+ fn tuner_holder_options_nexus_resource_based ( ) {
332+ let resource_opts = ResourceBasedSlotsOptionsBuilder :: default ( )
333+ . target_mem_usage ( 0.8 )
334+ . target_cpu_usage ( 0.9 )
335+ . build ( )
336+ . unwrap ( ) ;
337+
338+ let options = TunerHolderOptions {
339+ workflow_slot_options : None ,
340+ activity_slot_options : None ,
341+ local_activity_slot_options : None ,
342+ nexus_slot_options : Some ( SlotSupplierOptions :: ResourceBased (
343+ ResourceSlotOptions :: new ( 5 , 100 , Duration :: from_millis ( 100 ) )
344+ ) ) ,
345+ resource_based_options : Some ( resource_opts) ,
346+ } ;
347+
348+ let tuner = options. build_tuner_holder ( ) . unwrap ( ) ;
349+ // The tuner is built successfully with resource-based nexus slots
350+ let _ = tuner. nexus_task_slot_supplier ( ) ;
351+ }
352+
353+ #[ test]
354+ fn tuner_holder_options_nexus_custom ( ) {
355+ let custom_supplier: Arc < dyn SlotSupplier < SlotKind = NexusSlotKind > + Send + Sync > =
356+ Arc :: new ( TestSlotSupplier ) ;
357+
358+ let options = TunerHolderOptions {
359+ workflow_slot_options : None ,
360+ activity_slot_options : None ,
361+ local_activity_slot_options : None ,
362+ nexus_slot_options : Some ( SlotSupplierOptions :: Custom ( custom_supplier. clone ( ) ) ) ,
363+ resource_based_options : None ,
364+ } ;
365+
366+ let tuner = options. build_tuner_holder ( ) . unwrap ( ) ;
367+ // The tuner is built successfully with custom nexus slots
368+ let _ = tuner. nexus_task_slot_supplier ( ) ;
369+ }
370+
371+ #[ test]
372+ fn tuner_builder_with_nexus_slot_supplier ( ) {
373+ let mut builder = TunerBuilder :: default ( ) ;
374+ let custom_supplier: Arc < dyn SlotSupplier < SlotKind = NexusSlotKind > + Send + Sync > =
375+ Arc :: new ( FixedSizeSlotSupplier :: new ( 25 ) ) ;
376+
377+ builder. nexus_slot_supplier ( custom_supplier. clone ( ) ) ;
378+ let tuner = builder. build ( ) ;
379+
380+ // The tuner is built successfully with the custom nexus slot supplier
381+ let _ = tuner. nexus_task_slot_supplier ( ) ;
382+ }
383+
384+ #[ test]
385+ fn tuner_holder_options_builder_validates_resource_based_requirements ( ) {
386+ // Should fail when nexus uses ResourceBased but resource_based_options is not set
387+ let result = TunerHolderOptionsBuilder :: default ( )
388+ . nexus_slot_options ( SlotSupplierOptions :: ResourceBased (
389+ ResourceSlotOptions :: new ( 5 , 100 , Duration :: from_millis ( 100 ) )
390+ ) )
391+ . build ( ) ;
392+
393+ assert ! ( result. is_err( ) ) ;
394+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "resource_based_options" ) ) ;
395+ }
396+
397+ #[ test]
398+ fn tuner_holder_options_all_slot_types ( ) {
399+ let resource_opts = ResourceBasedSlotsOptionsBuilder :: default ( )
400+ . target_mem_usage ( 0.8 )
401+ . target_cpu_usage ( 0.9 )
402+ . build ( )
403+ . unwrap ( ) ;
404+
405+ let options = TunerHolderOptions {
406+ workflow_slot_options : Some ( SlotSupplierOptions :: FixedSize { slots : 10 } ) ,
407+ activity_slot_options : Some ( SlotSupplierOptions :: FixedSize { slots : 20 } ) ,
408+ local_activity_slot_options : Some ( SlotSupplierOptions :: ResourceBased (
409+ ResourceSlotOptions :: new ( 2 , 50 , Duration :: from_millis ( 100 ) )
410+ ) ) ,
411+ nexus_slot_options : Some ( SlotSupplierOptions :: ResourceBased (
412+ ResourceSlotOptions :: new ( 5 , 100 , Duration :: from_millis ( 100 ) )
413+ ) ) ,
414+ resource_based_options : Some ( resource_opts) ,
415+ } ;
416+
417+ let tuner = options. build_tuner_holder ( ) . unwrap ( ) ;
418+ // All suppliers should be successfully configured
419+ let _ = tuner. workflow_task_slot_supplier ( ) ;
420+ let _ = tuner. activity_task_slot_supplier ( ) ;
421+ let _ = tuner. local_activity_slot_supplier ( ) ;
422+ let _ = tuner. nexus_task_slot_supplier ( ) ;
423+ }
424+ }
0 commit comments