istio

Форк
0
161 строка · 4.9 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package helmreconciler
16

17
import (
18
	"context"
19
	"errors"
20
	"fmt"
21
	"os"
22
	"reflect"
23
	"sync"
24
	"testing"
25

26
	kerrors "k8s.io/apimachinery/pkg/api/errors"
27
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29
	"k8s.io/apimachinery/pkg/runtime/schema"
30
	"k8s.io/apimachinery/pkg/types"
31
	"sigs.k8s.io/controller-runtime/pkg/client"
32
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
33
	"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
34

35
	v1alpha12 "istio.io/api/operator/v1alpha1"
36
	"istio.io/istio/operator/pkg/apis/istio/v1alpha1"
37
	"istio.io/istio/operator/pkg/object"
38
)
39

40
var interceptorFunc = interceptor.Funcs{Patch: func(
41
	ctx context.Context,
42
	clnt client.WithWatch,
43
	obj client.Object,
44
	patch client.Patch,
45
	opts ...client.PatchOption,
46
) error {
47
	// Apply patches are supposed to upsert, but fake client fails if the object doesn't exist,
48
	// if an apply patch occurs for an object that doesn't yet exist, create it.
49
	if patch.Type() != types.ApplyPatchType {
50
		return clnt.Patch(ctx, obj, patch, opts...)
51
	}
52
	check, ok := obj.DeepCopyObject().(client.Object)
53
	if !ok {
54
		return errors.New("could not check for object in fake client")
55
	}
56
	if err := clnt.Get(ctx, client.ObjectKeyFromObject(obj), check); kerrors.IsNotFound(err) {
57
		if err := clnt.Create(ctx, check); err != nil {
58
			return fmt.Errorf("could not inject object creation for fake: %w", err)
59
		}
60
	} else if err != nil {
61
		return err
62
	}
63
	obj.SetResourceVersion(check.GetResourceVersion())
64
	return clnt.Update(ctx, obj)
65
}}
66

67
func TestHelmReconciler_ApplyObject(t *testing.T) {
68
	tests := []struct {
69
		name         string
70
		currentState string
71
		input        string
72
		want         string
73
		wantErr      bool
74
	}{
75
		{
76
			name:  "creates if not present",
77
			input: "testdata/configmap.yaml",
78
			want:  "testdata/configmap.yaml",
79
		},
80
		{
81
			name:         "updates if present",
82
			currentState: "testdata/configmap.yaml",
83
			input:        "testdata/configmap-changed.yaml",
84
			want:         "testdata/configmap-changed.yaml",
85
		},
86
		// Test IstioOperator field removals
87
		{
88
			name:  "creates if not present",
89
			input: "testdata/iop-test-gw-1.yaml",
90
			want:  "testdata/iop-test-gw-1.yaml",
91
		},
92
		{
93
			name:         "updates if present",
94
			currentState: "testdata/iop-test-gw-1.yaml",
95
			input:        "testdata/iop-changed.yaml",
96
			want:         "testdata/iop-changed.yaml",
97
		},
98
	}
99
	for _, tt := range tests {
100
		t.Run(tt.name, func(t *testing.T) {
101
			obj := loadData(t, tt.input)
102
			var k8sClient client.Client
103
			if tt.currentState != "" {
104
				k8sClient = fake.NewClientBuilder().
105
					WithRuntimeObjects(loadData(t, tt.currentState).
106
						UnstructuredObject()).WithInterceptorFuncs(interceptorFunc).Build()
107
			} else {
108
				// no current state provided, initialize fake client without runtime object
109
				k8sClient = fake.NewClientBuilder().WithInterceptorFuncs(interceptorFunc).Build()
110
			}
111

112
			cl := k8sClient
113
			h := &HelmReconciler{
114
				client: cl,
115
				opts:   &Options{},
116
				iop: &v1alpha1.IstioOperator{
117
					ObjectMeta: metav1.ObjectMeta{
118
						Name:      "test-operator",
119
						Namespace: "istio-operator-test",
120
					},
121
					Spec: &v1alpha12.IstioOperatorSpec{},
122
				},
123
				countLock:     &sync.Mutex{},
124
				prunedKindSet: map[schema.GroupKind]struct{}{},
125
			}
126
			if err := h.ApplyObject(obj.UnstructuredObject()); (err != nil) != tt.wantErr {
127
				t.Errorf("HelmReconciler.ApplyObject() error = %v, wantErr %v", err, tt.wantErr)
128
			}
129

130
			manifest := loadData(t, tt.want)
131
			key := client.ObjectKeyFromObject(manifest.UnstructuredObject())
132
			got, want := obj.UnstructuredObject(), manifest.UnstructuredObject()
133

134
			if err := cl.Get(context.Background(), key, got); err != nil {
135
				t.Errorf("error validating manifest %v: %v", manifest.Hash(), err)
136
			}
137
			// remove resource version and annotations (last applied config) when we compare as we don't care
138
			unstructured.RemoveNestedField(got.Object, "metadata", "resourceVersion")
139
			unstructured.RemoveNestedField(got.Object, "metadata", "annotations")
140

141
			if !reflect.DeepEqual(want, got) {
142
				t.Errorf("wanted:\n%v\ngot:\n%v",
143
					object.NewK8sObject(want, nil, nil).YAMLDebugString(),
144
					object.NewK8sObject(got, nil, nil).YAMLDebugString(),
145
				)
146
			}
147
		})
148
	}
149
}
150

151
func loadData(t *testing.T, file string) *object.K8sObject {
152
	contents, err := os.ReadFile(file)
153
	if err != nil {
154
		t.Fatal(err)
155
	}
156
	obj, err := object.ParseYAMLToK8sObject(contents)
157
	if err != nil {
158
		t.Fatal(err)
159
	}
160
	return obj
161
}
162

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.