k8s.io/apiserver@v0.31.1/pkg/apis/apiserver/load/load_test.go (about)

     1  /*
     2  Copyright 2023 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 load
    18  
    19  import (
    20  	"bytes"
    21  	"os"
    22  	"reflect"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	api "k8s.io/apiserver/pkg/apis/apiserver"
    31  )
    32  
    33  var defaultConfig = &api.AuthorizationConfiguration{}
    34  
    35  func writeTempFile(t *testing.T, content string) string {
    36  	t.Helper()
    37  	file, err := os.CreateTemp("", "config")
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	t.Cleanup(func() {
    42  		if err := os.Remove(file.Name()); err != nil {
    43  			t.Fatal(err)
    44  		}
    45  	})
    46  	if err := os.WriteFile(file.Name(), []byte(content), 0600); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	return file.Name()
    50  }
    51  
    52  func TestLoadFromFile(t *testing.T) {
    53  	// no file
    54  	{
    55  		_, err := LoadFromFile("")
    56  		if err == nil {
    57  			t.Fatalf("expected err: %v", err)
    58  		}
    59  	}
    60  
    61  	// empty file
    62  	{
    63  		config, err := LoadFromFile(writeTempFile(t, ``))
    64  		if err != nil {
    65  			t.Fatalf("unexpected err: %v", err)
    66  		}
    67  		if !reflect.DeepEqual(config, defaultConfig) {
    68  			t.Fatalf("unexpected config:\n%s", cmp.Diff(defaultConfig, config))
    69  		}
    70  	}
    71  
    72  	// valid file
    73  	{
    74  		input := `{
    75  			"apiVersion":"apiserver.config.k8s.io/v1alpha1",
    76  			"kind":"AuthorizationConfiguration",
    77  			"authorizers":[{"type":"Webhook"}]}`
    78  		expect := &api.AuthorizationConfiguration{
    79  			Authorizers: []api.AuthorizerConfiguration{{Type: "Webhook"}},
    80  		}
    81  
    82  		config, err := LoadFromFile(writeTempFile(t, input))
    83  		if err != nil {
    84  			t.Fatalf("unexpected err: %v", err)
    85  		}
    86  		if !reflect.DeepEqual(config, expect) {
    87  			t.Fatalf("unexpected config:\n%s", cmp.Diff(expect, config))
    88  		}
    89  	}
    90  
    91  	// missing file
    92  	{
    93  		_, err := LoadFromFile(`bogus-missing-file`)
    94  		if err == nil {
    95  			t.Fatalf("expected err, got none")
    96  		}
    97  		if !strings.Contains(err.Error(), "bogus-missing-file") {
    98  			t.Fatalf("expected missing file error, got %v", err)
    99  		}
   100  	}
   101  
   102  	// invalid content file
   103  	{
   104  		input := `{
   105  			"apiVersion":"apiserver.config.k8s.io/v99",
   106  			"kind":"AuthorizationConfiguration",
   107  			"authorizers":{"type":"Webhook"}}`
   108  
   109  		_, err := LoadFromFile(writeTempFile(t, input))
   110  		if err == nil {
   111  			t.Fatalf("expected err, got none")
   112  		}
   113  		if !strings.Contains(err.Error(), "apiserver.config.k8s.io/v99") {
   114  			t.Fatalf("expected apiVersion error, got %v", err)
   115  		}
   116  	}
   117  }
   118  
   119  func TestLoadFromReader(t *testing.T) {
   120  	// no reader
   121  	{
   122  		config, err := LoadFromReader(nil)
   123  		if err != nil {
   124  			t.Fatalf("unexpected err: %v", err)
   125  		}
   126  		if !reflect.DeepEqual(config, defaultConfig) {
   127  			t.Fatalf("unexpected config:\n%s", cmp.Diff(defaultConfig, config))
   128  		}
   129  	}
   130  
   131  	// empty reader
   132  	{
   133  		config, err := LoadFromReader(&bytes.Buffer{})
   134  		if err != nil {
   135  			t.Fatalf("unexpected err: %v", err)
   136  		}
   137  		if !reflect.DeepEqual(config, defaultConfig) {
   138  			t.Fatalf("unexpected config:\n%s", cmp.Diff(defaultConfig, config))
   139  		}
   140  	}
   141  
   142  	// valid reader
   143  	{
   144  		input := `{
   145  			"apiVersion":"apiserver.config.k8s.io/v1alpha1",
   146  			"kind":"AuthorizationConfiguration",
   147  			"authorizers":[{"type":"Webhook"}]}`
   148  		expect := &api.AuthorizationConfiguration{
   149  			Authorizers: []api.AuthorizerConfiguration{{Type: "Webhook"}},
   150  		}
   151  
   152  		config, err := LoadFromReader(bytes.NewBufferString(input))
   153  		if err != nil {
   154  			t.Fatalf("unexpected err: %v", err)
   155  		}
   156  		if !reflect.DeepEqual(config, expect) {
   157  			t.Fatalf("unexpected config:\n%s", cmp.Diff(expect, config))
   158  		}
   159  	}
   160  
   161  	// invalid reader
   162  	{
   163  		input := `{
   164  			"apiVersion":"apiserver.config.k8s.io/v99",
   165  			"kind":"AuthorizationConfiguration",
   166  			"authorizers":[{"type":"Webhook"}]}`
   167  
   168  		_, err := LoadFromReader(bytes.NewBufferString(input))
   169  		if err == nil {
   170  			t.Fatalf("expected err, got none")
   171  		}
   172  		if !strings.Contains(err.Error(), "apiserver.config.k8s.io/v99") {
   173  			t.Fatalf("expected apiVersion error, got %v", err)
   174  		}
   175  	}
   176  }
   177  
   178  func TestLoadFromData(t *testing.T) {
   179  	testcases := []struct {
   180  		name         string
   181  		data         []byte
   182  		expectErr    string
   183  		expectConfig *api.AuthorizationConfiguration
   184  	}{
   185  		{
   186  			name:         "nil",
   187  			data:         nil,
   188  			expectConfig: defaultConfig,
   189  		},
   190  		{
   191  			name:         "nil",
   192  			data:         []byte{},
   193  			expectConfig: defaultConfig,
   194  		},
   195  		{
   196  			name: "v1alpha1 - json",
   197  			data: []byte(`{
   198  "apiVersion":"apiserver.config.k8s.io/v1alpha1",
   199  "kind":"AuthorizationConfiguration",
   200  "authorizers":[{"type":"Webhook"}]}`),
   201  			expectConfig: &api.AuthorizationConfiguration{
   202  				Authorizers: []api.AuthorizerConfiguration{{Type: "Webhook"}},
   203  			},
   204  		},
   205  		{
   206  			name: "v1alpha1 - defaults",
   207  			data: []byte(`{
   208  "apiVersion":"apiserver.config.k8s.io/v1alpha1",
   209  "kind":"AuthorizationConfiguration",
   210  "authorizers":[{"type":"Webhook","name":"default","webhook":{}}]}`),
   211  			expectConfig: &api.AuthorizationConfiguration{
   212  				Authorizers: []api.AuthorizerConfiguration{{
   213  					Type: "Webhook",
   214  					Name: "default",
   215  					Webhook: &api.WebhookConfiguration{
   216  						AuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
   217  						UnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
   218  					},
   219  				}},
   220  			},
   221  		},
   222  		{
   223  			name: "v1alpha1 - yaml",
   224  			data: []byte(`
   225  apiVersion: apiserver.config.k8s.io/v1alpha1
   226  kind: AuthorizationConfiguration
   227  authorizers:
   228  - type: Webhook
   229  `),
   230  			expectConfig: &api.AuthorizationConfiguration{
   231  				Authorizers: []api.AuthorizerConfiguration{{Type: "Webhook"}},
   232  			},
   233  		},
   234  		{
   235  			name: "v1beta1 - json",
   236  			data: []byte(`{
   237  "apiVersion":"apiserver.config.k8s.io/v1beta1",
   238  "kind":"AuthorizationConfiguration",
   239  "authorizers":[{"type":"Webhook"}]}`),
   240  			expectConfig: &api.AuthorizationConfiguration{
   241  				Authorizers: []api.AuthorizerConfiguration{{Type: "Webhook"}},
   242  			},
   243  		},
   244  		{
   245  			name: "v1beta1 - defaults",
   246  			data: []byte(`{
   247  "apiVersion":"apiserver.config.k8s.io/v1beta1",
   248  "kind":"AuthorizationConfiguration",
   249  "authorizers":[{"type":"Webhook","name":"default","webhook":{}}]}`),
   250  			expectConfig: &api.AuthorizationConfiguration{
   251  				Authorizers: []api.AuthorizerConfiguration{{
   252  					Type: "Webhook",
   253  					Name: "default",
   254  					Webhook: &api.WebhookConfiguration{
   255  						AuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
   256  						UnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
   257  					},
   258  				}},
   259  			},
   260  		},
   261  		{
   262  			name: "v1beta1 - yaml",
   263  			data: []byte(`
   264  apiVersion: apiserver.config.k8s.io/v1beta1
   265  kind: AuthorizationConfiguration
   266  authorizers:
   267  - type: Webhook
   268  `),
   269  			expectConfig: &api.AuthorizationConfiguration{
   270  				Authorizers: []api.AuthorizerConfiguration{{Type: "Webhook"}},
   271  			},
   272  		},
   273  		{
   274  			name:      "missing apiVersion",
   275  			data:      []byte(`{"kind":"AuthorizationConfiguration"}`),
   276  			expectErr: `'apiVersion' is missing`,
   277  		},
   278  		{
   279  			name:      "missing kind",
   280  			data:      []byte(`{"apiVersion":"apiserver.config.k8s.io/v1alpha1"}`),
   281  			expectErr: `'Kind' is missing`,
   282  		},
   283  		{
   284  			name:      "unknown group",
   285  			data:      []byte(`{"apiVersion":"apps/v1alpha1","kind":"AuthorizationConfiguration"}`),
   286  			expectErr: `apps/v1alpha1`,
   287  		},
   288  		{
   289  			name:      "unknown version",
   290  			data:      []byte(`{"apiVersion":"apiserver.config.k8s.io/v99","kind":"AuthorizationConfiguration"}`),
   291  			expectErr: `apiserver.config.k8s.io/v99`,
   292  		},
   293  		{
   294  			name:      "unknown kind",
   295  			data:      []byte(`{"apiVersion":"apiserver.config.k8s.io/v1alpha1","kind":"SomeConfiguration"}`),
   296  			expectErr: `SomeConfiguration`,
   297  		},
   298  		{
   299  			name: "unknown field",
   300  			data: []byte(`{
   301  "apiVersion":"apiserver.config.k8s.io/v1alpha1",
   302  "kind":"AuthorizationConfiguration",
   303  "authorzers":[{"type":"Webhook"}]}`),
   304  			expectErr: `unknown field "authorzers"`,
   305  		},
   306  	}
   307  
   308  	for _, tc := range testcases {
   309  		t.Run(tc.name, func(t *testing.T) {
   310  			config, err := LoadFromData(tc.data)
   311  			if err != nil {
   312  				if len(tc.expectErr) == 0 {
   313  					t.Fatalf("unexpected error: %v", err)
   314  				}
   315  				if !strings.Contains(err.Error(), tc.expectErr) {
   316  					t.Fatalf("unexpected error: %v", err)
   317  				}
   318  				return
   319  			}
   320  			if len(tc.expectErr) > 0 {
   321  				t.Fatalf("expected err, got none")
   322  			}
   323  
   324  			if !reflect.DeepEqual(config, tc.expectConfig) {
   325  				t.Fatalf("unexpected config:\n%s", cmp.Diff(tc.expectConfig, config))
   326  			}
   327  		})
   328  	}
   329  }