@@ -20,11 +20,12 @@ import (
2020)
2121
2222const (
23- testVPC = "abc"
24- testAttachment = "def"
25- testVPCHex1234 = "0000000004d2" // decimal 1234
26- testRD65000_1 = "65000:1" // RD/RT for ASN 65000, NN 1
27- testContainerID = "test-container"
23+ testVPC = "abc"
24+ testAttachment = "def"
25+ testVPCHex1234 = "0000000004d2" // decimal 1234
26+ testRD65000_1 = "65000:1" // RD/RT for ASN 65000, NN 1
27+ testContainerID = "test-container"
28+ testInvalidBase62 = "abc-def" // shared invalid base62 string for tests
2829)
2930
3031func fakeClient (objs ... client.Object ) client.Client {
@@ -127,6 +128,82 @@ func TestParseConf(t *testing.T) {
127128 ),
128129 wantErr : `invalid interface_type "unknown": must be "veth" or "tap"` ,
129130 },
131+ {
132+ name : "missing vpc" ,
133+ input : fmt .Sprintf (
134+ `{"cniVersion":"1.0.0","name":"test",` +
135+ `"type":"galactic-cni","vpcattachment":"%s"}` ,
136+ testAttachment ,
137+ ),
138+ wantErr : "vpc is required and must be a non-empty base62 string" ,
139+ },
140+ {
141+ name : "empty vpc" ,
142+ input : fmt .Sprintf (
143+ `{"cniVersion":"1.0.0","name":"test",` +
144+ `"type":"galactic-cni","vpc":"",` +
145+ `"vpcattachment":"%s"}` ,
146+ testAttachment ,
147+ ),
148+ wantErr : "vpc is required and must be a non-empty base62 string" ,
149+ },
150+ {
151+ name : "vpc with invalid char hyphen" ,
152+ input : fmt .Sprintf (
153+ `{"cniVersion":"1.0.0","name":"test",` +
154+ `"type":"galactic-cni","vpc":"%s",` +
155+ `"vpcattachment":"%s"}` ,
156+ testInvalidBase62 , testAttachment ,
157+ ),
158+ wantErr : fmt .Sprintf ("invalid base62 value for field 'vpc': %q" , testInvalidBase62 ),
159+ },
160+ {
161+ name : "vpc with invalid char underscore" ,
162+ input : fmt .Sprintf (
163+ `{"cniVersion":"1.0.0","name":"test",` +
164+ `"type":"galactic-cni","vpc":"abc_def",` +
165+ `"vpcattachment":"%s"}` ,
166+ testAttachment ,
167+ ),
168+ wantErr : `invalid base62 value for field 'vpc': "abc_def"` ,
169+ },
170+ {
171+ name : "missing vpcattachment" ,
172+ input : fmt .Sprintf (
173+ `{"cniVersion":"1.0.0","name":"test",` +
174+ `"type":"galactic-cni","vpc":"%s"}` ,
175+ testVPC ,
176+ ),
177+ wantErr : "vpcattachment is required and must be a non-empty base62 string" ,
178+ },
179+ {
180+ name : "empty vpcattachment" ,
181+ input : fmt .Sprintf (
182+ `{"cniVersion":"1.0.0","name":"test",` +
183+ `"type":"galactic-cni","vpc":"%s",` +
184+ `"vpcattachment":""}` ,
185+ testVPC ,
186+ ),
187+ wantErr : "vpcattachment is required and must be a non-empty base62 string" ,
188+ },
189+ {
190+ name : "vpcattachment with invalid char space" ,
191+ input : fmt .Sprintf (
192+ `{"cniVersion":"1.0.0","name":"test",` +
193+ `"type":"galactic-cni","vpc":"%s",` +
194+ `"vpcattachment":"def ghi"}` ,
195+ testVPC ,
196+ ),
197+ wantErr : `invalid base62 value for field 'vpcattachment': "def ghi"` ,
198+ },
199+ {
200+ name : "valid vpc and vpcattachment with mixed case base62" ,
201+ input : `{"cniVersion":"1.0.0","name":"test",` +
202+ `"type":"galactic-cni","vpc":"Abc123XYZ",` +
203+ `"vpcattachment":"DeF456"}` ,
204+ wantVPC : "Abc123XYZ" ,
205+ wantIfType : interfaceTypeVeth ,
206+ },
130207 }
131208
132209 for _ , tt := range tests {
@@ -154,6 +231,67 @@ func TestParseConf(t *testing.T) {
154231 }
155232}
156233
234+ // ---- isValidBase62 -------------------------------------------------------
235+
236+ func TestIsValidBase62 (t * testing.T ) {
237+ tests := []struct {
238+ name string
239+ input string
240+ want bool
241+ }{
242+ {"empty" , "" , false },
243+ {"digits only" , "1234567890" , true },
244+ {"lowercase only" , "abcdefghij" , true },
245+ {"uppercase only" , "ABCDEFGHIJ" , true },
246+ {"mixed case" , "aBcDeFgHiJ" , true },
247+ {"mixed digits and letters" , "abc123XYZ" , true },
248+ {"hyphen" , testInvalidBase62 , false },
249+ {"underscore" , "abc_def" , false },
250+ {"space" , "abc def" , false },
251+ {"dot" , "abc.def" , false },
252+ {"slash" , "abc/def" , false },
253+ {"plus" , "abc+def" , false },
254+ {"equals" , "abc=def" , false },
255+ {"single digit" , "0" , true },
256+ {"single lowercase" , "a" , true },
257+ {"single uppercase" , "Z" , true },
258+ }
259+
260+ for _ , tt := range tests {
261+ t .Run (tt .name , func (t * testing.T ) {
262+ got := isValidBase62 (tt .input )
263+ if got != tt .want {
264+ t .Errorf ("isValidBase62(%q) = %v, want %v" , tt .input , got , tt .want )
265+ }
266+ })
267+ }
268+ }
269+
270+ func TestSanitizeForError (t * testing.T ) {
271+ printable := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()"
272+ tests := []struct {
273+ name string
274+ input string
275+ want string
276+ }{
277+ {"normal string" , testInvalidBase62 , testInvalidBase62 },
278+ {"empty" , "" , "" },
279+ {"newline" , "abc\n def" , sanitizeForErrorBinary },
280+ {"null byte" , "abc\x00 def" , sanitizeForErrorBinary },
281+ {"del char" , "abc\x7f def" , sanitizeForErrorBinary },
282+ {"printable range" , printable , printable },
283+ }
284+
285+ for _ , tt := range tests {
286+ t .Run (tt .name , func (t * testing.T ) {
287+ got := sanitizeForError (tt .input )
288+ if got != tt .want {
289+ t .Errorf ("sanitizeForError(%q) = %q, want %q" , tt .input , got , tt .want )
290+ }
291+ })
292+ }
293+ }
294+
157295// ---- bgpVRFInstanceName --------------------------------------------------
158296
159297func TestBGPVRFInstanceName (t * testing.T ) {
@@ -656,9 +794,9 @@ func TestCmdCheckMissingVPC(t *testing.T) {
656794 if err == nil {
657795 t .Fatalf ("expected error for missing VPC, got nil" )
658796 }
659- // parseConf allows empty VPC; the error comes from intf generation .
660- if ! strings .Contains (err .Error (), "CHECK failed " ) {
661- t .Fatalf ("error %q does not contain 'CHECK failed '" , err .Error ())
797+ // parseConf now rejects empty VPC before CHECK runs .
798+ if ! strings .Contains (err .Error (), "vpc is required " ) {
799+ t .Fatalf ("error %q does not contain 'vpc is required '" , err .Error ())
662800 }
663801}
664802
@@ -850,8 +988,9 @@ func TestCmdStatusMissingVPC(t *testing.T) {
850988 if err == nil {
851989 t .Fatalf ("expected error for missing VPC, got nil" )
852990 }
853- if ! strings .Contains (err .Error (), "STATUS failed" ) {
854- t .Fatalf ("error %q does not contain 'STATUS failed'" , err .Error ())
991+ // parseConf now rejects empty VPC before STATUS runs.
992+ if ! strings .Contains (err .Error (), "vpc is required" ) {
993+ t .Fatalf ("error %q does not contain 'vpc is required'" , err .Error ())
855994 }
856995}
857996
@@ -870,7 +1009,8 @@ func TestCmdStatusMissingVPCAttachment(t *testing.T) {
8701009 if err == nil {
8711010 t .Fatalf ("expected error for missing VPCAttachment, got nil" )
8721011 }
873- if ! strings .Contains (err .Error (), "STATUS failed" ) {
874- t .Fatalf ("error %q does not contain 'STATUS failed'" , err .Error ())
1012+ // parseConf now rejects empty VPCAttachment before STATUS runs.
1013+ if ! strings .Contains (err .Error (), "vpcattachment is required" ) {
1014+ t .Fatalf ("error %q does not contain 'vpcattachment is required'" , err .Error ())
8751015 }
8761016}
0 commit comments