...

Source file src/k8s.io/component-base/featuregate/feature_gate_test.go

Documentation: k8s.io/component-base/featuregate

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package featuregate
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/spf13/pflag"
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	"k8s.io/component-base/metrics/legacyregistry"
    28  	featuremetrics "k8s.io/component-base/metrics/prometheus/feature"
    29  	"k8s.io/component-base/metrics/testutil"
    30  )
    31  
    32  func TestFeatureGateFlag(t *testing.T) {
    33  	// gates for testing
    34  	const testAlphaGate Feature = "TestAlpha"
    35  	const testBetaGate Feature = "TestBeta"
    36  
    37  	tests := []struct {
    38  		arg        string
    39  		expect     map[Feature]bool
    40  		parseError string
    41  	}{
    42  		{
    43  			arg: "",
    44  			expect: map[Feature]bool{
    45  				allAlphaGate:  false,
    46  				allBetaGate:   false,
    47  				testAlphaGate: false,
    48  				testBetaGate:  false,
    49  			},
    50  		},
    51  		{
    52  			arg: "fooBarBaz=true",
    53  			expect: map[Feature]bool{
    54  				allAlphaGate:  false,
    55  				allBetaGate:   false,
    56  				testAlphaGate: false,
    57  				testBetaGate:  false,
    58  			},
    59  			parseError: "unrecognized feature gate: fooBarBaz",
    60  		},
    61  		{
    62  			arg: "AllAlpha=false",
    63  			expect: map[Feature]bool{
    64  				allAlphaGate:  false,
    65  				allBetaGate:   false,
    66  				testAlphaGate: false,
    67  				testBetaGate:  false,
    68  			},
    69  		},
    70  		{
    71  			arg: "AllAlpha=true",
    72  			expect: map[Feature]bool{
    73  				allAlphaGate:  true,
    74  				allBetaGate:   false,
    75  				testAlphaGate: true,
    76  				testBetaGate:  false,
    77  			},
    78  		},
    79  		{
    80  			arg: "AllAlpha=banana",
    81  			expect: map[Feature]bool{
    82  				allAlphaGate:  false,
    83  				allBetaGate:   false,
    84  				testAlphaGate: false,
    85  				testBetaGate:  false,
    86  			},
    87  			parseError: "invalid value of AllAlpha",
    88  		},
    89  		{
    90  			arg: "AllAlpha=false,TestAlpha=true",
    91  			expect: map[Feature]bool{
    92  				allAlphaGate:  false,
    93  				allBetaGate:   false,
    94  				testAlphaGate: true,
    95  				testBetaGate:  false,
    96  			},
    97  		},
    98  		{
    99  			arg: "TestAlpha=true,AllAlpha=false",
   100  			expect: map[Feature]bool{
   101  				allAlphaGate:  false,
   102  				allBetaGate:   false,
   103  				testAlphaGate: true,
   104  				testBetaGate:  false,
   105  			},
   106  		},
   107  		{
   108  			arg: "AllAlpha=true,TestAlpha=false",
   109  			expect: map[Feature]bool{
   110  				allAlphaGate:  true,
   111  				allBetaGate:   false,
   112  				testAlphaGate: false,
   113  				testBetaGate:  false,
   114  			},
   115  		},
   116  		{
   117  			arg: "TestAlpha=false,AllAlpha=true",
   118  			expect: map[Feature]bool{
   119  				allAlphaGate:  true,
   120  				allBetaGate:   false,
   121  				testAlphaGate: false,
   122  				testBetaGate:  false,
   123  			},
   124  		},
   125  		{
   126  			arg: "TestBeta=true,AllAlpha=false",
   127  			expect: map[Feature]bool{
   128  				allAlphaGate:  false,
   129  				allBetaGate:   false,
   130  				testAlphaGate: false,
   131  				testBetaGate:  true,
   132  			},
   133  		},
   134  
   135  		{
   136  			arg: "AllBeta=false",
   137  			expect: map[Feature]bool{
   138  				allAlphaGate:  false,
   139  				allBetaGate:   false,
   140  				testAlphaGate: false,
   141  				testBetaGate:  false,
   142  			},
   143  		},
   144  		{
   145  			arg: "AllBeta=true",
   146  			expect: map[Feature]bool{
   147  				allAlphaGate:  false,
   148  				allBetaGate:   true,
   149  				testAlphaGate: false,
   150  				testBetaGate:  true,
   151  			},
   152  		},
   153  		{
   154  			arg: "AllBeta=banana",
   155  			expect: map[Feature]bool{
   156  				allAlphaGate:  false,
   157  				allBetaGate:   false,
   158  				testAlphaGate: false,
   159  				testBetaGate:  false,
   160  			},
   161  			parseError: "invalid value of AllBeta",
   162  		},
   163  		{
   164  			arg: "AllBeta=false,TestBeta=true",
   165  			expect: map[Feature]bool{
   166  				allAlphaGate:  false,
   167  				allBetaGate:   false,
   168  				testAlphaGate: false,
   169  				testBetaGate:  true,
   170  			},
   171  		},
   172  		{
   173  			arg: "TestBeta=true,AllBeta=false",
   174  			expect: map[Feature]bool{
   175  				allAlphaGate:  false,
   176  				allBetaGate:   false,
   177  				testAlphaGate: false,
   178  				testBetaGate:  true,
   179  			},
   180  		},
   181  		{
   182  			arg: "AllBeta=true,TestBeta=false",
   183  			expect: map[Feature]bool{
   184  				allAlphaGate:  false,
   185  				allBetaGate:   true,
   186  				testAlphaGate: false,
   187  				testBetaGate:  false,
   188  			},
   189  		},
   190  		{
   191  			arg: "TestBeta=false,AllBeta=true",
   192  			expect: map[Feature]bool{
   193  				allAlphaGate:  false,
   194  				allBetaGate:   true,
   195  				testAlphaGate: false,
   196  				testBetaGate:  false,
   197  			},
   198  		},
   199  		{
   200  			arg: "TestAlpha=true,AllBeta=false",
   201  			expect: map[Feature]bool{
   202  				allAlphaGate:  false,
   203  				allBetaGate:   false,
   204  				testAlphaGate: true,
   205  				testBetaGate:  false,
   206  			},
   207  		},
   208  	}
   209  	for i, test := range tests {
   210  		t.Run(test.arg, func(t *testing.T) {
   211  			fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError)
   212  			f := NewFeatureGate()
   213  			f.Add(map[Feature]FeatureSpec{
   214  				testAlphaGate: {Default: false, PreRelease: Alpha},
   215  				testBetaGate:  {Default: false, PreRelease: Beta},
   216  			})
   217  			f.AddFlag(fs)
   218  
   219  			err := fs.Parse([]string{fmt.Sprintf("--%s=%s", flagName, test.arg)})
   220  			if test.parseError != "" {
   221  				if !strings.Contains(err.Error(), test.parseError) {
   222  					t.Errorf("%d: Parse() Expected %v, Got %v", i, test.parseError, err)
   223  				}
   224  			} else if err != nil {
   225  				t.Errorf("%d: Parse() Expected nil, Got %v", i, err)
   226  			}
   227  			for k, v := range test.expect {
   228  				if actual := f.enabled.Load().(map[Feature]bool)[k]; actual != v {
   229  					t.Errorf("%d: expected %s=%v, Got %v", i, k, v, actual)
   230  				}
   231  			}
   232  		})
   233  	}
   234  }
   235  
   236  func TestFeatureGateOverride(t *testing.T) {
   237  	const testAlphaGate Feature = "TestAlpha"
   238  	const testBetaGate Feature = "TestBeta"
   239  
   240  	// Don't parse the flag, assert defaults are used.
   241  	var f *featureGate = NewFeatureGate()
   242  	f.Add(map[Feature]FeatureSpec{
   243  		testAlphaGate: {Default: false, PreRelease: Alpha},
   244  		testBetaGate:  {Default: false, PreRelease: Beta},
   245  	})
   246  
   247  	f.Set("TestAlpha=true,TestBeta=true")
   248  	if f.Enabled(testAlphaGate) != true {
   249  		t.Errorf("Expected true")
   250  	}
   251  	if f.Enabled(testBetaGate) != true {
   252  		t.Errorf("Expected true")
   253  	}
   254  
   255  	f.Set("TestAlpha=false")
   256  	if f.Enabled(testAlphaGate) != false {
   257  		t.Errorf("Expected false")
   258  	}
   259  	if f.Enabled(testBetaGate) != true {
   260  		t.Errorf("Expected true")
   261  	}
   262  }
   263  
   264  func TestFeatureGateFlagDefaults(t *testing.T) {
   265  	// gates for testing
   266  	const testAlphaGate Feature = "TestAlpha"
   267  	const testBetaGate Feature = "TestBeta"
   268  
   269  	// Don't parse the flag, assert defaults are used.
   270  	var f *featureGate = NewFeatureGate()
   271  	f.Add(map[Feature]FeatureSpec{
   272  		testAlphaGate: {Default: false, PreRelease: Alpha},
   273  		testBetaGate:  {Default: true, PreRelease: Beta},
   274  	})
   275  
   276  	if f.Enabled(testAlphaGate) != false {
   277  		t.Errorf("Expected false")
   278  	}
   279  	if f.Enabled(testBetaGate) != true {
   280  		t.Errorf("Expected true")
   281  	}
   282  }
   283  
   284  func TestFeatureGateKnownFeatures(t *testing.T) {
   285  	// gates for testing
   286  	const (
   287  		testAlphaGate      Feature = "TestAlpha"
   288  		testBetaGate       Feature = "TestBeta"
   289  		testGAGate         Feature = "TestGA"
   290  		testDeprecatedGate Feature = "TestDeprecated"
   291  	)
   292  
   293  	// Don't parse the flag, assert defaults are used.
   294  	var f *featureGate = NewFeatureGate()
   295  	f.Add(map[Feature]FeatureSpec{
   296  		testAlphaGate:      {Default: false, PreRelease: Alpha},
   297  		testBetaGate:       {Default: true, PreRelease: Beta},
   298  		testGAGate:         {Default: true, PreRelease: GA},
   299  		testDeprecatedGate: {Default: false, PreRelease: Deprecated},
   300  	})
   301  
   302  	known := strings.Join(f.KnownFeatures(), " ")
   303  
   304  	assert.Contains(t, known, testAlphaGate)
   305  	assert.Contains(t, known, testBetaGate)
   306  	assert.NotContains(t, known, testGAGate)
   307  	assert.NotContains(t, known, testDeprecatedGate)
   308  }
   309  
   310  func TestFeatureGateSetFromMap(t *testing.T) {
   311  	// gates for testing
   312  	const testAlphaGate Feature = "TestAlpha"
   313  	const testBetaGate Feature = "TestBeta"
   314  	const testLockedTrueGate Feature = "TestLockedTrue"
   315  	const testLockedFalseGate Feature = "TestLockedFalse"
   316  
   317  	tests := []struct {
   318  		name        string
   319  		setmap      map[string]bool
   320  		expect      map[Feature]bool
   321  		setmapError string
   322  	}{
   323  		{
   324  			name: "set TestAlpha and TestBeta true",
   325  			setmap: map[string]bool{
   326  				"TestAlpha": true,
   327  				"TestBeta":  true,
   328  			},
   329  			expect: map[Feature]bool{
   330  				testAlphaGate: true,
   331  				testBetaGate:  true,
   332  			},
   333  		},
   334  		{
   335  			name: "set TestBeta true",
   336  			setmap: map[string]bool{
   337  				"TestBeta": true,
   338  			},
   339  			expect: map[Feature]bool{
   340  				testAlphaGate: false,
   341  				testBetaGate:  true,
   342  			},
   343  		},
   344  		{
   345  			name: "set TestAlpha false",
   346  			setmap: map[string]bool{
   347  				"TestAlpha": false,
   348  			},
   349  			expect: map[Feature]bool{
   350  				testAlphaGate: false,
   351  				testBetaGate:  false,
   352  			},
   353  		},
   354  		{
   355  			name: "set TestInvaild true",
   356  			setmap: map[string]bool{
   357  				"TestInvaild": true,
   358  			},
   359  			expect: map[Feature]bool{
   360  				testAlphaGate: false,
   361  				testBetaGate:  false,
   362  			},
   363  			setmapError: "unrecognized feature gate:",
   364  		},
   365  		{
   366  			name: "set locked gates",
   367  			setmap: map[string]bool{
   368  				"TestLockedTrue":  true,
   369  				"TestLockedFalse": false,
   370  			},
   371  			expect: map[Feature]bool{
   372  				testAlphaGate: false,
   373  				testBetaGate:  false,
   374  			},
   375  		},
   376  		{
   377  			name: "set locked gates",
   378  			setmap: map[string]bool{
   379  				"TestLockedTrue": false,
   380  			},
   381  			expect: map[Feature]bool{
   382  				testAlphaGate: false,
   383  				testBetaGate:  false,
   384  			},
   385  			setmapError: "cannot set feature gate TestLockedTrue to false, feature is locked to true",
   386  		},
   387  		{
   388  			name: "set locked gates",
   389  			setmap: map[string]bool{
   390  				"TestLockedFalse": true,
   391  			},
   392  			expect: map[Feature]bool{
   393  				testAlphaGate: false,
   394  				testBetaGate:  false,
   395  			},
   396  			setmapError: "cannot set feature gate TestLockedFalse to true, feature is locked to false",
   397  		},
   398  	}
   399  	for i, test := range tests {
   400  		t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) {
   401  			f := NewFeatureGate()
   402  			f.Add(map[Feature]FeatureSpec{
   403  				testAlphaGate:       {Default: false, PreRelease: Alpha},
   404  				testBetaGate:        {Default: false, PreRelease: Beta},
   405  				testLockedTrueGate:  {Default: true, PreRelease: GA, LockToDefault: true},
   406  				testLockedFalseGate: {Default: false, PreRelease: GA, LockToDefault: true},
   407  			})
   408  			err := f.SetFromMap(test.setmap)
   409  			if test.setmapError != "" {
   410  				if err == nil {
   411  					t.Errorf("expected error, got none")
   412  				} else if !strings.Contains(err.Error(), test.setmapError) {
   413  					t.Errorf("%d: SetFromMap(%#v) Expected err:%v, Got err:%v", i, test.setmap, test.setmapError, err)
   414  				}
   415  			} else if err != nil {
   416  				t.Errorf("%d: SetFromMap(%#v) Expected success, Got err:%v", i, test.setmap, err)
   417  			}
   418  			for k, v := range test.expect {
   419  				if actual := f.Enabled(k); actual != v {
   420  					t.Errorf("%d: SetFromMap(%#v) Expected %s=%v, Got %s=%v", i, test.setmap, k, v, k, actual)
   421  				}
   422  			}
   423  		})
   424  	}
   425  }
   426  
   427  func TestFeatureGateMetrics(t *testing.T) {
   428  	// gates for testing
   429  	featuremetrics.ResetFeatureInfoMetric()
   430  	const testAlphaGate Feature = "TestAlpha"
   431  	const testBetaGate Feature = "TestBeta"
   432  	const testAlphaEnabled Feature = "TestAlphaEnabled"
   433  	const testBetaDisabled Feature = "TestBetaDisabled"
   434  	testedMetrics := []string{"kubernetes_feature_enabled"}
   435  	expectedOutput := `
   436  		# HELP kubernetes_feature_enabled [BETA] This metric records the data about the stage and enablement of a k8s feature.
   437          # TYPE kubernetes_feature_enabled gauge
   438          kubernetes_feature_enabled{name="TestAlpha",stage="ALPHA"} 0
   439          kubernetes_feature_enabled{name="TestBeta",stage="BETA"} 1
   440  		kubernetes_feature_enabled{name="TestAlphaEnabled",stage="ALPHA"} 1
   441          kubernetes_feature_enabled{name="AllAlpha",stage="ALPHA"} 0
   442          kubernetes_feature_enabled{name="AllBeta",stage="BETA"} 0
   443  		kubernetes_feature_enabled{name="TestBetaDisabled",stage="ALPHA"} 0
   444  `
   445  
   446  	f := NewFeatureGate()
   447  	fMap := map[Feature]FeatureSpec{
   448  		testAlphaGate:    {Default: false, PreRelease: Alpha},
   449  		testAlphaEnabled: {Default: false, PreRelease: Alpha},
   450  		testBetaGate:     {Default: true, PreRelease: Beta},
   451  		testBetaDisabled: {Default: true, PreRelease: Alpha},
   452  	}
   453  	f.Add(fMap)
   454  	f.SetFromMap(map[string]bool{"TestAlphaEnabled": true, "TestBetaDisabled": false})
   455  	f.AddMetrics()
   456  	if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(expectedOutput), testedMetrics...); err != nil {
   457  		t.Fatal(err)
   458  	}
   459  }
   460  
   461  func TestFeatureGateString(t *testing.T) {
   462  	// gates for testing
   463  	const testAlphaGate Feature = "TestAlpha"
   464  	const testBetaGate Feature = "TestBeta"
   465  	const testGAGate Feature = "TestGA"
   466  
   467  	featuremap := map[Feature]FeatureSpec{
   468  		testGAGate:    {Default: true, PreRelease: GA},
   469  		testAlphaGate: {Default: false, PreRelease: Alpha},
   470  		testBetaGate:  {Default: true, PreRelease: Beta},
   471  	}
   472  
   473  	tests := []struct {
   474  		setmap map[string]bool
   475  		expect string
   476  	}{
   477  		{
   478  			setmap: map[string]bool{
   479  				"TestAlpha": false,
   480  			},
   481  			expect: "TestAlpha=false",
   482  		},
   483  		{
   484  			setmap: map[string]bool{
   485  				"TestAlpha": false,
   486  				"TestBeta":  true,
   487  			},
   488  			expect: "TestAlpha=false,TestBeta=true",
   489  		},
   490  		{
   491  			setmap: map[string]bool{
   492  				"TestGA":    true,
   493  				"TestAlpha": false,
   494  				"TestBeta":  true,
   495  			},
   496  			expect: "TestAlpha=false,TestBeta=true,TestGA=true",
   497  		},
   498  	}
   499  	for i, test := range tests {
   500  		t.Run(fmt.Sprintf("SetFromMap %s", test.expect), func(t *testing.T) {
   501  			f := NewFeatureGate()
   502  			f.Add(featuremap)
   503  			f.SetFromMap(test.setmap)
   504  			result := f.String()
   505  			if result != test.expect {
   506  				t.Errorf("%d: SetFromMap(%#v) Expected %s, Got %s", i, test.setmap, test.expect, result)
   507  			}
   508  		})
   509  	}
   510  }
   511  
   512  func TestFeatureGateOverrideDefault(t *testing.T) {
   513  	t.Run("overrides take effect", func(t *testing.T) {
   514  		f := NewFeatureGate()
   515  		if err := f.Add(map[Feature]FeatureSpec{
   516  			"TestFeature1": {Default: true},
   517  			"TestFeature2": {Default: false},
   518  		}); err != nil {
   519  			t.Fatal(err)
   520  		}
   521  		if err := f.OverrideDefault("TestFeature1", false); err != nil {
   522  			t.Fatal(err)
   523  		}
   524  		if err := f.OverrideDefault("TestFeature2", true); err != nil {
   525  			t.Fatal(err)
   526  		}
   527  		if f.Enabled("TestFeature1") {
   528  			t.Error("expected TestFeature1 to have effective default of false")
   529  		}
   530  		if !f.Enabled("TestFeature2") {
   531  			t.Error("expected TestFeature2 to have effective default of true")
   532  		}
   533  	})
   534  
   535  	t.Run("overrides are preserved across deep copies", func(t *testing.T) {
   536  		f := NewFeatureGate()
   537  		if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: false}}); err != nil {
   538  			t.Fatal(err)
   539  		}
   540  		if err := f.OverrideDefault("TestFeature", true); err != nil {
   541  			t.Fatal(err)
   542  		}
   543  		fcopy := f.DeepCopy()
   544  		if !fcopy.Enabled("TestFeature") {
   545  			t.Error("default override was not preserved by deep copy")
   546  		}
   547  	})
   548  
   549  	t.Run("reflected in known features", func(t *testing.T) {
   550  		f := NewFeatureGate()
   551  		if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {
   552  			Default:    false,
   553  			PreRelease: Alpha,
   554  		}}); err != nil {
   555  			t.Fatal(err)
   556  		}
   557  		if err := f.OverrideDefault("TestFeature", true); err != nil {
   558  			t.Fatal(err)
   559  		}
   560  		var found bool
   561  		for _, s := range f.KnownFeatures() {
   562  			if !strings.Contains(s, "TestFeature") {
   563  				continue
   564  			}
   565  			found = true
   566  			if !strings.Contains(s, "default=true") {
   567  				t.Errorf("expected override of default to be reflected in known feature description %q", s)
   568  			}
   569  		}
   570  		if !found {
   571  			t.Error("found no entry for TestFeature in known features")
   572  		}
   573  	})
   574  
   575  	t.Run("may not change default for specs with locked defaults", func(t *testing.T) {
   576  		f := NewFeatureGate()
   577  		if err := f.Add(map[Feature]FeatureSpec{
   578  			"LockedFeature": {
   579  				Default:       true,
   580  				LockToDefault: true,
   581  			},
   582  		}); err != nil {
   583  			t.Fatal(err)
   584  		}
   585  		if f.OverrideDefault("LockedFeature", false) == nil {
   586  			t.Error("expected error when attempting to override the default for a feature with a locked default")
   587  		}
   588  		if f.OverrideDefault("LockedFeature", true) == nil {
   589  			t.Error("expected error when attempting to override the default for a feature with a locked default")
   590  		}
   591  	})
   592  
   593  	t.Run("does not supersede explicitly-set value", func(t *testing.T) {
   594  		f := NewFeatureGate()
   595  		if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: true}}); err != nil {
   596  			t.Fatal(err)
   597  		}
   598  		if err := f.OverrideDefault("TestFeature", false); err != nil {
   599  			t.Fatal(err)
   600  		}
   601  		if err := f.SetFromMap(map[string]bool{"TestFeature": true}); err != nil {
   602  			t.Fatal(err)
   603  		}
   604  		if !f.Enabled("TestFeature") {
   605  			t.Error("expected feature to be effectively enabled despite default override")
   606  		}
   607  	})
   608  
   609  	t.Run("prevents re-registration of feature spec after overriding default", func(t *testing.T) {
   610  		f := NewFeatureGate()
   611  		if err := f.Add(map[Feature]FeatureSpec{
   612  			"TestFeature": {
   613  				Default:    true,
   614  				PreRelease: Alpha,
   615  			},
   616  		}); err != nil {
   617  			t.Fatal(err)
   618  		}
   619  		if err := f.OverrideDefault("TestFeature", false); err != nil {
   620  			t.Fatal(err)
   621  		}
   622  		if err := f.Add(map[Feature]FeatureSpec{
   623  			"TestFeature": {
   624  				Default:    true,
   625  				PreRelease: Alpha,
   626  			},
   627  		}); err == nil {
   628  			t.Error("expected re-registration to return a non-nil error after overriding its default")
   629  		}
   630  	})
   631  
   632  	t.Run("does not allow override for an unknown feature", func(t *testing.T) {
   633  		f := NewFeatureGate()
   634  		if err := f.OverrideDefault("TestFeature", true); err == nil {
   635  			t.Error("expected an error to be returned in attempt to override default for unregistered feature")
   636  		}
   637  	})
   638  
   639  	t.Run("returns error if already added to flag set", func(t *testing.T) {
   640  		f := NewFeatureGate()
   641  		fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
   642  		f.AddFlag(fs)
   643  
   644  		if err := f.OverrideDefault("TestFeature", true); err == nil {
   645  			t.Error("expected a non-nil error to be returned")
   646  		}
   647  	})
   648  }
   649  

View as plain text