k8s.io/apiserver@v0.31.1/pkg/audit/request_test.go (about)

     1  /*
     2  Copyright 2018 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 audit
    18  
    19  import (
    20  	"net/http"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  
    29  	"github.com/google/go-cmp/cmp"
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  func TestMaybeTruncateUserAgent(t *testing.T) {
    34  	req := &http.Request{}
    35  	req.Header = http.Header{}
    36  
    37  	ua := "short-agent"
    38  	req.Header.Set("User-Agent", ua)
    39  	assert.Equal(t, ua, maybeTruncateUserAgent(req))
    40  
    41  	ua = ""
    42  	for i := 0; i < maxUserAgentLength*2; i++ {
    43  		ua = ua + "a"
    44  	}
    45  	req.Header.Set("User-Agent", ua)
    46  	assert.NotEqual(t, ua, maybeTruncateUserAgent(req))
    47  }
    48  
    49  func TestCopyWithoutManagedFields(t *testing.T) {
    50  	tests := []struct {
    51  		name     string
    52  		object   runtime.Object
    53  		expected runtime.Object
    54  		ok       bool
    55  		err      error
    56  	}{
    57  		{
    58  			name:   "object specified is not a meta.Accessor or a list or a table",
    59  			object: &metav1.Status{},
    60  		},
    61  		{
    62  			name: "object specified is a meta.Accessor and has managed fields",
    63  			object: &corev1.Pod{
    64  				ObjectMeta: metav1.ObjectMeta{
    65  					Name:      "foo",
    66  					Namespace: "bar",
    67  					ManagedFields: []metav1.ManagedFieldsEntry{
    68  						{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
    69  						{Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
    70  					},
    71  				},
    72  			},
    73  			expected: &corev1.Pod{
    74  				ObjectMeta: metav1.ObjectMeta{
    75  					Name:      "foo",
    76  					Namespace: "bar",
    77  				},
    78  			},
    79  			ok: true,
    80  		},
    81  		{
    82  			name: "object specified is a list and its items have managed fields",
    83  			object: &corev1.PodList{
    84  				Items: []corev1.Pod{
    85  					{
    86  						ObjectMeta: metav1.ObjectMeta{
    87  							Name:      "foo",
    88  							Namespace: "ns1",
    89  							ManagedFields: []metav1.ManagedFieldsEntry{
    90  								{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
    91  								{Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
    92  							},
    93  						},
    94  					},
    95  					{
    96  						ObjectMeta: metav1.ObjectMeta{
    97  							Name:      "bar",
    98  							Namespace: "ns2",
    99  							ManagedFields: []metav1.ManagedFieldsEntry{
   100  								{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
   101  								{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
   102  							},
   103  						},
   104  					},
   105  				},
   106  			},
   107  			expected: &corev1.PodList{
   108  				Items: []corev1.Pod{
   109  					{
   110  						ObjectMeta: metav1.ObjectMeta{
   111  							Name:      "foo",
   112  							Namespace: "ns1",
   113  						},
   114  					},
   115  					{
   116  						ObjectMeta: metav1.ObjectMeta{
   117  							Name:      "bar",
   118  							Namespace: "ns2",
   119  						},
   120  					},
   121  				},
   122  			},
   123  			ok: true,
   124  		},
   125  		{
   126  			name: "object specified is a Table and objects in its rows have managed fields",
   127  			object: &metav1.Table{
   128  				Rows: []metav1.TableRow{
   129  					{
   130  						Object: runtime.RawExtension{
   131  							Object: &corev1.Pod{
   132  								ObjectMeta: metav1.ObjectMeta{
   133  									Name:      "foo",
   134  									Namespace: "ns1",
   135  									ManagedFields: []metav1.ManagedFieldsEntry{
   136  										{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
   137  										{Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
   138  									},
   139  								},
   140  							},
   141  						},
   142  					},
   143  					{
   144  						Object: runtime.RawExtension{
   145  							Object: &corev1.Pod{
   146  								ObjectMeta: metav1.ObjectMeta{
   147  									Name:      "bar",
   148  									Namespace: "ns2",
   149  									ManagedFields: []metav1.ManagedFieldsEntry{
   150  										{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
   151  										{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Now()}},
   152  									},
   153  								},
   154  							},
   155  						},
   156  					},
   157  					// add an empty row to make sure we don't panic
   158  					{
   159  						Object: runtime.RawExtension{},
   160  					},
   161  				},
   162  			},
   163  			expected: &metav1.Table{
   164  				Rows: []metav1.TableRow{
   165  					{
   166  						Object: runtime.RawExtension{
   167  							Object: &corev1.Pod{
   168  								ObjectMeta: metav1.ObjectMeta{
   169  									Name:      "foo",
   170  									Namespace: "ns1",
   171  								},
   172  							},
   173  						},
   174  					},
   175  					{
   176  						Object: runtime.RawExtension{
   177  							Object: &corev1.Pod{
   178  								ObjectMeta: metav1.ObjectMeta{
   179  									Name:      "bar",
   180  									Namespace: "ns2",
   181  								},
   182  							},
   183  						},
   184  					},
   185  					{
   186  						Object: runtime.RawExtension{},
   187  					},
   188  				},
   189  			},
   190  			ok: true,
   191  		},
   192  	}
   193  
   194  	for _, test := range tests {
   195  		t.Run(test.name, func(t *testing.T) {
   196  			original := test.object.DeepCopyObject()
   197  			objectGot, ok, err := copyWithoutManagedFields(test.object)
   198  
   199  			if test.err != err {
   200  				t.Errorf("expected error: %v, but got: %v", test.err, err)
   201  			}
   202  			if test.ok != ok {
   203  				t.Errorf("expected ok: %t, but got: %t", test.ok, ok)
   204  			}
   205  
   206  			switch {
   207  			case test.expected == nil:
   208  				if objectGot != nil {
   209  					t.Errorf("expected the returned object to be nil, but got %#v", objectGot)
   210  				}
   211  			default:
   212  				// verify that a deep copy of the specified object is made before mutating it.
   213  				if expected, actual := reflect.ValueOf(test.object), reflect.ValueOf(objectGot); expected.Pointer() == actual.Pointer() {
   214  					t.Error("expected the returned object to be a deep copy of the input object")
   215  				}
   216  
   217  				if !cmp.Equal(test.expected, objectGot) {
   218  					t.Errorf("expected and actual do not match, diff: %s", cmp.Diff(test.expected, objectGot))
   219  				}
   220  			}
   221  
   222  			// we always expect the original object to be unchanged.
   223  			if !cmp.Equal(original, test.object) {
   224  				t.Errorf("the original object has mutated, diff: %s", cmp.Diff(original, test.object))
   225  			}
   226  		})
   227  	}
   228  }