@@ -16,6 +16,7 @@ import (
1616 "google.golang.org/grpc/codes"
1717 "google.golang.org/grpc/status"
1818 "google.golang.org/protobuf/types/known/structpb"
19+ "google.golang.org/protobuf/types/known/timestamppb"
1920)
2021
2122// testMinimalUUIDv7 is the test's copy of minimalUUIDv7 from task.go
@@ -663,3 +664,85 @@ func (suite *AttachFunctionTestSuite) TestAttachFunction_IdempotentRequest_Param
663664func TestAttachFunctionTestSuite (t * testing.T ) {
664665 suite .Run (t , new (AttachFunctionTestSuite ))
665666}
667+
668+ // TestGetSoftDeletedAttachedFunctions_TimestampConsistency verifies that timestamps
669+ // are returned in microseconds (UnixMicro) to match other API methods
670+ func TestGetSoftDeletedAttachedFunctions_TimestampConsistency (t * testing.T ) {
671+ ctx := context .Background ()
672+
673+ // Create test timestamps with known values
674+ testTime := time .Date (2025 , 10 , 30 , 12 , 0 , 0 , 123456000 , time .UTC ) // 123.456 milliseconds
675+ expectedMicros := uint64 (testTime .UnixMicro ())
676+
677+ // Create mock coordinator with minimal setup
678+ mockMetaDomain := & dbmodel_mocks.IMetaDomain {}
679+ mockAttachedFunctionDb := & dbmodel_mocks.IAttachedFunctionDb {}
680+ mockMetaDomain .On ("AttachedFunctionDb" , mock .Anything ).Return (mockAttachedFunctionDb )
681+
682+ // Mock the database response with our test timestamps
683+ attachedFunctions := []* dbmodel.AttachedFunction {
684+ {
685+ ID : uuid .New (),
686+ Name : "test_function" ,
687+ InputCollectionID : "collection_123" ,
688+ OutputCollectionName : "output_collection" ,
689+ CompletionOffset : 100 ,
690+ MinRecordsForInvocation : 10 ,
691+ CreatedAt : testTime ,
692+ UpdatedAt : testTime ,
693+ NextRun : testTime ,
694+ },
695+ }
696+
697+ mockAttachedFunctionDb .On ("GetSoftDeletedAttachedFunctions" , mock .Anything , mock .Anything ).
698+ Return (attachedFunctions , nil )
699+
700+ coordinator := & Coordinator {
701+ catalog : Catalog {
702+ metaDomain : mockMetaDomain ,
703+ },
704+ }
705+
706+ // Call GetSoftDeletedAttachedFunctions
707+ cutoffTime := timestamppb .New (testTime .Add (- 24 * time .Hour ))
708+ resp , err := coordinator .GetSoftDeletedAttachedFunctions (ctx , & coordinatorpb.GetSoftDeletedAttachedFunctionsRequest {
709+ CutoffTime : cutoffTime ,
710+ Limit : 100 ,
711+ })
712+
713+ // Verify response
714+ if err != nil {
715+ t .Fatalf ("GetSoftDeletedAttachedFunctions failed: %v" , err )
716+ }
717+ if len (resp .AttachedFunctions ) != 1 {
718+ t .Fatalf ("Expected 1 attached function, got %d" , len (resp .AttachedFunctions ))
719+ }
720+
721+ af := resp .AttachedFunctions [0 ]
722+
723+ // Verify timestamps are in microseconds (not seconds)
724+ if af .CreatedAt != expectedMicros {
725+ t .Errorf ("CreatedAt timestamp mismatch: expected %d microseconds, got %d" , expectedMicros , af .CreatedAt )
726+ }
727+ if af .UpdatedAt != expectedMicros {
728+ t .Errorf ("UpdatedAt timestamp mismatch: expected %d microseconds, got %d" , expectedMicros , af .UpdatedAt )
729+ }
730+ if af .NextRunAt != expectedMicros {
731+ t .Errorf ("NextRunAt timestamp mismatch: expected %d microseconds, got %d" , expectedMicros , af .NextRunAt )
732+ }
733+
734+ // Verify these are NOT in seconds (would be ~1000x smaller)
735+ expectedSeconds := uint64 (testTime .Unix ())
736+ if af .CreatedAt == expectedSeconds {
737+ t .Error ("CreatedAt appears to be in seconds instead of microseconds" )
738+ }
739+ if af .UpdatedAt == expectedSeconds {
740+ t .Error ("UpdatedAt appears to be in seconds instead of microseconds" )
741+ }
742+ if af .NextRunAt == expectedSeconds {
743+ t .Error ("NextRunAt appears to be in seconds instead of microseconds" )
744+ }
745+
746+ mockMetaDomain .AssertExpectations (t )
747+ mockAttachedFunctionDb .AssertExpectations (t )
748+ }
0 commit comments