diff --git a/internal/email/coverage_test.go b/internal/email/coverage_test.go index fdc3090d5..750f436e8 100644 --- a/internal/email/coverage_test.go +++ b/internal/email/coverage_test.go @@ -1023,6 +1023,7 @@ func TestSMTPSender_Port25NoTLS(t *testing.T) { // TestSender_VerificationPathWithEmailIdentityError tests the isEmailVerified error path in SendToEmail. func TestSender_SendToEmail_GetEmailIdentityError(t *testing.T) { mockSES := new(MockSESClient) + t.Cleanup(func() { mockSES.AssertExpectations(t) }) // Return sandbox mode mockSES.On("GetAccount", mock.Anything, mock.AnythingOfType("*sesv2.GetAccountInput")). Return(&sesv2.GetAccountOutput{ProductionAccessEnabled: false}, nil) @@ -1290,6 +1291,7 @@ func TestSMTPSender_AllNotificationMethods_WithRealData(t *testing.T) { // TestSender_SendMethods_ErrorPaths tests error paths in Sender template methods. func TestSender_SendMethods_ErrorPaths(t *testing.T) { mockSNS := new(MockSNSClient) + t.Cleanup(func() { mockSNS.AssertExpectations(t) }) mockSNS.On("Publish", mock.Anything, mock.Anything).Return(nil, assert.AnError) sender := NewSenderWithClients(mockSNS, nil, SenderConfig{ @@ -1353,6 +1355,7 @@ func TestSender_SendMethods_ErrorPaths(t *testing.T) { // TestSender_SendToEmail_EmailVerificationCheck tests email verification check path. func TestSender_SendToEmail_EmailVerificationCheck(t *testing.T) { mockSES := new(MockSESClient) + t.Cleanup(func() { mockSES.AssertExpectations(t) }) // Test case: sandbox mode, verification check fails but we still try to verify mockSES.On("GetAccount", mock.Anything, mock.AnythingOfType("*sesv2.GetAccountInput")). diff --git a/internal/purchase/money_path_regression_test.go b/internal/purchase/money_path_regression_test.go index 5233d8e0d..53dc3c70e 100644 --- a/internal/purchase/money_path_regression_test.go +++ b/internal/purchase/money_path_regression_test.go @@ -40,12 +40,17 @@ func captureIdempotencyTokens(t *testing.T, exec *config.PurchaseExecution) map[ mockFactory := new(MockProviderFactory) mockProviderInst := new(MockProvider) mockServiceClient := new(MockServiceClient) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) + t.Cleanup(func() { mockFactory.AssertExpectations(t) }) + t.Cleanup(func() { mockProviderInst.AssertExpectations(t) }) + t.Cleanup(func() { mockServiceClient.AssertExpectations(t) }) plan := &config.PurchasePlan{Name: "Direct purchase"} mockStore.SavePurchaseExecutionFn = func(_ context.Context, _ *config.PurchaseExecution) error { return nil } mockStore.On("SavePurchaseHistory", ctx, mock.AnythingOfType("*config.PurchaseHistoryRecord")).Return(nil) - mockEmail.On("SendPurchaseConfirmation", ctx, mock.AnythingOfType("email.NotificationData")).Return(nil) + // No SendPurchaseConfirmation expectation: processPurchaseRecommendations + // never sends it (its callers do), so mockEmail must see no call at all. mockFactory.On("CreateAndValidateProvider", mock.Anything, "aws", mock.Anything).Return(mockProviderInst, nil) mockProviderInst.On("GetServiceClient", mock.Anything, common.ServiceEC2, mock.Anything).Return(mockServiceClient, nil) @@ -101,6 +106,10 @@ func TestOfferingClassStampedOnHistoryMatchesPurchase(t *testing.T) { mockFactory := new(MockProviderFactory) mockProviderInst := new(MockProvider) mockServiceClient := new(MockServiceClient) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) + t.Cleanup(func() { mockFactory.AssertExpectations(t) }) + t.Cleanup(func() { mockProviderInst.AssertExpectations(t) }) + t.Cleanup(func() { mockServiceClient.AssertExpectations(t) }) mockStore.On("GetGlobalConfig", ctx).Return(&config.GlobalConfig{OfferingClass: tc.configured}, nil) var history *config.PurchaseHistoryRecord @@ -141,6 +150,7 @@ func TestUnknownOfferingClassRefusesBeforePurchase(t *testing.T) { ctx := context.Background() mockStore := new(MockConfigStore) mockFactory := new(MockProviderFactory) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) mockStore.On("GetGlobalConfig", ctx).Return(&config.GlobalConfig{OfferingClass: "Standard"}, nil) manager := &Manager{config: mockStore, providerFactory: mockFactory} @@ -233,6 +243,11 @@ func TestMultiAccountSeedsStablePerAccountKey(t *testing.T) { mockFactory := new(MockProviderFactory) mockProviderInst := new(MockProvider) mockServiceClient := new(MockServiceClient) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) + t.Cleanup(func() { mockEmail.AssertExpectations(t) }) + t.Cleanup(func() { mockFactory.AssertExpectations(t) }) + t.Cleanup(func() { mockProviderInst.AssertExpectations(t) }) + t.Cleanup(func() { mockServiceClient.AssertExpectations(t) }) baseExec := &config.PurchaseExecution{ ExecutionID: "root-exec", @@ -299,6 +314,11 @@ func TestSQSRedeliveryDoesNotDoubleExecute(t *testing.T) { mockFactory := new(MockProviderFactory) mockProviderInst := new(MockProvider) mockServiceClient := new(MockServiceClient) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) + t.Cleanup(func() { mockEmail.AssertExpectations(t) }) + t.Cleanup(func() { mockFactory.AssertExpectations(t) }) + t.Cleanup(func() { mockProviderInst.AssertExpectations(t) }) + t.Cleanup(func() { mockServiceClient.AssertExpectations(t) }) newPending := func() *config.PurchaseExecution { return &config.PurchaseExecution{ @@ -373,6 +393,11 @@ func TestMultiAccountPartialSuccessIsAcked(t *testing.T) { mockFactory := new(MockProviderFactory) mockProviderInst := new(MockProvider) mockServiceClient := new(MockServiceClient) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) + t.Cleanup(func() { mockEmail.AssertExpectations(t) }) + t.Cleanup(func() { mockFactory.AssertExpectations(t) }) + t.Cleanup(func() { mockProviderInst.AssertExpectations(t) }) + t.Cleanup(func() { mockServiceClient.AssertExpectations(t) }) accounts := []config.CloudAccount{ {ID: "acct-ok", Name: "OK", Provider: "aws", ExternalID: "111111111111", AWSAuthMode: "access_keys"}, @@ -476,6 +501,9 @@ func TestExecuteForAccount_CommittedButUnsavedIsAcked(t *testing.T) { mockFactory := new(MockProviderFactory) mockProviderInst := new(MockProvider) mockServiceClient := new(MockServiceClient) + t.Cleanup(func() { mockStore.AssertExpectations(t) }) + t.Cleanup(func() { mockFactory.AssertExpectations(t) }) + t.Cleanup(func() { mockProviderInst.AssertExpectations(t) }) accounts := []config.CloudAccount{ // role_arn with no STS client wired fails credential resolution @@ -525,7 +553,9 @@ func TestExecuteForAccount_CommittedButUnsavedIsAcked(t *testing.T) { return nil } mockStore.On("SavePurchaseHistory", mock.Anything, mock.AnythingOfType("*config.PurchaseHistoryRecord")).Return(nil) - mockEmail.On("SendPurchaseConfirmation", ctx, mock.AnythingOfType("email.NotificationData")).Return(nil) + // No SendPurchaseConfirmation expectation: acct-unsaved's row never saves, + // so executeForAccount returns AUDIT LOSS before sendPurchaseNotification, + // and acct-bad never commits. No confirmation goes out on this run. mockFactory.On("CreateAndValidateProvider", mock.Anything, "aws", mock.Anything).Return(mockProviderInst, nil) mockProviderInst.On("GetServiceClient", mock.Anything, common.ServiceEC2, mock.Anything).Return(mockServiceClient, nil)