@@ -323,3 +323,124 @@ func TestAttributeRequirementLevelUnmarshalText(t *testing.T) {
323323 })
324324 }
325325}
326+
327+ func TestValidateFeatureGates (t * testing.T ) {
328+ tests := []struct {
329+ name string
330+ featureGate FeatureGate
331+ gateID FeatureGateID
332+ wantErr string
333+ }{
334+ {
335+ name : "valid alpha gate" ,
336+ gateID : "component.feature" ,
337+ featureGate : FeatureGate {
338+ Description : "Test feature gate" ,
339+ Stage : FeatureGateStageAlpha ,
340+ FromVersion : "v0.100.0" ,
341+ ReferenceURL : "https://example.com" ,
342+ },
343+ },
344+ {
345+ name : "valid stable gate with to_version" ,
346+ gateID : "component.stable" ,
347+ featureGate : FeatureGate {
348+ Description : "Stable feature gate" ,
349+ Stage : FeatureGateStageStable ,
350+ FromVersion : "v0.90.0" ,
351+ ToVersion : "v0.95.0" ,
352+ },
353+ },
354+ {
355+ name : "empty description" ,
356+ gateID : "component.feature" ,
357+ featureGate : FeatureGate {
358+ Stage : FeatureGateStageAlpha ,
359+ FromVersion : "v0.100.0" ,
360+ },
361+ wantErr : `description is required` ,
362+ },
363+ {
364+ name : "invalid stage" ,
365+ gateID : "component.feature" ,
366+ featureGate : FeatureGate {
367+ Description : "Test feature" ,
368+ Stage : "invalid" ,
369+ FromVersion : "v0.100.0" ,
370+ },
371+ wantErr : `invalid stage "invalid"` ,
372+ },
373+ {
374+ name : "from_version without v prefix" ,
375+ gateID : "component.feature" ,
376+ featureGate : FeatureGate {
377+ Description : "Test feature" ,
378+ Stage : FeatureGateStageAlpha ,
379+ FromVersion : "0.100.0" ,
380+ },
381+ wantErr : `from_version "0.100.0" must start with 'v'` ,
382+ },
383+ {
384+ name : "to_version without v prefix" ,
385+ gateID : "component.feature" ,
386+ featureGate : FeatureGate {
387+ Description : "Test feature" ,
388+ Stage : FeatureGateStageStable ,
389+ FromVersion : "v0.90.0" ,
390+ ToVersion : "0.95.0" ,
391+ },
392+ wantErr : `to_version "0.95.0" must start with 'v'` ,
393+ },
394+ {
395+ name : "stable gate missing to_version" ,
396+ gateID : "component.feature" ,
397+ featureGate : FeatureGate {
398+ Description : "Test feature" ,
399+ Stage : FeatureGateStageStable ,
400+ FromVersion : "v0.90.0" ,
401+ },
402+ wantErr : `to_version is required for stable stage gates` ,
403+ },
404+ {
405+ name : "deprecated gate missing to_version" ,
406+ gateID : "component.feature" ,
407+ featureGate : FeatureGate {
408+ Description : "Test feature" ,
409+ Stage : FeatureGateStageDeprecated ,
410+ FromVersion : "v0.90.0" ,
411+ },
412+ wantErr : `to_version is required for deprecated stage gates` ,
413+ },
414+ }
415+
416+ for _ , tt := range tests {
417+ t .Run (tt .name , func (t * testing.T ) {
418+ md := & Metadata {
419+ FeatureGates : map [FeatureGateID ]FeatureGate {
420+ tt .gateID : tt .featureGate ,
421+ },
422+ }
423+ err := md .validateFeatureGates ()
424+ if tt .wantErr != "" {
425+ require .Error (t , err )
426+ assert .ErrorContains (t , err , tt .wantErr )
427+ } else {
428+ require .NoError (t , err )
429+ }
430+ })
431+ }
432+ }
433+
434+ func TestValidateFeatureGatesEmptyID (t * testing.T ) {
435+ md := & Metadata {
436+ FeatureGates : map [FeatureGateID ]FeatureGate {
437+ "" : {
438+ Description : "Test" ,
439+ Stage : FeatureGateStageAlpha ,
440+ },
441+ },
442+ }
443+ err := md .validateFeatureGates ()
444+ require .Error (t , err )
445+ assert .ErrorContains (t , err , "feature gate ID cannot be empty" )
446+ }
0 commit comments