@@ -9,7 +9,10 @@ import (
99
1010 "github.com/LeanerCloud/CUDly/pkg/common"
1111 "github.com/aws/aws-sdk-go-v2/aws"
12+ awsrds "github.com/aws/aws-sdk-go-v2/service/rds"
13+ rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
1214 "github.com/stretchr/testify/assert"
15+ "github.com/stretchr/testify/require"
1316)
1417
1518// ==================== Tests for coverage improvement ====================
@@ -18,72 +21,124 @@ import (
1821
1922// ==================== Tests for queryMajorEngineVersions ====================
2023
21- func TestQueryMajorEngineVersions_Success (t * testing.T ) {
22- // This test verifies the logic of queryMajorEngineVersions without mocking
23- // Since it requires AWS credentials, we test the error cases and structure
24+ // engineKeyedRDSMajorVersionsStub implements RDSMajorVersionsClient with
25+ // canned per-engine responses and records which engines were queried, so
26+ // queryMajorEngineVersionsWithClient can be tested hermetically (no AWS
27+ // credentials, no network).
28+ type engineKeyedRDSMajorVersionsStub struct {
29+ versionsByEngine map [string ][]rdstypes.DBMajorEngineVersion
30+ errByEngine map [string ]error
31+ enginesQueried []string
32+ }
2433
25- ctx := context .Background ()
26- origCfg := toolCfg
27- defer func () { toolCfg = origCfg }()
34+ func (s * engineKeyedRDSMajorVersionsStub ) DescribeDBMajorEngineVersions (
35+ _ context.Context ,
36+ params * awsrds.DescribeDBMajorEngineVersionsInput ,
37+ _ ... func (* awsrds.Options ),
38+ ) (* awsrds.DescribeDBMajorEngineVersionsOutput , error ) {
39+ engine := aws .ToString (params .Engine )
40+ s .enginesQueried = append (s .enginesQueried , engine )
41+ if err := s .errByEngine [engine ]; err != nil {
42+ return nil , err
43+ }
44+ return & awsrds.DescribeDBMajorEngineVersionsOutput {
45+ DBMajorEngineVersions : s .versionsByEngine [engine ],
46+ }, nil
47+ }
2848
29- // Test with empty profile (should work if AWS credentials are configured)
30- toolCfg .Profile = ""
31- toolCfg .ValidationProfile = ""
49+ // TestQueryMajorEngineVersionsWithClient_Success replaces a former
50+ // live-credential test: it stubs the RDS client and asserts the merged
51+ // engine:major-version map deterministically.
52+ func TestQueryMajorEngineVersionsWithClient_Success (t * testing.T ) {
53+ stub := & engineKeyedRDSMajorVersionsStub {
54+ versionsByEngine : map [string ][]rdstypes.DBMajorEngineVersion {
55+ "mysql" : {rdsMajorVersion ("mysql" , "5.7" ), rdsMajorVersion ("mysql" , "8.0" )},
56+ "postgres" : {rdsMajorVersion ("postgres" , "13" )},
57+ },
58+ }
3259
33- // This will attempt to load AWS config - may fail without credentials
34- result , err := queryMajorEngineVersions (ctx , toolCfg )
60+ result , err := queryMajorEngineVersionsWithClient (context .Background (), stub )
61+ require .NoError (t , err )
62+
63+ assert .ElementsMatch (t ,
64+ []string {"mysql" , "postgres" , "aurora-mysql" , "aurora-postgresql" },
65+ stub .enginesQueried ,
66+ "must query every supported engine exactly once" )
67+
68+ require .Len (t , result , 3 )
69+ assert .Equal (t , "mysql" , result ["mysql:5.7" ].Engine )
70+ assert .Equal (t , "5.7" , result ["mysql:5.7" ].MajorEngineVersion )
71+ assert .Equal (t , "8.0" , result ["mysql:8.0" ].MajorEngineVersion )
72+ assert .Equal (t , "13" , result ["postgres:13" ].MajorEngineVersion )
73+ require .Len (t , result ["postgres:13" ].SupportedEngineLifecycles , 1 ,
74+ "lifecycle data must be carried through from the API response" )
75+ }
3576
36- // Either succeeds with valid credentials or fails gracefully
37- if err != nil {
38- assert .Error (t , err )
39- assert .Contains (t , err .Error (), "failed to load AWS config" )
40- } else {
41- // If it succeeds, verify the result structure
42- assert .NotNil (t , result )
43- // Result can be empty if no versions are found
77+ // TestQueryMajorEngineVersionsWithClient_EngineErrorContinues asserts the
78+ // warn-and-continue contract: one engine failing must not drop the results
79+ // of the others, and the overall call still succeeds.
80+ func TestQueryMajorEngineVersionsWithClient_EngineErrorContinues (t * testing.T ) {
81+ stub := & engineKeyedRDSMajorVersionsStub {
82+ versionsByEngine : map [string ][]rdstypes.DBMajorEngineVersion {
83+ "postgres" : {rdsMajorVersion ("postgres" , "15" )},
84+ },
85+ errByEngine : map [string ]error {
86+ "mysql" : errors .New ("DescribeDBMajorEngineVersions throttled" ),
87+ },
4488 }
89+
90+ result , err := queryMajorEngineVersionsWithClient (context .Background (), stub )
91+ require .NoError (t , err , "per-engine API failures are warn-and-continue" )
92+
93+ assert .ElementsMatch (t ,
94+ []string {"mysql" , "postgres" , "aurora-mysql" , "aurora-postgresql" },
95+ stub .enginesQueried ,
96+ "a failing engine must not stop the remaining engine queries" )
97+ require .Len (t , result , 1 )
98+ assert .Equal (t , "15" , result ["postgres:15" ].MajorEngineVersion )
4599}
46100
47- func TestQueryMajorEngineVersions_ProfileHandling (t * testing.T ) {
101+ // TestQueryMajorEngineVersions_ProfileSelection asserts validation-profile
102+ // precedence deterministically: the configured profiles point at names
103+ // guaranteed not to exist in the (redirected, empty) shared config, so
104+ // config loading fails fast without any live AWS call and the error names
105+ // the profile the function actually selected.
106+ func TestQueryMajorEngineVersions_ProfileSelection (t * testing.T ) {
48107 ctx := context .Background ()
49- origCfg := toolCfg
50- defer func () { toolCfg = origCfg }()
51108
52109 tests := []struct {
53110 name string
54111 profile string
55112 validationProfile string
113+ wantProfileInErr string
56114 }{
57115 {
58- name : "Uses validation profile if set" ,
59- profile : "main-profile" ,
60- validationProfile : "validation-profile" ,
116+ name : "validation profile takes precedence" ,
117+ profile : "cudly-test-main-profile-does-not-exist" ,
118+ validationProfile : "cudly-test-validation-profile-does-not-exist" ,
119+ wantProfileInErr : "cudly-test-validation-profile-does-not-exist" ,
61120 },
62121 {
63- name : "Falls back to main profile" ,
64- profile : "main-profile" ,
65- validationProfile : "" ,
66- },
67- {
68- name : "Empty profiles use default" ,
69- profile : "" ,
70- validationProfile : "" ,
122+ name : "falls back to main profile" ,
123+ profile : "cudly-test-main-profile-does-not-exist" ,
124+ wantProfileInErr : "cudly-test-main-profile-does-not-exist" ,
71125 },
72126 }
73127
74128 for _ , tt := range tests {
75129 t .Run (tt .name , func (t * testing.T ) {
76- toolCfg .Profile = tt .profile
77- toolCfg .ValidationProfile = tt .validationProfile
78-
79- // This will attempt to load config - may fail without valid profiles
80- _ , err := queryMajorEngineVersions (ctx , toolCfg )
81-
82- // We just verify it doesn't panic - actual AWS calls may fail
83- // Error is acceptable for invalid profiles
84- if err != nil {
85- assert .Error (t , err )
86- }
130+ t .Setenv ("AWS_CONFIG_FILE" , os .DevNull )
131+ t .Setenv ("AWS_SHARED_CREDENTIALS_FILE" , os .DevNull )
132+
133+ _ , err := queryMajorEngineVersions (ctx , Config {
134+ Profile : tt .profile ,
135+ ValidationProfile : tt .validationProfile ,
136+ })
137+
138+ require .Error (t , err )
139+ assert .Contains (t , err .Error (), "failed to load AWS config" )
140+ assert .Contains (t , err .Error (), tt .wantProfileInErr ,
141+ "error must name the selected profile" )
87142 })
88143 }
89144}
0 commit comments