@@ -402,10 +402,10 @@ func TestStore_KubernetesSecretRotation(t *testing.T) {
402402 // Create a temporary directory to simulate K8s secret mount
403403 tmpDir := t .TempDir ()
404404
405- // Create initial secret file
405+ // Create initial secret file using the atomic writer pattern (like Kubernetes)
406406 secretFile := filepath .Join (tmpDir , "tls.crt" )
407407 initialContent := []byte ("initial-cert-content" )
408- err := os . WriteFile ( secretFile , initialContent , 0o644 )
408+ err := atomicWriteFile ( tmpDir , "tls.crt" , initialContent )
409409 require .NoError (t , err )
410410
411411 // Create store and add the file
@@ -424,31 +424,74 @@ func TestStore_KubernetesSecretRotation(t *testing.T) {
424424 require .True (t , exists )
425425 require .Equal (t , initialContent , content )
426426
427- // Simulate Kubernetes secret rotation:
428- // 1. Remove the file (this sends a REMOVE event)
429- err = os .Remove (secretFile )
430- require .NoError (t , err )
427+ // Add a small delay to ensure the file system watcher is ready
428+ time .Sleep (100 * time .Millisecond )
431429
432- // 2. Create new file with updated content (simulating symlink update)
430+ // Simulate Kubernetes secret rotation using atomic operations
433431 newContent := []byte ("rotated-cert-content" )
434- err = os . WriteFile ( secretFile , newContent , 0o644 )
432+ err = atomicWriteFile ( tmpDir , "tls.crt" , newContent )
435433 require .NoError (t , err )
436434
437- // Wait for rotation event
435+ // Wait for rotation event with more robust event handling
438436 var rotationEvent RotationEvent
439- select {
440- case rotationEvent = <- store .RotationEvents ():
441- assert .Equal (t , secretFile , rotationEvent .Path )
442- case err := <- store .Errors ():
443- t .Fatalf ("Unexpected error during rotation: %v" , err )
444- case <- time .After (2 * time .Second ):
445- t .Fatal ("No rotation event received within timeout" )
437+ var gotRotationEvent bool
438+
439+ // We might get multiple events, so we need to handle them properly
440+ timeout := time .After (5 * time .Second )
441+ for ! gotRotationEvent {
442+ select {
443+ case rotationEvent = <- store .RotationEvents ():
444+ if rotationEvent .Path == secretFile {
445+ gotRotationEvent = true
446+ }
447+ // Continue if we got an event for a different file (shouldn't happen in this test)
448+ case err := <- store .Errors ():
449+ t .Fatalf ("Unexpected error during rotation: %v" , err )
450+ case <- timeout :
451+ t .Fatal ("No rotation event received within timeout" )
452+ }
446453 }
447454
448- // Verify content was updated
449- content , exists = store .GetContent (secretFile )
450- require .True (t , exists )
451- require .Equal (t , newContent , content )
455+ assert .Equal (t , secretFile , rotationEvent .Path )
456+
457+ // Verify content was updated with eventual consistency
458+ assert .Eventually (t , func () bool {
459+ content , exists := store .GetContent (secretFile )
460+ return exists && string (content ) == string (newContent )
461+ }, 1 * time .Second , 50 * time .Millisecond , "Content should be updated after rotation" )
462+ }
463+
464+ // atomicWriteFile simulates how Kubernetes writes files atomically
465+ // This is a simplified version that focuses on the filesystem events that matter for testing
466+ func atomicWriteFile (targetDir , filename string , data []byte ) error {
467+ targetFile := filepath .Join (targetDir , filename )
468+
469+ // Check if target exists
470+ _ , err := os .Stat (targetFile )
471+ targetExists := err == nil
472+
473+ if targetExists {
474+ // For existing files, write to a temp file first, then do atomic rename
475+ tempFile := targetFile + ".tmp"
476+
477+ // Write new content to temp file
478+ if err := os .WriteFile (tempFile , data , 0o644 ); err != nil {
479+ return fmt .Errorf ("failed to write temp file: %w" , err )
480+ }
481+
482+ // Atomic rename (this is the key operation that generates the filesystem events)
483+ if err := os .Rename (tempFile , targetFile ); err != nil {
484+ os .Remove (tempFile ) // cleanup on failure
485+ return fmt .Errorf ("failed to rename temp file: %w" , err )
486+ }
487+ } else {
488+ // For new files, just write directly
489+ if err := os .WriteFile (targetFile , data , 0o644 ); err != nil {
490+ return fmt .Errorf ("failed to write file: %w" , err )
491+ }
492+ }
493+
494+ return nil
452495}
453496
454497func TestStore_RealFileDeletion (t * testing.T ) {
0 commit comments