From 77eda672fe6de911f5a66e0bf84fb93608a65ccd Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Tue, 20 Oct 2026 05:13:35 +0200 Subject: [PATCH 1/2] chore(tests): parallelize cmd pure-logic tests Add t.Parallel() to 228 top-level cmd tests that a type-aware scan shows reach no package-level var write or global setter, transitively. Refs #58 Co-Authored-By: Claude Opus 5.5 --- cmd/archera_comparison_key_test.go | 6 ++++++ cmd/archera_comparison_masking_test.go | 3 +++ cmd/archera_comparison_test.go | 3 +++ cmd/cancellation_prepurchase_test.go | 2 ++ cmd/cancellation_test.go | 1 + cmd/configure_azure_sp_test.go | 9 +++++++++ cmd/configure_azure_store_test.go | 1 + cmd/configure_gcp_step_test.go | 4 ++++ cmd/configure_gcp_store_test.go | 1 + cmd/configure_gcp_test.go | 11 +++++++++++ cmd/configure_test.go | 8 ++++++++ cmd/csv_real_purchase_test.go | 3 +++ cmd/effective_dry_run_test.go | 1 + cmd/helpers_account_alias_test.go | 4 ++++ cmd/helpers_adjust_existing_test.go | 7 +++++++ cmd/helpers_count_linear_test.go | 4 ++++ cmd/helpers_instance_limit_rescale_test.go | 6 ++++++ cmd/helpers_instance_limit_test.go | 1 + cmd/helpers_test.go | 5 +++++ cmd/helpers_typed_nil_details_test.go | 3 +++ cmd/instance_limit_savings_plan_test.go | 2 ++ cmd/main_parse_services_test.go | 4 ++++ cmd/main_purchase_id_comprehensive_test.go | 1 + cmd/main_purchase_id_test.go | 4 ++++ cmd/main_service_client_test.go | 4 ++++ cmd/main_test.go | 2 ++ cmd/multi_service_account_names_test.go | 2 ++ cmd/multi_service_adjust_excluded_versions_test.go | 5 +++++ cmd/multi_service_apply_filters_test.go | 5 +++++ cmd/multi_service_coverage_extended_support_test.go | 2 ++ cmd/multi_service_coverage_major_versions_test.go | 2 ++ cmd/multi_service_coverage_test.go | 1 + cmd/multi_service_csv_cap_ranking_test.go | 1 + cmd/multi_service_csv_coverage_column_test.go | 1 + cmd/multi_service_csv_formatters_test.go | 7 +++++++ cmd/multi_service_csv_header_test.go | 3 +++ cmd/multi_service_csv_report_test.go | 5 +++++ cmd/multi_service_csv_strict_test.go | 7 +++++++ cmd/multi_service_csv_test.go | 3 +++ cmd/multi_service_csv_thresholds_test.go | 4 ++++ cmd/multi_service_csv_total_row_test.go | 3 +++ cmd/multi_service_csv_write_failure_test.go | 2 ++ cmd/multi_service_determine_services_test.go | 4 ++++ cmd/multi_service_engine_versions_paginate_test.go | 7 +++++++ cmd/multi_service_engine_versions_test.go | 2 ++ ...multi_service_extended_support_unavailable_test.go | 8 ++++++++ cmd/multi_service_extract_major_version_test.go | 1 + cmd/multi_service_filters_savings_plans_test.go | 2 ++ cmd/multi_service_filters_test.go | 7 +++++++ cmd/multi_service_helpers_test.go | 4 ++++ cmd/multi_service_max_instances_test.go | 2 ++ cmd/multi_service_rds_instances_pages_test.go | 2 ++ cmd/multi_service_should_include_test.go | 2 ++ cmd/multi_service_stats_plan_types_test.go | 3 +++ cmd/multi_service_stats_test.go | 1 + cmd/multi_service_test.go | 4 ++++ cmd/purchase_account_guard_test.go | 1 + cmd/purchase_failure_exit_2157_test.go | 1 + cmd/purchase_safeguards_2121_test.go | 2 ++ cmd/purchase_succeeded_summaries_2205_test.go | 3 +++ cmd/savings_plan_purchase_test.go | 9 +++++++++ cmd/savings_plan_region_test.go | 1 + cmd/secrets_store_test.go | 7 +++++++ cmd/validators_test.go | 2 ++ 64 files changed, 228 insertions(+) diff --git a/cmd/archera_comparison_key_test.go b/cmd/archera_comparison_key_test.go index 77bb8da31..c3a63af01 100644 --- a/cmd/archera_comparison_key_test.go +++ b/cmd/archera_comparison_key_test.go @@ -193,6 +193,7 @@ func TestArcheraLongKeyVisibleDisguisesAreWithheld(t *testing.T) { // Exactly 8 consecutive key characters are withheld, 7 are shown; the first // and last 8 count as much as any other. func TestArcheraKeyFragmentBoundary(t *testing.T) { + t.Parallel() spaced := func(frag string) error { return archeraSafeError(errors.New("A: "+archeraSplitEverywhere(frag, "\u2800")), archeraLongKey) } @@ -208,6 +209,7 @@ func TestArcheraKeyFragmentBoundary(t *testing.T) { // The irregular-insertion rule is bounded: key characters 2 apart read as the // key, 3 apart do not. Uses an 8-character key so there is a single window. func TestArcheraKeyGapBound(t *testing.T) { + t.Parallel() const key = "abcdefgh" two := archeraSafeError(errors.New("A: abc"+"aa"+"defgh"), key).Error() assert.Contains(t, two, archeraWithheld) @@ -241,6 +243,7 @@ func TestArcheraHostileLargeDecodeValueIsBounded(t *testing.T) { // Only text that could be displayed (plus a small slack for a key cut by the // cap) is checked: a key echoed far beyond the cap changes nothing. func TestArcheraKeyBeyondCheckWindowIsIgnored(t *testing.T) { + t.Parallel() far := strings.Repeat("A", archeraMaxErrorSize+archeraCheckSlack+64) + archeraSplitEverywhere(archeraLongKey, "\u2800") got := archeraSafeError(errors.New(far), archeraLongKey).Error() assert.NotContains(t, got, archeraWithheld) @@ -250,6 +253,7 @@ func TestArcheraKeyBeyondCheckWindowIsIgnored(t *testing.T) { // A key spaced by the longest separator and cut by the cap is still withheld, // so the look-ahead slack covers a whole window of such a key. func TestArcheraKeySpacedByLongestSeparatorAtCapIsWithheld(t *testing.T) { + t.Parallel() sep := strings.Repeat("-", archeraMaxSep) msg := strings.Repeat("A", archeraMaxErrorSize-4) + archeraSplitEverywhere(archeraLongKey, sep) got := archeraSafeError(errors.New(msg), archeraLongKey).Error() @@ -259,6 +263,7 @@ func TestArcheraKeySpacedByLongestSeparatorAtCapIsWithheld(t *testing.T) { // A key with an inner space or a format character is matched on what a reader // sees of it. func TestArcheraKeyWithInnerSpaceOrFormatRune(t *testing.T) { + t.Parallel() for name, key := range map[string]string{"inner space": "abcd efgh ijkl", "format rune": "abcdefg\u200bhijklmn"} { got := archeraSafeError(errors.New("A: abcd\u2800efgh\u2800ijkl and abcdefghijklmn"), key).Error() assert.Contains(t, got, archeraWithheld, name) @@ -267,6 +272,7 @@ func TestArcheraKeyWithInnerSpaceOrFormatRune(t *testing.T) { // Ordinary vendor text must survive: the gap rule only fires on the key. func TestArcheraOrdinaryVendorTextIsNotWithheld(t *testing.T) { + t.Parallel() msgs := []string{ "invalid credentials for the account; request id 4821-aa; HTTP 403 forbidden", "organization not found: check the org id and the plan id", diff --git a/cmd/archera_comparison_masking_test.go b/cmd/archera_comparison_masking_test.go index 59bf63e9c..44c044f5e 100644 --- a/cmd/archera_comparison_masking_test.go +++ b/cmd/archera_comparison_masking_test.go @@ -157,6 +157,7 @@ func mustJSON(t *testing.T, v string) string { // otherwise survive as a readable prefix. Sweep the boundary and assert no // 4+ byte prefix of the key remains, for a plain and a strip-split key. func TestArcheraErrorsLeaveNoKeyPrefixAtCap(t *testing.T) { + t.Parallel() k := archeraTestKey for _, echo := range []string{k, k[:5] + "\u200b" + k[5:], archeraSplitEverywhere(k, "\u200b")} { for padLen := archeraMaxErrorSize - len(k) - 8; padLen <= archeraMaxErrorSize+2; padLen++ { @@ -174,6 +175,7 @@ func TestArcheraErrorsLeaveNoKeyPrefixAtCap(t *testing.T) { // The withhold check must see the full text: a cut through a split key would // hide it from a check run after the cap while leaving a readable prefix. func TestArcheraErrorsWithholdSplitKeyAtAnyCapOffset(t *testing.T) { + t.Parallel() k := archeraTestKey for name, sep := range map[string]string{"variation selector": "\ufe0f", "invalid utf-8": "\xff", "combining acute": "\u0301"} { for padLen := archeraMaxErrorSize - 3*len(k); padLen <= archeraMaxErrorSize+2; padLen++ { @@ -184,6 +186,7 @@ func TestArcheraErrorsWithholdSplitKeyAtAnyCapOffset(t *testing.T) { } func TestArcheraErrorsTrimKeyBeforeMasking(t *testing.T) { + t.Parallel() got := archeraSafeError(errors.New("bad key "+archeraTestKey[:5]+"\u200b"+archeraTestKey[5:]), " "+archeraTestKey+"\n").Error() assert.Equal(t, "bad key [redacted]", got) } diff --git a/cmd/archera_comparison_test.go b/cmd/archera_comparison_test.go index 628b8dcc2..a36813bfa 100644 --- a/cmd/archera_comparison_test.go +++ b/cmd/archera_comparison_test.go @@ -310,6 +310,7 @@ func TestArcheraComparisonJSON(t *testing.T) { } func TestArcheraMoneyExact(t *testing.T) { + t.Parallel() for in, want := range map[string]string{"0": "0", "7.25": "7.25", "10.125": "10.125", "1200": "1200", "0.00001": "0.00001"} { r, ok := new(big.Rat).SetString(in) require.True(t, ok) @@ -321,6 +322,7 @@ func TestArcheraMoneyExact(t *testing.T) { } func TestArcheraSanitize(t *testing.T) { + t.Parallel() got := archeraSanitize("a\x1bb\u009bc\nd") assert.Equal(t, "abcd", got) long := archeraSanitize(strings.Repeat("é", 300)) @@ -406,6 +408,7 @@ func TestArcheraNoKeyFlagAndStructsRedacted(t *testing.T) { // fields the decoder would reject (enums, UUIDs, terms) still carry control // characters into the DTO. func TestArcheraDTOSanitizesEveryVendorString(t *testing.T) { + t.Parallel() dirty := func(s string) string { return s + "\x1b[31m\u0085\u009b\u202e\u200b\u2028\u2029" } str := func(s string) *string { v := dirty(s); return &v } pay := insurance.PaymentOption(dirty("no_upfront")) diff --git a/cmd/cancellation_prepurchase_test.go b/cmd/cancellation_prepurchase_test.go index aea8f0183..dfb1bc772 100644 --- a/cmd/cancellation_prepurchase_test.go +++ b/cmd/cancellation_prepurchase_test.go @@ -313,6 +313,7 @@ func TestFetchAllRecs_AccountFilters(t *testing.T) { } func TestRequireResolvedAccountNames_CSVRows(t *testing.T) { + t.Parallel() rows := []common.Recommendation{{Account: testCallerAccount, AccountName: testCallerAccount}} // The CSV wrote the ID where the name lookup had failed. require.Error(t, requireResolvedAccountNames(rows, &Config{ExcludeAccounts: []string{"sandbox"}})) @@ -324,6 +325,7 @@ func TestRequireResolvedAccountNames_CSVRows(t *testing.T) { } func TestRequireNamesResolved_BlankFilterValueIsNotANameFilter(t *testing.T) { + t.Parallel() unresolved := []common.Recommendation{{Account: testCallerAccount, AccountName: testCallerAccount}} require.NoError(t, requireNamesResolved(unresolved, &Config{ExcludeAccounts: []string{" "}})) diff --git a/cmd/cancellation_test.go b/cmd/cancellation_test.go index 043ccd6b0..39ac03488 100644 --- a/cmd/cancellation_test.go +++ b/cmd/cancellation_test.go @@ -265,6 +265,7 @@ func TestRegisterShutdownSignalHandler_CancelSetsFlagAndPrintsNoticeOnce(t *test // handler would return and the second signal below would terminate the test // binary. func TestInvocationContext_FurtherSigintsAreAbsorbed(t *testing.T) { + t.Parallel() ctx, stop := invocationContext() defer stop() diff --git a/cmd/configure_azure_sp_test.go b/cmd/configure_azure_sp_test.go index a37c593ad..5c8867148 100644 --- a/cmd/configure_azure_sp_test.go +++ b/cmd/configure_azure_sp_test.go @@ -102,6 +102,7 @@ const ( ) func TestCreateAzureServicePrincipal_Success(t *testing.T) { + t.Parallel() m := &mockSPProvisioner{ appObjectID: "app-object-id", appID: "app-client-id", @@ -145,6 +146,7 @@ func TestCreateAzureServicePrincipal_Success(t *testing.T) { } func TestCreateAzureServicePrincipal_ErrorPropagation(t *testing.T) { + t.Parallel() tests := []struct { name string setup func(*mockSPProvisioner) @@ -227,6 +229,7 @@ func TestCreateAzureServicePrincipal_ErrorPropagation(t *testing.T) { // the compensating delete also fails, the error names the orphaned application // so the operator can delete it manually. func TestCreateAzureServicePrincipal_RollbackFailureSurfaced(t *testing.T) { + t.Parallel() m := &mockSPProvisioner{ appObjectID: "app-object-id", appID: "app-client-id", @@ -246,6 +249,7 @@ func TestCreateAzureServicePrincipal_RollbackFailureSurfaced(t *testing.T) { } func TestCreateAzureServicePrincipal_ScopeFormat(t *testing.T) { + t.Parallel() m := &mockSPProvisioner{ appObjectID: "o", appID: "a", secret: "s", principalID: "p", roleDefID: "r", } @@ -297,6 +301,7 @@ func newFakePrincipalNotFoundProvisioner(fake *fakeRoleAssigner) *graphSPProvisi // TestGraphSPProvisioner_AssignRole_RetrySucceeds verifies that AssignRole // retries when ARM returns PrincipalNotFound and eventually succeeds. func TestGraphSPProvisioner_AssignRole_RetrySucceeds(t *testing.T) { + t.Parallel() principalNotFound := &azcore.ResponseError{ErrorCode: "PrincipalNotFound", StatusCode: 400} fake := &fakeRoleAssigner{failsRemaining: 2, principalNotFoundErr: principalNotFound} p := newFakePrincipalNotFoundProvisioner(fake) @@ -312,6 +317,7 @@ func TestGraphSPProvisioner_AssignRole_RetrySucceeds(t *testing.T) { // AssignRole fails loud with a clear message when the service principal never // propagates within the budget. func TestGraphSPProvisioner_AssignRole_ExhaustsRetryBudget(t *testing.T) { + t.Parallel() principalNotFound := &azcore.ResponseError{ErrorCode: "PrincipalNotFound", StatusCode: 400} fake := &fakeRoleAssigner{failsRemaining: 100, principalNotFoundErr: principalNotFound} p := newFakePrincipalNotFoundProvisioner(fake) @@ -329,6 +335,7 @@ func TestGraphSPProvisioner_AssignRole_ExhaustsRetryBudget(t *testing.T) { // TestGraphSPProvisioner_AssignRole_NonRetryableError verifies that a // non-PrincipalNotFound error is returned immediately without retrying. func TestGraphSPProvisioner_AssignRole_NonRetryableError(t *testing.T) { + t.Parallel() fake := &fakeRoleAssigner{otherErr: errors.New("authorization denied")} p := newFakePrincipalNotFoundProvisioner(fake) @@ -342,6 +349,7 @@ func TestGraphSPProvisioner_AssignRole_NonRetryableError(t *testing.T) { // TestGraphSPProvisioner_AssignRole_ContextCancellation verifies that context // cancellation is treated as a terminal stop and does not continue retrying. func TestGraphSPProvisioner_AssignRole_ContextCancellation(t *testing.T) { + t.Parallel() principalNotFound := &azcore.ResponseError{ErrorCode: "PrincipalNotFound", StatusCode: 400} fake := &fakeRoleAssigner{failsRemaining: 100, principalNotFoundErr: principalNotFound} p := newFakePrincipalNotFoundProvisioner(fake) @@ -359,6 +367,7 @@ func TestGraphSPProvisioner_AssignRole_ContextCancellation(t *testing.T) { // TestIsPrincipalNotFoundErr covers the error-code detection helper directly. func TestIsPrincipalNotFoundErr(t *testing.T) { + t.Parallel() tests := []struct { err error name string diff --git a/cmd/configure_azure_store_test.go b/cmd/configure_azure_store_test.go index 5546b7fa5..7be1c4961 100644 --- a/cmd/configure_azure_store_test.go +++ b/cmd/configure_azure_store_test.go @@ -12,6 +12,7 @@ import ( // Tests for storeAzureCredentials function. func TestStoreAzureCredentials(t *testing.T) { + t.Parallel() tests := []struct { mockSetup func(*MockSecretsStore) validateStore func(*testing.T, *MockSecretsStore) diff --git a/cmd/configure_gcp_step_test.go b/cmd/configure_gcp_step_test.go index cac04cdd1..24df945c6 100644 --- a/cmd/configure_gcp_step_test.go +++ b/cmd/configure_gcp_step_test.go @@ -11,6 +11,7 @@ import ( ) func TestGCPStepCreateServiceAccount_SkipUsesOperatorEmail(t *testing.T) { + t.Parallel() const existing = "existing-sa@my-proj.iam.gserviceaccount.com" reader := bufio.NewReader(strings.NewReader("s\n " + existing + " \n")) @@ -22,6 +23,7 @@ func TestGCPStepCreateServiceAccount_SkipUsesOperatorEmail(t *testing.T) { } func TestGCPStepCreateServiceAccount_UnknownOptionPromptsForEmail(t *testing.T) { + t.Parallel() const existing = "other@my-proj.iam.gserviceaccount.com" reader := bufio.NewReader(strings.NewReader("x\n" + existing + "\n")) @@ -32,6 +34,7 @@ func TestGCPStepCreateServiceAccount_UnknownOptionPromptsForEmail(t *testing.T) } func TestGCPStepCreateServiceAccount_SkipRejectsInvalidEmail(t *testing.T) { + t.Parallel() for _, in := range []string{"s\n\n", "s\nnot-an-email\n", "s\nuser@example.com\n", "s\n@x.gserviceaccount.com\n", "s\na@b@c.gserviceaccount.com\n", "s\na@.gserviceaccount.com\n", "s\n ", "s\na\x00@x.gserviceaccount.com\n", "s\n"} { email, err := gcpStepCreateServiceAccount(context.Background(), bufio.NewReader(strings.NewReader(in)), "my-proj") require.Error(t, err, "input %q", in) @@ -40,6 +43,7 @@ func TestGCPStepCreateServiceAccount_SkipRejectsInvalidEmail(t *testing.T) { } func TestGCPStepCreateServiceAccount_SkipAcceptsUppercaseEmail(t *testing.T) { + t.Parallel() const existing = "Existing-SA@My-Proj.IAM.GServiceAccount.com" email, err := gcpStepCreateServiceAccount(context.Background(), bufio.NewReader(strings.NewReader("s\n"+existing+"\n")), "my-proj") require.NoError(t, err) diff --git a/cmd/configure_gcp_store_test.go b/cmd/configure_gcp_store_test.go index 3449229a3..5688e06e0 100644 --- a/cmd/configure_gcp_store_test.go +++ b/cmd/configure_gcp_store_test.go @@ -12,6 +12,7 @@ import ( // Tests for storeGCPCredentials function. func TestStoreGCPCredentials(t *testing.T) { + t.Parallel() // private_key validation is presence-only; the key content is not parsed or // validated as a real PEM block by storeGCPCredentials. validGCPJSON := `{ diff --git a/cmd/configure_gcp_test.go b/cmd/configure_gcp_test.go index a22b5dbdd..224ee2dfd 100644 --- a/cmd/configure_gcp_test.go +++ b/cmd/configure_gcp_test.go @@ -20,6 +20,7 @@ import ( // appended to an existing binding for the role and the function reports a // change. func TestAddMemberToPolicyBinding_AppendsToExistingBinding(t *testing.T) { + t.Parallel() policy := &cloudresourcemanager.Policy{ Bindings: []*cloudresourcemanager.Binding{ {Role: "roles/viewer", Members: []string{"user:existing@example.com"}}, @@ -40,6 +41,7 @@ func TestAddMemberToPolicyBinding_AppendsToExistingBinding(t *testing.T) { // TestAddMemberToPolicyBinding_AlreadyBoundNoChange verifies that an // already-bound member is a no-op (returns false, no duplicate appended). func TestAddMemberToPolicyBinding_AlreadyBoundNoChange(t *testing.T) { + t.Parallel() member := "serviceAccount:sa@proj.iam.gserviceaccount.com" policy := &cloudresourcemanager.Policy{ Bindings: []*cloudresourcemanager.Binding{ @@ -59,6 +61,7 @@ func TestAddMemberToPolicyBinding_AlreadyBoundNoChange(t *testing.T) { // TestAddMemberToPolicyBinding_CreatesMissingBinding verifies a new binding is // appended when the role is absent from the policy. func TestAddMemberToPolicyBinding_CreatesMissingBinding(t *testing.T) { + t.Parallel() policy := &cloudresourcemanager.Policy{ Bindings: []*cloudresourcemanager.Binding{ {Role: "roles/viewer", Members: []string{"user:existing@example.com"}}, @@ -81,6 +84,7 @@ func TestAddMemberToPolicyBinding_CreatesMissingBinding(t *testing.T) { // role must NOT drop or mutate a conditional (IAM condition) binding on another // role. Losing conditional bindings would silently widen access. func TestAddMemberToPolicyBinding_PreservesConditionalBindings(t *testing.T) { + t.Parallel() conditional := &cloudresourcemanager.Binding{ Role: "roles/storage.objectViewer", Members: []string{"user:auditor@example.com"}, @@ -150,6 +154,7 @@ func (m *mockGCPKeyProvisioner) DeleteKey(_ context.Context, keyName string) err } func TestWriteServiceAccountKey_Success(t *testing.T) { + t.Parallel() keyMaterial := []byte(`{"type":"service_account","project_id":"proj"}`) m := &mockGCPKeyProvisioner{ keyName: "projects/-/serviceAccounts/sa@proj.iam.gserviceaccount.com/keys/abc123", @@ -175,6 +180,7 @@ func TestWriteServiceAccountKey_Success(t *testing.T) { // (so it does not linger as an active unused credential) and the reserved local // file is cleaned up. func TestWriteServiceAccountKey_DecodeFailureRollsBack(t *testing.T) { + t.Parallel() m := &mockGCPKeyProvisioner{ keyName: "projects/-/serviceAccounts/sa@proj.iam.gserviceaccount.com/keys/abc123", privateKeyData: "!!!not-base64!!!", @@ -198,6 +204,7 @@ func TestWriteServiceAccountKey_DecodeFailureRollsBack(t *testing.T) { // compensating DeleteKey also fails, the error names the orphaned remote key so // the operator can delete it manually, while still surfacing the original cause. func TestWriteServiceAccountKey_RollbackFailureSurfaced(t *testing.T) { + t.Parallel() m := &mockGCPKeyProvisioner{ keyName: "projects/-/serviceAccounts/sa@proj.iam.gserviceaccount.com/keys/orphan999", privateKeyData: "!!!not-base64!!!", @@ -217,6 +224,7 @@ func TestWriteServiceAccountKey_RollbackFailureSurfaced(t *testing.T) { // the remote key fails, no rollback is attempted (nothing was minted) and no // local file is left behind. func TestWriteServiceAccountKey_CreateFailureNoOrphan(t *testing.T) { + t.Parallel() m := &mockGCPKeyProvisioner{ createErr: &googleapi.Error{Code: 403}, } @@ -235,6 +243,7 @@ func TestWriteServiceAccountKey_CreateFailureNoOrphan(t *testing.T) { // TestWriteServiceAccountKey_CreateFailureAmbiguous verifies that only a 4xx // googleapi error is a definite failure; every other outcome may have minted a key. func TestWriteServiceAccountKey_CreateFailureAmbiguous(t *testing.T) { + t.Parallel() const sa = "sa@proj.iam.gserviceaccount.com" cases := []struct { name string @@ -267,6 +276,7 @@ func TestWriteServiceAccountKey_CreateFailureAmbiguous(t *testing.T) { // destination file already exists (exclusive-create fails), the remote key is // never minted, so there is nothing to orphan. func TestWriteServiceAccountKey_ReserveFailureNoMint(t *testing.T) { + t.Parallel() keyFile := filepath.Join(t.TempDir(), "cudly-gcp-key.json") require.NoError(t, os.WriteFile(keyFile, []byte("pre-existing"), 0o600)) @@ -457,6 +467,7 @@ func TestUploadGCPCredentialsFile_OperatorFileKept(t *testing.T) { } func TestGcloudDeleteKeyCommand(t *testing.T) { + t.Parallel() assert.Equal(t, "gcloud iam service-accounts keys delete abc123 --iam-account=sa@proj.iam.gserviceaccount.com", gcloudDeleteKeyCommand(testMintedKeyName)) diff --git a/cmd/configure_test.go b/cmd/configure_test.go index f03969b07..3cabc6f5d 100644 --- a/cmd/configure_test.go +++ b/cmd/configure_test.go @@ -39,6 +39,7 @@ func (m *MockSecretsStore) UpdateSecret(ctx context.Context, secretID string, se // TestAzureCredentials_Struct tests the AzureCredentials struct. func TestAzureCredentials_Struct(t *testing.T) { + t.Parallel() creds := AzureCredentials{ TenantID: "tenant-123", ClientID: "client-456", @@ -54,6 +55,7 @@ func TestAzureCredentials_Struct(t *testing.T) { // TestAzureConfigOptions_Defaults tests AzureConfigOptions defaults. func TestAzureConfigOptions_Defaults(t *testing.T) { + t.Parallel() opts := AzureConfigOptions{} assert.Equal(t, "", opts.StackName) @@ -67,6 +69,7 @@ func TestAzureConfigOptions_Defaults(t *testing.T) { // TestAzureConfigOptions_WithValues tests AzureConfigOptions with values. func TestAzureConfigOptions_WithValues(t *testing.T) { + t.Parallel() opts := AzureConfigOptions{ StackName: "my-cudly", Profile: "production", @@ -88,6 +91,7 @@ func TestAzureConfigOptions_WithValues(t *testing.T) { // TestGCPCredentials_Struct tests the GCPCredentials struct. func TestGCPCredentials_Struct(t *testing.T) { + t.Parallel() creds := GCPCredentials{ Type: "service_account", ProjectID: "my-project", @@ -107,6 +111,7 @@ func TestGCPCredentials_Struct(t *testing.T) { // TestGCPConfigOptions_Defaults tests GCPConfigOptions defaults. func TestGCPConfigOptions_Defaults(t *testing.T) { + t.Parallel() opts := GCPConfigOptions{} assert.Equal(t, "", opts.StackName) @@ -118,6 +123,7 @@ func TestGCPConfigOptions_Defaults(t *testing.T) { // TestGCPConfigOptions_WithValues tests GCPConfigOptions with values. func TestGCPConfigOptions_WithValues(t *testing.T) { + t.Parallel() opts := GCPConfigOptions{ StackName: "my-cudly", Profile: "production", @@ -135,6 +141,7 @@ func TestGCPConfigOptions_WithValues(t *testing.T) { // Tests for validateAzureUUID function. func TestValidateAzureUUID(t *testing.T) { + t.Parallel() tests := []struct { name string uuid string @@ -255,6 +262,7 @@ func TestValidateAzureUUID(t *testing.T) { // Tests for validateGCPProjectID function. func TestValidateGCPProjectID(t *testing.T) { + t.Parallel() tests := []struct { name string projectID string diff --git a/cmd/csv_real_purchase_test.go b/cmd/csv_real_purchase_test.go index 90def6f85..1802a7209 100644 --- a/cmd/csv_real_purchase_test.go +++ b/cmd/csv_real_purchase_test.go @@ -195,6 +195,7 @@ func firstRunRequests(rdsPurchases, cachePurchases int) map[string]int { // must never answer a purchase call, so a test that forgets to install its own // purchase fixture fails instead of "succeeding". func TestAWSFixturesHaveNoPurchaseOps(t *testing.T) { + t.Parallel() for key := range awsFixtures { assert.NotContains(t, key, "Purchase") } @@ -318,6 +319,7 @@ func TestCSVReplay_SecondRunBuysNothing(t *testing.T) { // The dedupe key adds the "elasticache:" engine prefix only for ProviderAWS, // so a CSV row must carry its provider or replays re-buy ElastiCache (#2228). func TestLoadRecommendationsFromCSV_StampsAWSProvider(t *testing.T) { + t.Parallel() recs, err := loadRecommendationsFromCSV(writeTestRecommendationsCSV(t, csvPurchases)) require.NoError(t, err) require.Len(t, recs, 2) @@ -390,6 +392,7 @@ func testCSVReplayMemoryDB(t *testing.T, csv string) { } func TestLoadRecommendationsFromCSV_MemoryDBEngineIsCanonical(t *testing.T) { + t.Parallel() for _, engine := range []string{"redis", "valkey", ""} { recs, err := loadRecommendationsFromCSV(writeTestRecommendationsCSV(t, memdbCSVWithEngine(engine))) require.NoError(t, err) diff --git a/cmd/effective_dry_run_test.go b/cmd/effective_dry_run_test.go index 28f38e980..ec030dd85 100644 --- a/cmd/effective_dry_run_test.go +++ b/cmd/effective_dry_run_test.go @@ -23,6 +23,7 @@ func TestYesFlagRemoved(t *testing.T) { // true. That flag has since been removed; --purchase is now the only control, // so moving money is always an explicit opt-in and a bare run is always safe. func TestEffectiveDryRun(t *testing.T) { + t.Parallel() tests := []struct { name string actualPurchase bool // --purchase diff --git a/cmd/helpers_account_alias_test.go b/cmd/helpers_account_alias_test.go index 6a5e36a82..d5550f994 100644 --- a/cmd/helpers_account_alias_test.go +++ b/cmd/helpers_account_alias_test.go @@ -14,6 +14,7 @@ import ( ) func TestNewAccountAliasCacheWithClient(t *testing.T) { + t.Parallel() mockOrg := &MockOrganizationsClient{} cache := NewAccountAliasCacheWithClient(mockOrg) @@ -24,6 +25,7 @@ func TestNewAccountAliasCacheWithClient(t *testing.T) { } func TestGetAccountAlias(t *testing.T) { + t.Parallel() ctx := context.Background() tests := []struct { @@ -109,6 +111,7 @@ func TestGetAccountAlias(t *testing.T) { } func TestGetAccountAliasConcurrency(t *testing.T) { + t.Parallel() // This test relies on AccountAliasCache.GetAccountAlias using double-checked locking: // first acquire a read lock to check the cache, then acquire a write lock and re-check // before calling the API. Without this pattern, multiple goroutines could pass the @@ -153,6 +156,7 @@ func TestGetAccountAliasConcurrency(t *testing.T) { } func TestGetAccountAliasRealFunction(t *testing.T) { + t.Parallel() // Skip integration test that requires real AWS API t.Skip("Skipping integration test - GetAccountAlias tested via mock tests") diff --git a/cmd/helpers_adjust_existing_test.go b/cmd/helpers_adjust_existing_test.go index 61b0e0078..41682e509 100644 --- a/cmd/helpers_adjust_existing_test.go +++ b/cmd/helpers_adjust_existing_test.go @@ -11,6 +11,7 @@ import ( ) func TestAdjustRecommendationsForExisting(t *testing.T) { + t.Parallel() ctx := context.Background() tests := []struct { @@ -122,6 +123,7 @@ func TestAdjustRecommendationsForExisting(t *testing.T) { } func TestAdjustRecommendationsForExistingRIsEdgeCases(t *testing.T) { + t.Parallel() ctx := context.Background() tests := []struct { @@ -190,16 +192,19 @@ func TestAdjustRecommendationsForExistingRIsEdgeCases(t *testing.T) { } func TestNewDuplicateChecker_CustomWindow(t *testing.T) { + t.Parallel() checker := NewDuplicateChecker(48) assert.Equal(t, 48, checker.LookbackHours) } func TestNewDuplicateChecker_ZeroUsesDefault(t *testing.T) { + t.Parallel() checker := NewDuplicateChecker(0) assert.Equal(t, DefaultDuplicateCheckLookbackHours, checker.LookbackHours) } func TestAdjustRecommendationsForExisting_WithinWindow(t *testing.T) { + t.Parallel() ctx := context.Background() rec := common.Recommendation{ ResourceType: "db.t3.small", Region: "us-east-1", Count: 5, @@ -223,6 +228,7 @@ func TestAdjustRecommendationsForExisting_WithinWindow(t *testing.T) { } func TestAdjustRecommendationsForExisting_OutsideWindow(t *testing.T) { + t.Parallel() ctx := context.Background() rec := common.Recommendation{ ResourceType: "db.t3.small", Region: "us-east-1", Count: 5, @@ -247,6 +253,7 @@ func TestAdjustRecommendationsForExisting_OutsideWindow(t *testing.T) { } func TestAdjustRecommendationsForExisting_PartialCoverage(t *testing.T) { + t.Parallel() ctx := context.Background() rec := common.Recommendation{ ResourceType: "db.t3.small", Region: "us-east-1", Count: 10, diff --git a/cmd/helpers_count_linear_test.go b/cmd/helpers_count_linear_test.go index 33172a0ff..00fcdb3a9 100644 --- a/cmd/helpers_count_linear_test.go +++ b/cmd/helpers_count_linear_test.go @@ -21,6 +21,7 @@ func riRec(count int, avg, existing, cov, util float64) common.Recommendation { } func TestRederiveProjections(t *testing.T) { + t.Parallel() rds := riRec(10, 125, 10, 55, 100) rds.Service = common.ServiceRDS noKnown := riRec(10, 125, 0, 80, 100) @@ -58,6 +59,7 @@ func TestRederiveProjections(t *testing.T) { } func TestSyncDataWarehouseNodes(t *testing.T) { + t.Parallel() ptr := &common.DataWarehouseDetails{NodeType: "ra3.xlplus", NumberOfNodes: 10, ClusterType: "multi-node"} rec := common.Recommendation{Service: common.ServiceRedshift, Count: 3, Details: ptr} @@ -104,6 +106,7 @@ func TestRefreshCountLinearMatchesSizerOutput(t *testing.T) { // Issue #1845: the cap changes Count, so the projections must follow. func TestApplyInstanceLimitRederivesProjections(t *testing.T) { + t.Parallel() capped := riRec(100, 125, 0, 80, 100) untouched := riRec(5, 10, 0, 40, 100) untouched.ResourceType = "c5.large" @@ -129,6 +132,7 @@ func TestApplyInstanceLimitRederivesProjections(t *testing.T) { } func TestApplyInstanceLimitSyncsRedshiftNodes(t *testing.T) { + t.Parallel() src := &common.DataWarehouseDetails{NodeType: "ra3.xlplus", NumberOfNodes: 10, ClusterType: "multi-node"} rec := common.Recommendation{Service: common.ServiceRedshift, Count: 10, Details: src} got := ApplyInstanceLimit([]common.Recommendation{rec}, 3) diff --git a/cmd/helpers_instance_limit_rescale_test.go b/cmd/helpers_instance_limit_rescale_test.go index a778f1524..624d1fad1 100644 --- a/cmd/helpers_instance_limit_rescale_test.go +++ b/cmd/helpers_instance_limit_rescale_test.go @@ -20,6 +20,7 @@ func float64Ptr(v float64) *float64 { return &v } // The assertion is the ratio, not a literal figure, so the test keeps // meaning if the fixture's dollar values are ever changed. func TestApplyInstanceLimitRescalesTruncatedRow(t *testing.T) { + t.Parallel() const ( origCount = 100 maxKept = 10 @@ -74,6 +75,7 @@ func TestApplyInstanceLimitRescalesTruncatedRow(t *testing.T) { // a fix that rescaled every row would satisfy the truncation test above while // silently shrinking rows that fit inside the budget. func TestApplyInstanceLimitLeavesUntruncatedRowsUntouched(t *testing.T) { + t.Parallel() monthly := float64Ptr(200) rec := common.Recommendation{ Service: common.ServiceEC2, @@ -106,6 +108,7 @@ func TestApplyInstanceLimitLeavesUntruncatedRowsUntouched(t *testing.T) { // breakdown" and the frontend renders it as "—". Truncation must not turn // that into a confident $0. func TestApplyInstanceLimitPreservesNilRecurringMonthlyCost(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ { Service: common.ServiceEC2, @@ -130,6 +133,7 @@ func TestApplyInstanceLimitPreservesNilRecurringMonthlyCost(t *testing.T) { // it must pass through with its money untouched rather than through a ratio // computed from a zero denominator (NaN) or a negative one (sign flip). func TestApplyInstanceLimitNonPositiveCountIsNotRescaled(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ {ResourceType: "zero-count", Count: 0, EstimatedSavings: 600, OnDemandCost: 100}, {ResourceType: "negative-count", Count: -5, EstimatedSavings: 300, OnDemandCost: 50}, @@ -161,6 +165,7 @@ func TestApplyInstanceLimitNonPositiveCountIsNotRescaled(t *testing.T) { // --override-count no longer routes SPs here: it leaves them alone precisely // because an SP is dollar-denominated rather than count-denominated (#1844). func TestApplyInstanceLimitRescalesSavingsPlanHourlyCommitment(t *testing.T) { + t.Parallel() const ratio = 2.0 / 5.0 rec := common.Recommendation{ @@ -197,6 +202,7 @@ func TestApplyInstanceLimitRescalesSavingsPlanHourlyCommitment(t *testing.T) { // asserted against an independently computed expectation rather than against // the function's own output, so it cannot agree with a wrong implementation. func TestApplyInstanceLimitTotalMatchesSumOfKeptRows(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ {ResourceType: "whole", Count: 6, EstimatedSavings: 500}, // fits whole {ResourceType: "truncated", Count: 6, EstimatedSavings: 100}, // truncated 6 -> 4 diff --git a/cmd/helpers_instance_limit_test.go b/cmd/helpers_instance_limit_test.go index 9c194f0b6..40965f167 100644 --- a/cmd/helpers_instance_limit_test.go +++ b/cmd/helpers_instance_limit_test.go @@ -9,6 +9,7 @@ import ( ) func TestApplyInstanceLimit(t *testing.T) { + t.Parallel() tests := []struct { name string recs []common.Recommendation diff --git a/cmd/helpers_test.go b/cmd/helpers_test.go index 3dffee484..00affbf65 100644 --- a/cmd/helpers_test.go +++ b/cmd/helpers_test.go @@ -13,6 +13,7 @@ import ( ) func TestCalculateTotalInstances(t *testing.T) { + t.Parallel() tests := []struct { name string recs []common.Recommendation @@ -246,6 +247,7 @@ func TestApplySizing_LegacyCoverageRecordsCountsFlooredToZero(t *testing.T) { } func TestGetRecommendationDescription(t *testing.T) { + t.Parallel() tests := []struct { name string expected string @@ -294,6 +296,7 @@ func TestGetRecommendationDescription(t *testing.T) { } func TestNormalizeEngineName(t *testing.T) { + t.Parallel() tests := []struct { input string expected string @@ -331,6 +334,7 @@ func TestNormalizeEngineName(t *testing.T) { // value-typed case to cover -- see // pkg/common/service_details_codec.go's package doc for the invariant. func TestGetEngineFromRecommendation(t *testing.T) { + t.Parallel() tests := []struct { name string expected string @@ -401,6 +405,7 @@ func TestConfirmPurchaseRejectsNonterminalInput(t *testing.T) { } func TestResolveAccountName_LookupErrorIsReturnedAndRememberedForTheRun(t *testing.T) { + t.Parallel() ctx := context.Background() org := &MockOrganizationsClient{} org.On("DescribeAccount", ctx, &organizations.DescribeAccountInput{AccountId: aws.String("999888777666")}). diff --git a/cmd/helpers_typed_nil_details_test.go b/cmd/helpers_typed_nil_details_test.go index 9ff50db3d..b34a86eea 100644 --- a/cmd/helpers_typed_nil_details_test.go +++ b/cmd/helpers_typed_nil_details_test.go @@ -23,6 +23,7 @@ func typedNilSPDetails() common.ServiceDetails { // in this file depend on. If this ever stops holding, the guards below are // guarding nothing and the tests would pass vacuously. func TestTypedNilSPDetailsAssertionSucceeds(t *testing.T) { + t.Parallel() details, ok := typedNilSPDetails().(*common.SavingsPlanDetails) require.True(t, ok, "a typed nil must still satisfy the type assertion") require.Nil(t, details, "and must yield a nil pointer, which is what makes an unguarded deref panic") @@ -37,6 +38,7 @@ func TestTypedNilSPDetailsAssertionSucceeds(t *testing.T) { // still scale (they do not depend on Details) and Details is left exactly as // it was rather than being replaced with a fabricated zero-value struct. func TestScaleRecommendationCostsSurvivesTypedNilDetails(t *testing.T) { + t.Parallel() rec := common.Recommendation{ Service: common.ServiceSavingsPlansCompute, Count: 4, @@ -66,6 +68,7 @@ func TestScaleRecommendationCostsSurvivesTypedNilDetails(t *testing.T) { // panicking mid-run leaves the operator with no report at all rather than a // degraded one. func TestApplyInstanceLimitSurvivesTypedNilSPDetails(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ { Service: common.ServiceSavingsPlansCompute, diff --git a/cmd/instance_limit_savings_plan_test.go b/cmd/instance_limit_savings_plan_test.go index e2e27538d..3e769ce19 100644 --- a/cmd/instance_limit_savings_plan_test.go +++ b/cmd/instance_limit_savings_plan_test.go @@ -23,6 +23,7 @@ func mkSP() common.Recommendation { } func TestApplyInstanceLimit_SavingsPlanExempt(t *testing.T) { + t.Parallel() got := ApplyInstanceLimit([]common.Recommendation{mkRI("db.r5.large", 3), mkSP(), mkRI("db.r5.xlarge", 2)}, 1) require.Len(t, got, 2) @@ -110,6 +111,7 @@ func TestScoreLimitAndDisplay_MinCountKeepsSavingsPlan(t *testing.T) { } func TestApplyInstanceLimit_SavingsPlanAfterBudgetSpent(t *testing.T) { + t.Parallel() got := ApplyInstanceLimit([]common.Recommendation{mkRI("a", 3), mkRI("b", 2), mkSP()}, 3) require.Len(t, got, 2) diff --git a/cmd/main_parse_services_test.go b/cmd/main_parse_services_test.go index 21771dfa3..4bd1a9c9b 100644 --- a/cmd/main_parse_services_test.go +++ b/cmd/main_parse_services_test.go @@ -8,6 +8,7 @@ import ( ) func TestParseServices(t *testing.T) { + t.Parallel() tests := []struct { name string input []string @@ -79,6 +80,7 @@ func TestParseServices(t *testing.T) { } func TestGetAllServices(t *testing.T) { + t.Parallel() services := getAllServices() expected := []common.ServiceType{ @@ -98,6 +100,7 @@ func TestGetAllServices(t *testing.T) { } func TestParseServicesWithEmptyAndNil(t *testing.T) { + t.Parallel() for _, input := range [][]string{nil, {}} { result, err := parseServices(input) assert.NoError(t, err) @@ -111,6 +114,7 @@ func TestParseServicesWithEmptyAndNil(t *testing.T) { } func TestParseServicesSavingsPlanAliases(t *testing.T) { + t.Parallel() expected := []common.ServiceType{common.ServiceSavingsPlansCompute, common.ServiceSavingsPlansEC2Instance, common.ServiceSavingsPlansSageMaker, common.ServiceSavingsPlansDatabase} for _, alias := range []string{"savingsplans", "savings-plans", "SP"} { result, err := parseServices([]string{"ec2", alias, "savingsplans-compute", "rds", "EC2"}) diff --git a/cmd/main_purchase_id_comprehensive_test.go b/cmd/main_purchase_id_comprehensive_test.go index 7381a049b..54bc01338 100644 --- a/cmd/main_purchase_id_comprehensive_test.go +++ b/cmd/main_purchase_id_comprehensive_test.go @@ -8,6 +8,7 @@ import ( ) func TestGeneratePurchaseIDComprehensive(t *testing.T) { + t.Parallel() // Use a test coverage value testCoverage := 75.0 diff --git a/cmd/main_purchase_id_test.go b/cmd/main_purchase_id_test.go index b2411473a..0957b1a27 100644 --- a/cmd/main_purchase_id_test.go +++ b/cmd/main_purchase_id_test.go @@ -10,6 +10,7 @@ import ( ) func TestGeneratePurchaseID(t *testing.T) { + t.Parallel() tests := []struct { name string region string @@ -95,6 +96,7 @@ func TestGeneratePurchaseID(t *testing.T) { } func TestGeneratePurchaseIDEdgeCases(t *testing.T) { + t.Parallel() testCoverage := 80.0 // Test with recommendations that have special characters @@ -125,6 +127,7 @@ func TestGeneratePurchaseIDEdgeCases(t *testing.T) { } func TestGeneratePurchaseIDCoverageVariations(t *testing.T) { + t.Parallel() rec := common.Recommendation{ Service: common.ServiceRDS, ResourceType: "db.t3.small", @@ -156,6 +159,7 @@ func TestGeneratePurchaseIDCoverageVariations(t *testing.T) { } func TestGeneratePurchaseID_EdgeCases(t *testing.T) { + t.Parallel() tests := []struct { name string region string diff --git a/cmd/main_service_client_test.go b/cmd/main_service_client_test.go index 3df913c49..891e5ccdb 100644 --- a/cmd/main_service_client_test.go +++ b/cmd/main_service_client_test.go @@ -9,6 +9,7 @@ import ( ) func TestCreateServiceClient(t *testing.T) { + t.Parallel() cfg := aws.Config{ Region: "us-east-1", } @@ -97,6 +98,7 @@ func TestCreateServiceClient(t *testing.T) { } func TestCreateServiceClientAllServices(t *testing.T) { + t.Parallel() cfg := aws.Config{ Region: "eu-central-1", } @@ -110,6 +112,7 @@ func TestCreateServiceClientAllServices(t *testing.T) { } func TestSanitizeAccountName(t *testing.T) { + t.Parallel() tests := []struct { name string input string @@ -137,6 +140,7 @@ func TestSanitizeAccountName(t *testing.T) { } func TestValidateInstanceTypes(t *testing.T) { + t.Parallel() tests := []struct { name string errorContains string diff --git a/cmd/main_test.go b/cmd/main_test.go index f0c738c82..4c7990926 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -69,6 +69,7 @@ func TestMain(m *testing.M) { } func TestRunTool(t *testing.T) { + t.Parallel() // Skip this integration test that requires AWS credentials t.Skip("Skipping integration test that requires AWS credentials - functionality tested in TestProcessServiceWithMocks") @@ -171,6 +172,7 @@ func TestCommandFlags(t *testing.T) { // default Coverage=80 instead of the actual target value the user passed. // Regression guard for the Aurora-target / RDS-target CLI dry-run runs. func TestEffectiveSizingPct(t *testing.T) { + t.Parallel() tests := []struct { name string cfg Config diff --git a/cmd/multi_service_account_names_test.go b/cmd/multi_service_account_names_test.go index cf82de645..228a683f0 100644 --- a/cmd/multi_service_account_names_test.go +++ b/cmd/multi_service_account_names_test.go @@ -12,6 +12,7 @@ import ( ) func TestPopulateAccountNames(t *testing.T) { + t.Parallel() ctx := context.Background() tests := []struct { @@ -120,6 +121,7 @@ func TestPopulateAccountNames(t *testing.T) { // TestPopulateAccountNamesLogic tests the logic of populateAccountNames // by verifying it populates the AccountName field correctly. func TestPopulateAccountNamesLogic(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("Correctly populates account names", func(t *testing.T) { diff --git a/cmd/multi_service_adjust_excluded_versions_test.go b/cmd/multi_service_adjust_excluded_versions_test.go index c3a386767..f326f887e 100644 --- a/cmd/multi_service_adjust_excluded_versions_test.go +++ b/cmd/multi_service_adjust_excluded_versions_test.go @@ -13,6 +13,7 @@ import ( ) func TestAdjustRecommendationForExcludedVersions_MultipleVersionsInExtendedSupport(t *testing.T) { + t.Parallel() recommendation := common.Recommendation{ Service: common.ServiceRDS, Region: "us-east-1", @@ -63,6 +64,7 @@ func TestAdjustRecommendationForExcludedVersions_MultipleVersionsInExtendedSuppo } func TestAdjustRecommendationForExcludedVersions_NonRDSService(t *testing.T) { + t.Parallel() recommendation := common.Recommendation{ Service: common.ServiceEC2, Region: "us-east-1", @@ -87,6 +89,7 @@ func TestAdjustRecommendationForExcludedVersions_NonRDSService(t *testing.T) { // function gets past its early "no running instances" return and actually // reaches the switch. func TestAdjustRecommendationForExcludedVersions_TypedNilDetails(t *testing.T) { + t.Parallel() recommendation := common.Recommendation{ Service: common.ServiceRDS, Region: "us-east-1", @@ -174,6 +177,7 @@ func TestAdjustRecommendationForExcludedVersions_UnknownLifecycle(t *testing.T) // count must scale the money fields with it, or the report keeps the full // recommendation's cost for fewer instances. func TestAdjustRecommendationForExcludedVersions_ScalesMoneyWithCount(t *testing.T) { + t.Parallel() monthly := 30.0 recommendation := common.Recommendation{ Service: common.ServiceRDS, @@ -205,6 +209,7 @@ func TestAdjustRecommendationForExcludedVersions_ScalesMoneyWithCount(t *testing } func TestAdjustRecommendationForExcludedVersions(t *testing.T) { + t.Parallel() tests := []struct { versionInfo map[string]MajorEngineVersionInfo instanceVersions map[string][]InstanceEngineVersion diff --git a/cmd/multi_service_apply_filters_test.go b/cmd/multi_service_apply_filters_test.go index 9713b470b..1a9ed2a45 100644 --- a/cmd/multi_service_apply_filters_test.go +++ b/cmd/multi_service_apply_filters_test.go @@ -8,6 +8,7 @@ import ( ) func TestApplyFilters_RegionFiltering(t *testing.T) { + t.Parallel() tests := []struct { name string currentRegion string @@ -90,6 +91,7 @@ func TestApplyFilters_RegionFiltering(t *testing.T) { } func TestApplyFilters_InstanceTypeFiltering(t *testing.T) { + t.Parallel() tests := []struct { name string recs []common.Recommendation @@ -135,6 +137,7 @@ func TestApplyFilters_InstanceTypeFiltering(t *testing.T) { } func TestApplyFilters_EngineFiltering(t *testing.T) { + t.Parallel() tests := []struct { name string recs []common.Recommendation @@ -210,6 +213,7 @@ func TestApplyFilters_EngineFiltering(t *testing.T) { } func TestApplyFilters_AccountFiltering(t *testing.T) { + t.Parallel() tests := []struct { name string recs []common.Recommendation @@ -274,6 +278,7 @@ func TestApplyFilters_AccountFiltering(t *testing.T) { } func TestApplyFilters_CombinedFilters(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ {Region: "us-east-1", ResourceType: "db.t3.small", Count: 1, Service: common.ServiceRDS, Details: &common.DatabaseDetails{Engine: "postgresql"}, AccountName: "prod-account"}, {Region: "us-west-2", ResourceType: "db.t3.medium", Count: 2, Service: common.ServiceRDS, Details: &common.DatabaseDetails{Engine: "mysql"}, AccountName: "dev-account"}, diff --git a/cmd/multi_service_coverage_extended_support_test.go b/cmd/multi_service_coverage_extended_support_test.go index b1a629fea..5c2be9bff 100644 --- a/cmd/multi_service_coverage_extended_support_test.go +++ b/cmd/multi_service_coverage_extended_support_test.go @@ -10,6 +10,7 @@ import ( ) func TestIsInExtendedSupport_EdgeCases(t *testing.T) { + t.Parallel() now := time.Now() pastDate := now.AddDate(0, -6, 0) // 6 months ago futureDate := now.AddDate(3, 0, 0) // 3 years from now @@ -88,6 +89,7 @@ func TestIsInExtendedSupport_EdgeCases(t *testing.T) { // ==================== Tests for adjustRecommendationForExcludedVersions ==================== func TestAdjustRecommendationForExcludedVersions_AdditionalCases(t *testing.T) { + t.Parallel() now := time.Now() pastDate := now.AddDate(0, -6, 0) futureDate := now.AddDate(3, 0, 0) diff --git a/cmd/multi_service_coverage_major_versions_test.go b/cmd/multi_service_coverage_major_versions_test.go index af4cd2dda..d48bf2871 100644 --- a/cmd/multi_service_coverage_major_versions_test.go +++ b/cmd/multi_service_coverage_major_versions_test.go @@ -42,6 +42,7 @@ func (s *engineKeyedRDSMajorVersionsStub) DescribeDBMajorEngineVersions( // live-credential test: it stubs the RDS client and asserts the merged // engine:major-version map deterministically. func TestQueryMajorEngineVersionsWithClient_Success(t *testing.T) { + t.Parallel() stub := &engineKeyedRDSMajorVersionsStub{ versionsByEngine: map[string][]rdstypes.DBMajorEngineVersion{ "mysql": {rdsMajorVersion("mysql", "5.7"), rdsMajorVersion("mysql", "8.0")}, @@ -71,6 +72,7 @@ func TestQueryMajorEngineVersionsWithClient_Success(t *testing.T) { // call fails: missing lifecycle data must not silently disable the // extended-support exclusion (#2147). func TestQueryMajorEngineVersionsWithClient_EngineErrorContinues(t *testing.T) { + t.Parallel() stub := &engineKeyedRDSMajorVersionsStub{ versionsByEngine: map[string][]rdstypes.DBMajorEngineVersion{ "postgres": {rdsMajorVersion("postgres", "15")}, diff --git a/cmd/multi_service_coverage_test.go b/cmd/multi_service_coverage_test.go index 71e1e7d85..bcd116046 100644 --- a/cmd/multi_service_coverage_test.go +++ b/cmd/multi_service_coverage_test.go @@ -21,6 +21,7 @@ import ( // ==================== Tests for extractMajorVersion ==================== func TestExtractMajorVersion_ComprehensiveTests(t *testing.T) { + t.Parallel() tests := []struct { name string engine string diff --git a/cmd/multi_service_csv_cap_ranking_test.go b/cmd/multi_service_csv_cap_ranking_test.go index 4e5cf1a58..a88db9085 100644 --- a/cmd/multi_service_csv_cap_ranking_test.go +++ b/cmd/multi_service_csv_cap_ranking_test.go @@ -9,6 +9,7 @@ import ( ) func TestRequireRankingSignal_IgnoresZeroSavingsSavingsPlan(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ {Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 5, EstimatedSavings: 100}, {Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.small", Count: 5, EstimatedSavings: 50}, diff --git a/cmd/multi_service_csv_coverage_column_test.go b/cmd/multi_service_csv_coverage_column_test.go index ebf36b05c..7c842c8f8 100644 --- a/cmd/multi_service_csv_coverage_column_test.go +++ b/cmd/multi_service_csv_coverage_column_test.go @@ -19,6 +19,7 @@ import ( // (both land at ~100% on every under-buy row, so they add noise without // information). func TestWriteMultiServiceCSVReport_CoverageColumn(t *testing.T) { + t.Parallel() tmpDir := t.TempDir() filepath := tmpDir + "/util.csv" diff --git a/cmd/multi_service_csv_formatters_test.go b/cmd/multi_service_csv_formatters_test.go index fa7e03812..d84115a6d 100644 --- a/cmd/multi_service_csv_formatters_test.go +++ b/cmd/multi_service_csv_formatters_test.go @@ -16,6 +16,7 @@ import ( // previously meant either "CE was queried but returned 0%" or "CE // returned nothing", with no way to tell which. func TestFormatExistingCoverage(t *testing.T) { + t.Parallel() tests := []struct { name string rec common.Recommendation @@ -39,6 +40,7 @@ func TestFormatExistingCoverage(t *testing.T) { // all-upfront RIs) renders as "0.00". Operators need to tell "we don't // know" apart from "definitely zero" to compute total cost correctly. func TestFormatRecurringMonthlyOrBlank(t *testing.T) { + t.Parallel() zero := 0.0 twenty := 20.5 tests := []struct { @@ -60,6 +62,7 @@ func TestFormatRecurringMonthlyOrBlank(t *testing.T) { // TestExtractFamily covers the CSV Family column: the RDS family prefix and // the Savings Plan instance family. func TestExtractFamily(t *testing.T) { + t.Parallel() tests := []struct { name string rec common.Recommendation @@ -88,6 +91,7 @@ func TestExtractFamily(t *testing.T) { // with known sizes and stay blank for non-RDS / zero-count / unknown-size // inputs, matching the "0/empty = unknown" convention used elsewhere. func TestFormatNormalizedUnitsOrBlank(t *testing.T) { + t.Parallel() tests := []struct { name string rec common.Recommendation @@ -120,6 +124,7 @@ func TestFormatNormalizedUnitsOrBlank(t *testing.T) { // pointer (every producer constructs it that way); no value-typed case // is needed. func TestExtractDeployment(t *testing.T) { + t.Parallel() tests := []struct { name string rec common.Recommendation @@ -149,6 +154,7 @@ func TestExtractDeployment(t *testing.T) { // the Azure compute client and the GCP compute-engine client both construct // it that way. func TestExtractEngine(t *testing.T) { + t.Parallel() tests := []struct { name string rec common.Recommendation @@ -178,6 +184,7 @@ func TestExtractEngine(t *testing.T) { // as an empty cell so users can distinguish "no upfront due" from "actual // $0 upfront", consistent with the rest of the optional CSV columns. func TestFormatCurrencyOrBlank(t *testing.T) { + t.Parallel() tests := []struct { name string in float64 diff --git a/cmd/multi_service_csv_header_test.go b/cmd/multi_service_csv_header_test.go index 8adfd7fd9..eb0cdbd33 100644 --- a/cmd/multi_service_csv_header_test.go +++ b/cmd/multi_service_csv_header_test.go @@ -11,6 +11,7 @@ import ( ) func TestLoadRecommendationsFromCSV_HeaderValidation_1327(t *testing.T) { + t.Parallel() tests := []struct { name string header string @@ -43,6 +44,7 @@ func TestLoadRecommendationsFromCSV_HeaderValidation_1327(t *testing.T) { } func TestLoadRecommendationsFromCSV_BOMPrefixed_1327(t *testing.T) { + t.Parallel() recs, err := loadRecommendationsFromCSV(writeTestRecommendationsCSV(t, "\ufeffService,Region,ResourceType,Count,Term,PaymentOption\nrds,us-east-1,db.t3.micro,2,3yr,partial-upfront\n")) require.NoError(t, err) @@ -110,6 +112,7 @@ func TestLoadRecommendationsFromCSV_Encoding_1327(t *testing.T) { // Lock in encoding/csv behaviors the purchase path relies on. func TestLoadRecommendationsFromCSV_EdgeCases_1327(t *testing.T) { + t.Parallel() t.Run("CRLF line endings", func(t *testing.T) { recs, err := loadRecommendationsFromCSV(writeTestRecommendationsCSV(t, "Service,Region,ResourceType,Count,Term,PaymentOption\r\nrds,us-east-1,db.t3.micro,2,3yr,partial-upfront\r\n")) diff --git a/cmd/multi_service_csv_report_test.go b/cmd/multi_service_csv_report_test.go index 4a9e232a9..5763eadaf 100644 --- a/cmd/multi_service_csv_report_test.go +++ b/cmd/multi_service_csv_report_test.go @@ -11,6 +11,7 @@ import ( ) func TestWriteMultiServiceCSVReport_EmptyResults(t *testing.T) { + t.Parallel() tmpFile := "/tmp/test_empty_results.csv" defer os.Remove(tmpFile) @@ -23,6 +24,7 @@ func TestWriteMultiServiceCSVReport_EmptyResults(t *testing.T) { } func TestWriteMultiServiceCSVReport_Success(t *testing.T) { + t.Parallel() tmpFile := "/tmp/test_csv_success.csv" defer os.Remove(tmpFile) @@ -59,6 +61,7 @@ func TestWriteMultiServiceCSVReport_Success(t *testing.T) { } func TestWriteMultiServiceCSVReport_WithError(t *testing.T) { + t.Parallel() tmpFile := "/tmp/test_csv_with_error.csv" defer os.Remove(tmpFile) @@ -88,6 +91,7 @@ func TestWriteMultiServiceCSVReport_WithError(t *testing.T) { } func TestWriteMultiServiceCSVReport_InvalidPath(t *testing.T) { + t.Parallel() // Use an invalid path (directory that doesn't exist) invalidPath := "/nonexistent/directory/test.csv" @@ -110,6 +114,7 @@ func TestWriteMultiServiceCSVReport_InvalidPath(t *testing.T) { } func TestWriteMultiServiceCSVReport_MultipleResults(t *testing.T) { + t.Parallel() tmpFile := "/tmp/test_csv_multiple.csv" defer os.Remove(tmpFile) diff --git a/cmd/multi_service_csv_strict_test.go b/cmd/multi_service_csv_strict_test.go index 62ced1c8c..087f67638 100644 --- a/cmd/multi_service_csv_strict_test.go +++ b/cmd/multi_service_csv_strict_test.go @@ -18,6 +18,7 @@ func loadCSVContent(t *testing.T, content string) error { // Count cells must parse whole or not at all (#1944): fmt.Sscanf truncated // "3.7" to 3 and accepted trailing garbage, both feeding the purchase loop. func TestLoadRecommendationsFromCSV_StrictCount(t *testing.T) { + t.Parallel() tests := []struct { name string cell string @@ -45,6 +46,7 @@ func TestLoadRecommendationsFromCSV_StrictCount(t *testing.T) { } func TestLoadRecommendationsFromCSV_CountTrimmed(t *testing.T) { + t.Parallel() csvPath := writeTestRecommendationsCSV(t, "Service,Region,ResourceType,Count,Term,PaymentOption\nrds,us-east-1,db.t3.micro,\" 3 \",3yr,partial-upfront\n") recs, err := loadRecommendationsFromCSV(csvPath) require.NoError(t, err) @@ -53,12 +55,14 @@ func TestLoadRecommendationsFromCSV_CountTrimmed(t *testing.T) { } func TestLoadRecommendationsFromCSV_CountColumnRequired(t *testing.T) { + t.Parallel() err := loadCSVContent(t, "Service,Region,ResourceType,Term,PaymentOption\nrds,us-east-1,db.t3.micro,3yr,partial-upfront\n") require.Error(t, err) assert.Contains(t, err.Error(), "Count") } func TestLoadRecommendationsFromCSV_StrictEstimatedSavings(t *testing.T) { + t.Parallel() tests := []struct { name string cell string @@ -85,6 +89,7 @@ func TestLoadRecommendationsFromCSV_StrictEstimatedSavings(t *testing.T) { // A blank EstimatedSavings cell stays absent-as-zero: requireRankingSignal // relies on it to refuse a binding --max-instances cap. func TestLoadRecommendationsFromCSV_BlankSavingsStillZero(t *testing.T) { + t.Parallel() csvPath := writeTestRecommendationsCSV(t, "Service,Region,ResourceType,Count,EstimatedSavings,Term,PaymentOption\nrds,us-east-1,db.t3.micro,2, ,3yr,partial-upfront\n") recs, err := loadRecommendationsFromCSV(csvPath) require.NoError(t, err) @@ -129,6 +134,7 @@ func TestRunToolFromCSV_RejectsMalformedNumbers(t *testing.T) { // (1yr/3yr, all-upfront/partial-upfront/no-upfront); a blank or unknown value // fails the load with the row number instead of reaching the purchase loop. func TestLoadRecommendationsFromCSV_TermAndPaymentValues(t *testing.T) { + t.Parallel() tests := []struct { name string term string @@ -158,6 +164,7 @@ func TestLoadRecommendationsFromCSV_TermAndPaymentValues(t *testing.T) { } func TestLoadRecommendationsFromCSV_TermAndPaymentAccepted(t *testing.T) { + t.Parallel() for _, term := range []string{"1yr", "3yr"} { for _, payment := range []string{"all-upfront", "partial-upfront", "no-upfront"} { t.Run(term+"/"+payment, func(t *testing.T) { diff --git a/cmd/multi_service_csv_test.go b/cmd/multi_service_csv_test.go index be450f6aa..72c726094 100644 --- a/cmd/multi_service_csv_test.go +++ b/cmd/multi_service_csv_test.go @@ -13,6 +13,7 @@ import ( ) func TestDetermineCSVCoverage(t *testing.T) { + t.Parallel() tests := []struct { name string cfg Config @@ -73,6 +74,7 @@ func TestDetermineCSVCoverage(t *testing.T) { } func TestWriteMultiServiceCSVReport(t *testing.T) { + t.Parallel() tests := []struct { name string filename string @@ -197,6 +199,7 @@ func TestWriteMultiServiceCSVReport(t *testing.T) { // Tests for loadRecommendationsFromCSV function. func TestLoadRecommendationsFromCSV(t *testing.T) { + t.Parallel() tests := []struct { validate func(t *testing.T, recs []common.Recommendation) name string diff --git a/cmd/multi_service_csv_thresholds_test.go b/cmd/multi_service_csv_thresholds_test.go index 7049c0f47..77a37673a 100644 --- a/cmd/multi_service_csv_thresholds_test.go +++ b/cmd/multi_service_csv_thresholds_test.go @@ -105,6 +105,7 @@ func runCSVThresholdChild(t *testing.T, joinedArgs, csvKey, want string) { // TestCSVThresholdColumnsRoundTrip pins that the writer emits both columns and // the parser reads back exactly what was written. func TestCSVThresholdColumnsRoundTrip(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ {Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.small", Count: 2, Term: "1yr", PaymentOption: "all-upfront", CommitmentCost: 1200, EstimatedSavings: 50, SavingsPercentage: 33.333333333333336}, @@ -138,6 +139,7 @@ func TestCSVThresholdColumnsRoundTrip(t *testing.T) { // that cannot be stated as a finite number is written blank (absent), never as // "+Inf" or a fabricated 0. func TestThresholdCellsBlankWhenBreakEvenUnknownOrInfinite(t *testing.T) { + t.Parallel() never := common.Recommendation{Term: "1yr", CommitmentCost: 1200, EstimatedSavings: -100, SavingsPercentage: 1} months, known := common.BreakEven(never) require.True(t, known) @@ -151,6 +153,7 @@ func TestThresholdCellsBlankWhenBreakEvenUnknownOrInfinite(t *testing.T) { // TestCSVThresholdHeaderStaysStrict pins that carrying the new columns did not // loosen the required-column check. func TestCSVThresholdHeaderStaysStrict(t *testing.T) { + t.Parallel() _, err := loadCSVRecommendations(writeTestRecommendationsCSV(t, "Service,Region,ResourceType,Term,PaymentOption,SavingsPercentage,BreakEvenMonths\nrds,us-east-1,db.t3.small,1yr,all-upfront,10,3\n"), csvThresholdNeeds{savingsPct: true, breakEven: true}) @@ -161,6 +164,7 @@ func TestCSVThresholdHeaderStaysStrict(t *testing.T) { // TestCSVThresholdWhitespaceCellIsBlank pins that a whitespace-only cell is // blank: refused when its flag is set, ignored (left 0) when it is not. func TestCSVThresholdWhitespaceCellIsBlank(t *testing.T) { + t.Parallel() const row = "rds,us-east-1,db.t3.small,postgres,2,1yr,all-upfront,111111111111,100,%s,%s\n" for _, blank := range []string{" ", "\t"} { for _, col := range []struct { diff --git a/cmd/multi_service_csv_total_row_test.go b/cmd/multi_service_csv_total_row_test.go index 128fc2b19..586db75a9 100644 --- a/cmd/multi_service_csv_total_row_test.go +++ b/cmd/multi_service_csv_total_row_test.go @@ -21,6 +21,7 @@ import ( // removes the need to copy-paste columns into a spreadsheet to add // them up. func TestWriteMultiServiceCSVReport_SortAndTotal(t *testing.T) { + t.Parallel() tmpDir := t.TempDir() fp := tmpDir + "/sort-total.csv" @@ -84,6 +85,7 @@ func TestWriteMultiServiceCSVReport_SortAndTotal(t *testing.T) { // resolves their size suffix even though their own NU cell renders blank; // before the fix those rows inflated the TOTAL. func TestBuildTotalRow_NUSkipsRowsWithBlankNUCell(t *testing.T) { + t.Parallel() results := []common.PurchaseResult{ // 5 × db.r6g.large = 20 NU (rendered on the row). {Recommendation: common.Recommendation{Service: common.ServiceRDS, ResourceType: "db.r6g.large", Count: 5}}, @@ -123,6 +125,7 @@ func TestBuildTotalRow_NUSkipsRowsWithBlankNUCell(t *testing.T) { // TestBuildTotalRow_NUBlankWhenNoRowHasNU locks that a run with no RDS rows // leaves the TOTAL NU cell blank instead of summing NU for blank-cell rows. func TestBuildTotalRow_NUBlankWhenNoRowHasNU(t *testing.T) { + t.Parallel() results := []common.PurchaseResult{ {Recommendation: common.Recommendation{Service: common.ServiceElastiCache, ResourceType: "cache.r7g.large", Count: 3}}, } diff --git a/cmd/multi_service_csv_write_failure_test.go b/cmd/multi_service_csv_write_failure_test.go index b00784ee1..78fc15d55 100644 --- a/cmd/multi_service_csv_write_failure_test.go +++ b/cmd/multi_service_csv_write_failure_test.go @@ -15,6 +15,7 @@ import ( // Test loadRecommendationsFromCSV with file errors. func TestLoadRecommendationsFromCSV_FileErrors(t *testing.T) { + t.Parallel() tests := []struct { name string setup func(t *testing.T) string @@ -68,6 +69,7 @@ func (failingWriter) Write([]byte) (int, error) { return 0, errors.New("disk ful // Issue #2004: csv.Writer buffers everything, so the bytes only reach the // file at Flush. A Flush failure must surface instead of a nil return. func TestWriteMultiServiceCSV_FlushErrorIsReturned(t *testing.T) { + t.Parallel() results := []common.PurchaseResult{{ Recommendation: common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.small", Count: 1}, Success: true, diff --git a/cmd/multi_service_determine_services_test.go b/cmd/multi_service_determine_services_test.go index 3e7674006..322c8966f 100644 --- a/cmd/multi_service_determine_services_test.go +++ b/cmd/multi_service_determine_services_test.go @@ -9,6 +9,7 @@ import ( ) func TestDetermineServicesToProcess_AllServices(t *testing.T) { + t.Parallel() cfg := Config{ AllServices: true, } @@ -26,6 +27,7 @@ func TestDetermineServicesToProcess_AllServices(t *testing.T) { } func TestDetermineServicesToProcess_SpecificServices(t *testing.T) { + t.Parallel() cfg := Config{ AllServices: false, Services: []string{"rds", "elasticache"}, @@ -40,6 +42,7 @@ func TestDetermineServicesToProcess_SpecificServices(t *testing.T) { } func TestDetermineServicesToProcess_DefaultAndInvalid(t *testing.T) { + t.Parallel() for _, services := range [][]string{nil, {}} { result, err := determineServicesToProcess(Config{Services: services}) assert.NoError(t, err) @@ -51,6 +54,7 @@ func TestDetermineServicesToProcess_DefaultAndInvalid(t *testing.T) { } func TestDetermineServicesToProcess_SavingsPlanTypeFilters(t *testing.T) { + t.Parallel() allSP := []common.ServiceType{ common.ServiceSavingsPlansCompute, common.ServiceSavingsPlansEC2Instance, common.ServiceSavingsPlansSageMaker, common.ServiceSavingsPlansDatabase, diff --git a/cmd/multi_service_engine_versions_paginate_test.go b/cmd/multi_service_engine_versions_paginate_test.go index 97c6f5f4b..a7ddd26e6 100644 --- a/cmd/multi_service_engine_versions_paginate_test.go +++ b/cmd/multi_service_engine_versions_paginate_test.go @@ -62,6 +62,7 @@ func rdsMajorVersion(engine, major string) rdstypes.DBMajorEngineVersion { //nol // TestFetchMajorEngineVersionsForEngine_Paginates asserts that all pages are // fetched and results accumulated (issue #692 regression test). func TestFetchMajorEngineVersionsForEngine_Paginates(t *testing.T) { + t.Parallel() mock := &multiPageRDSMajorVersionsMock{ pages: []*awsrds.DescribeDBMajorEngineVersionsOutput{ { @@ -101,6 +102,7 @@ func TestFetchMajorEngineVersionsForEngine_Paginates(t *testing.T) { // TestFetchMajorEngineVersionsForEngine_EmptyMarkerTerminates asserts that an // empty-string Marker is treated as terminal (parity with PR #690). func TestFetchMajorEngineVersionsForEngine_EmptyMarkerTerminates(t *testing.T) { + t.Parallel() mock := &multiPageRDSMajorVersionsMock{ pages: []*awsrds.DescribeDBMajorEngineVersionsOutput{ { @@ -142,6 +144,7 @@ func (m *alwaysNextPageRDSMock) DescribeDBMajorEngineVersions( // TestFetchMajorEngineVersionsForEngine_PaginationCapError asserts that // exceeding maxEngineVersionPages returns a diagnostic error (issue #692). func TestFetchMajorEngineVersionsForEngine_PaginationCapError(t *testing.T) { + t.Parallel() mock := &alwaysNextPageRDSMock{} versionInfo := make(map[string]MajorEngineVersionInfo) @@ -175,6 +178,7 @@ func (m *cancelOnFirstQueryRDSMock) DescribeDBMajorEngineVersions( // Caller cancellation must remain terminal even when the SDK wraps the error. func TestQueryMajorEngineVersionsWithClient_CtxCancelIsTerminal(t *testing.T) { + t.Parallel() tests := []struct { name string wrap func(error) error @@ -212,6 +216,7 @@ func TestQueryMajorEngineVersionsWithClient_CtxCancelIsTerminal(t *testing.T) { // TestQueryMajorEngineVersionsWithClient_CtxDeadlineIsTerminal asserts the same // for an expired deadline (issue #1325): it fails fast before the first call. func TestQueryMajorEngineVersionsWithClient_CtxDeadlineIsTerminal(t *testing.T) { + t.Parallel() ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Minute)) defer cancel() @@ -225,6 +230,7 @@ func TestQueryMajorEngineVersionsWithClient_CtxDeadlineIsTerminal(t *testing.T) } func TestQueryMajorEngineVersionsWithClient_CtxAlreadyCanceled(t *testing.T) { + t.Parallel() ctx, cancel := context.WithCancel(context.Background()) cancel() @@ -258,6 +264,7 @@ func (m *cancelOnFinalSuccessRDSMock) DescribeDBMajorEngineVersions( } func TestQueryMajorEngineVersionsWithClient_CtxCanceledOnFinalSuccess(t *testing.T) { + t.Parallel() ctx, cancel := context.WithCancel(context.Background()) defer cancel() mock := &cancelOnFinalSuccessRDSMock{cancel: cancel} diff --git a/cmd/multi_service_engine_versions_test.go b/cmd/multi_service_engine_versions_test.go index 9bcf1a57e..12f6b7033 100644 --- a/cmd/multi_service_engine_versions_test.go +++ b/cmd/multi_service_engine_versions_test.go @@ -14,6 +14,7 @@ import ( ) func TestExtractMajorVersion_Additional(t *testing.T) { + t.Parallel() tests := []struct { name string engine string @@ -73,6 +74,7 @@ func TestExtractMajorVersion_Additional(t *testing.T) { } func TestIsInExtendedSupport(t *testing.T) { + t.Parallel() now := time.Now() pastDate := now.AddDate(0, -6, 0) futureDate := now.AddDate(3, 0, 0) diff --git a/cmd/multi_service_extended_support_unavailable_test.go b/cmd/multi_service_extended_support_unavailable_test.go index 00c127622..5ea4e748e 100644 --- a/cmd/multi_service_extended_support_unavailable_test.go +++ b/cmd/multi_service_extended_support_unavailable_test.go @@ -196,6 +196,7 @@ func queryRegions(t *testing.T, stub *rdsAPIStub, ctx context.Context) (map[stri } func TestQueryRDSInstancesInRegions_AllRegionsFail(t *testing.T) { + t.Parallel() stub := newRDSStub("us-east-1", "eu-west-1") stub.failRegions["us-east-1"], stub.failRegions["eu-west-1"] = true, true @@ -208,6 +209,7 @@ func TestQueryRDSInstancesInRegions_AllRegionsFail(t *testing.T) { } func TestQueryRDSInstancesInRegions_FailureMidPaginationMarksRegionFailed(t *testing.T) { + t.Parallel() stub := newRDSStub("us-east-1", "eu-west-1") stub.failPage2["us-east-1"] = true stub.instances["us-east-1"], stub.instances["eu-west-1"] = "db.r5.large", "db.t3.small" @@ -221,6 +223,7 @@ func TestQueryRDSInstancesInRegions_FailureMidPaginationMarksRegionFailed(t *tes } func TestQueryRDSInstancesInRegions_WorkerPanicMarksRegionFailed(t *testing.T) { + t.Parallel() stub := newRDSStub("us-east-1", "eu-west-1") stub.panicRegions["us-east-1"] = true stub.instances["eu-west-1"] = "db.t3.small" @@ -233,6 +236,7 @@ func TestQueryRDSInstancesInRegions_WorkerPanicMarksRegionFailed(t *testing.T) { } func TestQueryRDSInstancesInRegions_GenuineEmptyInventoryIsNotAFailure(t *testing.T) { + t.Parallel() stub := newRDSStub("us-east-1", "eu-west-1") inst, failed, err := queryRegions(t, stub, context.Background()) @@ -243,6 +247,7 @@ func TestQueryRDSInstancesInRegions_GenuineEmptyInventoryIsNotAFailure(t *testin } func TestQueryRDSInstancesInRegions_CancelledContextIsTerminal(t *testing.T) { + t.Parallel() stub := newRDSStub("us-east-1") ctx, cancel := context.WithCancel(context.Background()) regions, err := getAWSRegions(ctx, stub.awsConfig()) @@ -256,6 +261,7 @@ func TestQueryRDSInstancesInRegions_CancelledContextIsTerminal(t *testing.T) { } func TestQueryMajorEngineVersionsWithClient_EngineFailuresAreAggregated(t *testing.T) { + t.Parallel() denied := errors.New("AccessDenied") t.Run("all engines fail", func(t *testing.T) { stub := &engineKeyedRDSMajorVersionsStub{errByEngine: map[string]error{ @@ -289,6 +295,7 @@ func TestQueryMajorEngineVersionsWithClient_EngineFailuresAreAggregated(t *testi } func TestQueryMajorEngineVersionsWithClient_PaginationCapIsAnError(t *testing.T) { + t.Parallel() _, err := queryMajorEngineVersionsWithClient(context.Background(), &alwaysMarkerRDSStub{}) require.Error(t, err) assert.ErrorContains(t, err, "pagination cap") @@ -370,6 +377,7 @@ func rdsRec(region string) common.Recommendation { } func TestRequireRegionInventory(t *testing.T) { + t.Parallel() data := engineVersionData{failedRegions: map[string]error{"eu-west-1": errors.New("denied")}} assert.ErrorContains(t, requireRegionInventory([]common.Recommendation{rdsRec("eu-west-1")}, Config{}, data), "eu-west-1") diff --git a/cmd/multi_service_extract_major_version_test.go b/cmd/multi_service_extract_major_version_test.go index dcf30b6cd..f97f8569d 100644 --- a/cmd/multi_service_extract_major_version_test.go +++ b/cmd/multi_service_extract_major_version_test.go @@ -8,6 +8,7 @@ import ( // Comprehensive tests for extractMajorVersion function. func TestExtractMajorVersion_Comprehensive(t *testing.T) { + t.Parallel() tests := []struct { name string engine string diff --git a/cmd/multi_service_filters_savings_plans_test.go b/cmd/multi_service_filters_savings_plans_test.go index 77d227673..98853abca 100644 --- a/cmd/multi_service_filters_savings_plans_test.go +++ b/cmd/multi_service_filters_savings_plans_test.go @@ -15,6 +15,7 @@ import ( // --exclude-regions. The provider-side filters were fixed first; these cases // pin the same semantics on the CLI path. func TestApplyFilters_SavingsPlansRegionFilters(t *testing.T) { + t.Parallel() ec2SP := func(region string) common.Recommendation { return common.Recommendation{ Provider: common.ProviderAWS, @@ -113,6 +114,7 @@ func TestApplyFilters_SavingsPlansRegionFilters(t *testing.T) { // account-level plans stay unfiltered, and that it ANDs with // --include-regions / --exclude-regions. func TestApplyFilters_SavingsPlansRegionsFlag(t *testing.T) { + t.Parallel() sp := func(svc common.ServiceType, planType, region string) common.Recommendation { return common.Recommendation{ Provider: common.ProviderAWS, diff --git a/cmd/multi_service_filters_test.go b/cmd/multi_service_filters_test.go index 75a322161..bac374596 100644 --- a/cmd/multi_service_filters_test.go +++ b/cmd/multi_service_filters_test.go @@ -185,6 +185,7 @@ func TestApplyFilters_DropExtendedSupport(t *testing.T) { // --regions does not narrow Savings Plan rows loaded from --input-csv: CSV // rows carry no Provider or CommitmentType, so they are used as supplied. func TestApplyFilters_SavingsPlansRegionsFlagCSVModeUnchanged(t *testing.T) { + t.Parallel() csvPath := filepath.Join(t.TempDir(), "sp.csv") content := `Service,Region,ResourceType,Count,Term,PaymentOption,PlanType,HourlyCommitment,InstanceFamily,DetailsRegion savings-plans-compute,,,1,1yr,no-upfront,Compute,1.5,, @@ -206,6 +207,7 @@ savings-plans-ec2instance,,,1,1yr,no-upfront,EC2Instance,1.5,m5,us-east-1 // its plan region (Details.Region), as on the main path, while --regions alone // still leaves it alone (#2228). func TestApplyFilters_SavingsPlansIncludeRegionsCSVMode(t *testing.T) { + t.Parallel() csvPath := filepath.Join(t.TempDir(), "sp.csv") content := `Service,Region,ResourceType,Count,Term,PaymentOption,PlanType,HourlyCommitment,InstanceFamily,DetailsRegion savings-plans-ec2instance,,,1,1yr,no-upfront,EC2Instance,1.5,m5,us-east-1 @@ -236,6 +238,7 @@ savings-plans-ec2instance,,,1,1yr,no-upfront,EC2Instance,1.5,m5,us-east-1 } func TestRequireExactExcludes(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ { Account: "123456789012", @@ -285,6 +288,7 @@ const ( ) func TestApplyFilters_UnidentifiedAccountUnderInclude(t *testing.T) { + t.Parallel() unidentified := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1} named := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1, Account: testUnidentifiedAcct, AccountName: "prod"} tests := []struct { @@ -312,6 +316,7 @@ func TestApplyFilters_UnidentifiedAccountUnderInclude(t *testing.T) { } func TestApplyFilters_UnidentifiedAccountUnderExclude(t *testing.T) { + t.Parallel() unidentified := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1} named := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1, Account: testUnidentifiedAcct, AccountName: "prod"} other := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1, Account: testOtherAcct, AccountName: "dev"} @@ -341,6 +346,7 @@ func TestApplyFilters_UnidentifiedAccountUnderExclude(t *testing.T) { } func TestCSVExcludeOnly_UnidentifiedRowFilteredOutWithoutError(t *testing.T) { + t.Parallel() unidentified := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1} other := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro", Count: 1, Account: testOtherAcct, AccountName: "dev"} cfg := Config{IncludeExtendedSupport: true, ExcludeAccounts: []string{testUnidentifiedAcct}} @@ -354,6 +360,7 @@ func TestCSVExcludeOnly_UnidentifiedRowFilteredOutWithoutError(t *testing.T) { } func TestPopulateRecommendationAccountNames_UnidentifiedRecUnderExcludeOnly(t *testing.T) { + t.Parallel() cache := NewAccountAliasCacheWithClient(&MockOrganizationsClient{}) recs := []common.Recommendation{{Service: common.ServiceRDS, Region: "us-east-1", ResourceType: "db.t3.micro"}} diff --git a/cmd/multi_service_helpers_test.go b/cmd/multi_service_helpers_test.go index 4202c7a3d..309ae9f78 100644 --- a/cmd/multi_service_helpers_test.go +++ b/cmd/multi_service_helpers_test.go @@ -12,6 +12,7 @@ import ( ) func TestFormatServices(t *testing.T) { + t.Parallel() tests := []struct { name string expected string @@ -48,6 +49,7 @@ func TestFormatServices(t *testing.T) { } func TestGetServiceDisplayName(t *testing.T) { + t.Parallel() tests := []struct { service common.ServiceType expected string @@ -314,6 +316,7 @@ func TestCheckDuplicates_ErrorOnDryRun_ContinuesUnadjusted(t *testing.T) { } func TestGroupRecommendationsByServiceRegion(t *testing.T) { + t.Parallel() tests := []struct { expectedGroups map[common.ServiceType]map[string]int name string @@ -383,6 +386,7 @@ func TestGroupRecommendationsByServiceRegion(t *testing.T) { } func TestGenerateCSVFilename(t *testing.T) { + t.Parallel() tests := []struct { check func(t *testing.T, filename string) name string diff --git a/cmd/multi_service_max_instances_test.go b/cmd/multi_service_max_instances_test.go index 0d09f20d6..9a781e834 100644 --- a/cmd/multi_service_max_instances_test.go +++ b/cmd/multi_service_max_instances_test.go @@ -275,6 +275,7 @@ func TestMaxInstancesNeverPurchasesBelowMinCount(t *testing.T) { // the boundary (a truncated count exactly equal to the floor is kept) and the // disabled case. func TestDropTruncatedBelowMinCount(t *testing.T) { + t.Parallel() tests := []struct { name string counts []int @@ -388,6 +389,7 @@ func TestApplyGlobalInstanceLimit(t *testing.T) { // non-positive Count cannot raise the remaining budget and let later // recommendations push the run past the cap. func TestApplyInstanceLimitNonPositiveCountDoesNotCreditBudget(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ {ResourceType: "a", Count: 4}, {ResourceType: "b", Count: -10}, diff --git a/cmd/multi_service_rds_instances_pages_test.go b/cmd/multi_service_rds_instances_pages_test.go index 4e7b0218c..bfc73aa25 100644 --- a/cmd/multi_service_rds_instances_pages_test.go +++ b/cmd/multi_service_rds_instances_pages_test.go @@ -26,6 +26,7 @@ func (c *loopingRDSInstancesClient) DescribeDBInstances(_ context.Context, _ *aw } func TestQueryRDSInstancesPaged_PageCapErrors(t *testing.T) { + t.Parallel() client := &loopingRDSInstancesClient{} var mu sync.Mutex err := queryRDSInstancesPaged(context.Background(), client, "eu-west-1", map[string][]InstanceEngineVersion{}, &mu) @@ -35,6 +36,7 @@ func TestQueryRDSInstancesPaged_PageCapErrors(t *testing.T) { } func TestQueryRDSInstancesPaged_CanceledContextStops(t *testing.T) { + t.Parallel() ctx, cancel := context.WithCancel(context.Background()) client := &loopingRDSInstancesClient{onCall: cancel} var mu sync.Mutex diff --git a/cmd/multi_service_should_include_test.go b/cmd/multi_service_should_include_test.go index 8b259c3c9..5e2690194 100644 --- a/cmd/multi_service_should_include_test.go +++ b/cmd/multi_service_should_include_test.go @@ -303,6 +303,7 @@ func TestShouldIncludeEngine(t *testing.T) { } func TestShouldIncludePoolSize(t *testing.T) { + t.Parallel() tests := []struct { name string avg float64 @@ -326,6 +327,7 @@ func TestShouldIncludePoolSize(t *testing.T) { } func TestShouldIncludeAccountIDOrNameExactMatch(t *testing.T) { + t.Parallel() const id = "123456789012" tests := []struct { name string diff --git a/cmd/multi_service_stats_plan_types_test.go b/cmd/multi_service_stats_plan_types_test.go index 8875d1b01..e67e931eb 100644 --- a/cmd/multi_service_stats_plan_types_test.go +++ b/cmd/multi_service_stats_plan_types_test.go @@ -16,6 +16,7 @@ func spRec(service common.ServiceType, planType string, savings float64) common. } func TestSPSummaryCountsEveryPlanType(t *testing.T) { + t.Parallel() tests := []struct { name string rec common.Recommendation @@ -50,6 +51,7 @@ func TestSPSummaryCountsEveryPlanType(t *testing.T) { } func TestSPSummaryTotalsAddUp(t *testing.T) { + t.Parallel() recs := []common.Recommendation{ spRec(common.ServiceSavingsPlansCompute, "Compute", 1), spRec(common.ServiceSavingsPlansEC2Instance, "EC2Instance", 2), @@ -75,6 +77,7 @@ func TestPrintSPTypeSummariesShowsOther(t *testing.T) { } func TestCollectRISavingsLegacyAndCanonical(t *testing.T) { + t.Parallel() tests := []struct { service common.ServiceType wantEC2 float64 diff --git a/cmd/multi_service_stats_test.go b/cmd/multi_service_stats_test.go index 8172daff8..77fd4244b 100644 --- a/cmd/multi_service_stats_test.go +++ b/cmd/multi_service_stats_test.go @@ -52,6 +52,7 @@ func captureAppOutput(t *testing.T, fn func()) string { } func TestCalculateServiceStats(t *testing.T) { + t.Parallel() tests := []struct { name string service common.ServiceType diff --git a/cmd/multi_service_test.go b/cmd/multi_service_test.go index 6ca95c242..8fca751b8 100644 --- a/cmd/multi_service_test.go +++ b/cmd/multi_service_test.go @@ -25,6 +25,7 @@ import ( // ==================== Helper Function Tests ==================== func TestApplyCoverageToRecommendations(t *testing.T) { + t.Parallel() tests := []struct { name string recs []common.Recommendation @@ -119,6 +120,7 @@ func TestRunPurchaseAndReportDeclinedConfirmationPrintsDropsBeforeCancellation(t } func TestServiceProcessingOrder(t *testing.T) { + t.Parallel() // Test that services are processed in a consistent order services := []common.ServiceType{ common.ServiceRDS, @@ -150,6 +152,7 @@ func TestServiceProcessingOrder(t *testing.T) { } func TestGenerateCSVFilenameHelper(t *testing.T) { + t.Parallel() tests := []struct { name string service common.ServiceType @@ -188,6 +191,7 @@ func TestGenerateCSVFilenameHelper(t *testing.T) { } func TestMultiServiceConfig(t *testing.T) { + t.Parallel() cfg := MultiServiceConfig{ Services: map[common.ServiceType]ServiceConfig{ common.ServiceRDS: { diff --git a/cmd/purchase_account_guard_test.go b/cmd/purchase_account_guard_test.go index b9dbb51b7..7695eeacb 100644 --- a/cmd/purchase_account_guard_test.go +++ b/cmd/purchase_account_guard_test.go @@ -19,6 +19,7 @@ const ( ) func TestCheckPurchaseAccount(t *testing.T) { + t.Parallel() rec := common.Recommendation{Service: common.ServiceRDS, Region: "us-east-1", Account: testCallerAccount} require.NoError(t, checkPurchaseAccount(rec, testCallerAccount)) diff --git a/cmd/purchase_failure_exit_2157_test.go b/cmd/purchase_failure_exit_2157_test.go index 54c147a55..f14809a77 100644 --- a/cmd/purchase_failure_exit_2157_test.go +++ b/cmd/purchase_failure_exit_2157_test.go @@ -165,6 +165,7 @@ func TestPrintFinalMessage_SavingsPlanOnlySuccessShowsCompletion(t *testing.T) { } func TestPurchaseFailureError(t *testing.T) { + t.Parallel() ok := common.PurchaseResult{Success: true} bad := common.PurchaseResult{Success: false} assert.NoError(t, purchaseFailureError(nil, false)) diff --git a/cmd/purchase_safeguards_2121_test.go b/cmd/purchase_safeguards_2121_test.go index 3489b2cec..baa396845 100644 --- a/cmd/purchase_safeguards_2121_test.go +++ b/cmd/purchase_safeguards_2121_test.go @@ -61,6 +61,7 @@ func TestApplyTargetCoverage_InvalidInputsDropped_2121(t *testing.T) { } func TestDuplicateChecker_ValkeyDoesNotCoverRedis_2121(t *testing.T) { + t.Parallel() ctx := context.Background() recent := time.Now().Add(-1 * time.Hour) commitment := func(engine string) common.Commitment { @@ -119,6 +120,7 @@ func TestDuplicateChecker_ValkeyDoesNotCoverRedis_2121(t *testing.T) { } func TestDuplicateChecker_UnknownReservationStateRemainsOwned_2121(t *testing.T) { + t.Parallel() ctx := context.Background() recs := []common.Recommendation{{ Provider: common.ProviderAWS, diff --git a/cmd/purchase_succeeded_summaries_2205_test.go b/cmd/purchase_succeeded_summaries_2205_test.go index 3b09e9650..3419aa051 100644 --- a/cmd/purchase_succeeded_summaries_2205_test.go +++ b/cmd/purchase_succeeded_summaries_2205_test.go @@ -47,6 +47,7 @@ func containsVerify(s string) bool { } func TestAuditStopMessage_SuccessWithErrorReportsError(t *testing.T) { + t.Parallel() msg := auditStopMessage(1, 2, []common.PurchaseResult{succeededWithError()}, errors.New("cause")) assert.Contains(t, msg, "(errored: x)") assert.NotContains(t, msg, "(commitment") @@ -58,6 +59,7 @@ func TestAuditStopMessage_SuccessWithErrorReportsError(t *testing.T) { } func TestCalculateServiceStats_SuccessWithErrorCountsFailed(t *testing.T) { + t.Parallel() results := []common.PurchaseResult{ {Success: true}, succeededWithError(), @@ -70,6 +72,7 @@ func TestCalculateServiceStats_SuccessWithErrorCountsFailed(t *testing.T) { } func TestPurchaseFailureError_SuccessWithErrorIsFailure(t *testing.T) { + t.Parallel() err := purchaseFailureError([]common.PurchaseResult{{Success: true}, succeededWithError()}, false) assert.ErrorIs(t, err, errPurchasesFailed) assert.Contains(t, err.Error(), "1 of 2") diff --git a/cmd/savings_plan_purchase_test.go b/cmd/savings_plan_purchase_test.go index aa5cfc76a..ffecb6b78 100644 --- a/cmd/savings_plan_purchase_test.go +++ b/cmd/savings_plan_purchase_test.go @@ -45,6 +45,7 @@ func spRow(commit float64) common.Recommendation { } func TestRejectDuplicateSavingsPlanRows(t *testing.T) { + t.Parallel() t.Run("identical rows rejected", func(t *testing.T) { err := rejectDuplicateSavingsPlanRows([]common.Recommendation{spRow(1.5), spRow(1.5)}) require.Error(t, err) @@ -203,6 +204,7 @@ func TestProcessCSVRegionPurchases_SavingsPlanRowWithEmptyRegionAndProvider(t *t } func TestClientRegionFor(t *testing.T) { + t.Parallel() for _, svc := range []common.ServiceType{ common.ServiceSavingsPlansCompute, common.ServiceSavingsPlansEC2Instance, common.ServiceSavingsPlansSageMaker, common.ServiceSavingsPlansDatabase, @@ -222,6 +224,7 @@ func TestClientRegionFor(t *testing.T) { } func TestClientRegionFor_SavingsPlansAllNeverGetsARegion(t *testing.T) { + t.Parallel() for _, recRegion := range []string{"", "us-east-1"} { _, err := clientRegionFor(common.ServiceSavingsPlansAll, recRegion) assert.Error(t, err, "rec region %q", recRegion) @@ -230,6 +233,7 @@ func TestClientRegionFor_SavingsPlansAllNeverGetsARegion(t *testing.T) { } func TestPurchaseRegionLabel(t *testing.T) { + t.Parallel() ec2sp := parserShapedSP() ec2sp.Details = &common.SavingsPlanDetails{PlanType: "EC2Instance", Region: "eu-west-1"} assert.Equal(t, "eu-west-1", purchaseRegionLabel(ec2sp, "")) @@ -252,6 +256,7 @@ func validEC2InstanceSP() common.Recommendation { } func TestValidatePurchasePreconditions(t *testing.T) { + t.Parallel() mut := func(base common.Recommendation, f func(*common.Recommendation)) common.Recommendation { f(&base) return base @@ -302,6 +307,7 @@ func TestValidatePurchasePreconditions(t *testing.T) { // TestValidatePurchasePreconditions_CommitmentBounds mirrors the library's // spcommitment.Normalize bounds (0.001..1e6, positive, finite). func TestValidatePurchasePreconditions_CommitmentBounds(t *testing.T) { + t.Parallel() withCommitment := func(c float64) common.Recommendation { rec := parserShapedSP() rec.Details = &common.SavingsPlanDetails{PlanType: "Compute", HourlyCommitment: c} @@ -350,6 +356,7 @@ func TestProcessPurchaseLoop_DryRunReportsPreconditionFailureOnCSVShapedRows(t * } func TestCSVRoundTrip_SavingsPlanAndEC2DetailsSurviveWriteThenRead(t *testing.T) { + t.Parallel() compute := parserShapedSP() compute.Details = &common.SavingsPlanDetails{PlanType: "Compute", HourlyCommitment: 0.123456} ec2sp := validEC2InstanceSP() @@ -389,6 +396,7 @@ func TestCSVRoundTrip_SavingsPlanAndEC2DetailsSurviveWriteThenRead(t *testing.T) } func TestCSVWriter_AppendsDetailColumnsWithoutReorderingExistingOnes(t *testing.T) { + t.Parallel() path := filepath.Join(t.TempDir(), "report.csv") require.NoError(t, writeMultiServiceCSVReport([]common.PurchaseResult{{Recommendation: parserShapedSP(), Timestamp: time.Now()}}, path)) f, err := os.Open(path) @@ -408,6 +416,7 @@ func TestCSVWriter_AppendsDetailColumnsWithoutReorderingExistingOnes(t *testing. } func TestCSVReader_MalformedHourlyCommitmentRejected(t *testing.T) { + t.Parallel() path := filepath.Join(t.TempDir(), "in.csv") content := "Service,Region,ResourceType,Count,PlanType,HourlyCommitment,Term,PaymentOption\nsavings-plans-compute,,Compute,1,Compute,abc,1yr,no-upfront\n" require.NoError(t, os.WriteFile(path, []byte(content), 0o600)) diff --git a/cmd/savings_plan_region_test.go b/cmd/savings_plan_region_test.go index a9f42b2dd..9d85f0ce2 100644 --- a/cmd/savings_plan_region_test.go +++ b/cmd/savings_plan_region_test.go @@ -41,6 +41,7 @@ func TestFetchRecommendationsForRegion_SavingsPlanRowsCarryDetailsRegion(t *test } func TestWriteCSV_SavingsPlanRowHasRegionFamilyAndHourlyCommitment(t *testing.T) { + t.Parallel() rec := ec2InstanceSPRow() rec.Region = "eu-west-2" path := filepath.Join(t.TempDir(), "out.csv") diff --git a/cmd/secrets_store_test.go b/cmd/secrets_store_test.go index 55f424a18..f53141d72 100644 --- a/cmd/secrets_store_test.go +++ b/cmd/secrets_store_test.go @@ -26,6 +26,7 @@ func listStore(arns ...string) *MockSecretsStore { } func TestResolveSecretID(t *testing.T) { + t.Parallel() tests := []struct { name string arns []string @@ -51,6 +52,7 @@ func TestResolveSecretID(t *testing.T) { } func TestStoreAzureCredentials_SkipsPrefixMatch(t *testing.T) { + t.Parallel() store := listStore(oldARN, wantedARN) creds := AzureCredentials{TenantID: testTenantID, ClientID: testSPAppID, ClientSecret: testSPSecret, SubscriptionID: testSubID} require.NoError(t, storeAzureCredentials(context.Background(), store, "cudly", creds)) @@ -59,6 +61,7 @@ func TestStoreAzureCredentials_SkipsPrefixMatch(t *testing.T) { } func TestStoreGCPCredentials_SkipsPrefixMatch(t *testing.T) { + t.Parallel() gcpOld := arnPrefix + "cudly-GCPCredentials-old-GhIjKl" gcpWanted := arnPrefix + "cudly-GCPCredentials-AbCdEf" store := listStore(gcpOld, gcpWanted) @@ -91,6 +94,7 @@ func (f *fakeSecretsClient) UpdateSecret(context.Context, *secretsmanager.Update } func TestAWSSecretsStore_ListSecretsPaginates(t *testing.T) { + t.Parallel() fake := &fakeSecretsClient{pages: []*secretsmanager.ListSecretsOutput{ {SecretList: []secretsmgrtypes.SecretListEntry{{ARN: aws.String(oldARN)}}, NextToken: aws.String("t2")}, {SecretList: []secretsmgrtypes.SecretListEntry{{ARN: aws.String(wantedARN)}}}, @@ -103,6 +107,7 @@ func TestAWSSecretsStore_ListSecretsPaginates(t *testing.T) { } func TestAWSSecretsStore_ListSecretsFailsAtPageCap(t *testing.T) { + t.Parallel() fake := &fakeSecretsClient{loop: true} _, err := (&AWSSecretsStore{client: fake}).ListSecrets(context.Background(), wantedName) require.ErrorContains(t, err, "pagination cap") @@ -110,6 +115,7 @@ func TestAWSSecretsStore_ListSecretsFailsAtPageCap(t *testing.T) { } func TestAWSSecretsStore_ListSecretsHonorsCanceledContext(t *testing.T) { + t.Parallel() ctx, cancel := context.WithCancel(context.Background()) cancel() fake := &fakeSecretsClient{loop: true} @@ -118,6 +124,7 @@ func TestAWSSecretsStore_ListSecretsHonorsCanceledContext(t *testing.T) { } func TestResolveSecretID_ListErrorFails(t *testing.T) { + t.Parallel() m := NewMockSecretsStore() m.listSecretsFunc = func(context.Context, string) ([]string, error) { return nil, errors.New("AccessDenied") } _, err := resolveSecretID(context.Background(), m, wantedName) diff --git a/cmd/validators_test.go b/cmd/validators_test.go index d34305831..65b3dee81 100644 --- a/cmd/validators_test.go +++ b/cmd/validators_test.go @@ -259,6 +259,7 @@ func TestValidatePaymentAndTerm(t *testing.T) { } func TestContainsService(t *testing.T) { + t.Parallel() tests := []struct { name string service common.ServiceType @@ -302,6 +303,7 @@ func TestContainsService(t *testing.T) { } func TestValidateNoConflicts(t *testing.T) { + t.Parallel() tests := []struct { name string itemType string From 959f00e5a207e4d9736bfe9a47f79be93e39bf00 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Tue, 20 Oct 2026 05:30:46 +0200 Subject: [PATCH 2/2] chore(tests): keep SIGINT test serial Co-Authored-By: Claude Opus 5.5 --- cmd/cancellation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cancellation_test.go b/cmd/cancellation_test.go index 39ac03488..c52ca3683 100644 --- a/cmd/cancellation_test.go +++ b/cmd/cancellation_test.go @@ -265,7 +265,7 @@ func TestRegisterShutdownSignalHandler_CancelSetsFlagAndPrintsNoticeOnce(t *test // handler would return and the second signal below would terminate the test // binary. func TestInvocationContext_FurtherSigintsAreAbsorbed(t *testing.T) { - t.Parallel() + // Serial: syscall.Kill(SIGINT) is process-wide and would hit any parallel test that installs a handler. ctx, stop := invocationContext() defer stop()