knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/kvstore/kvstore_cm_test.go (about) 1 /* 2 Copyright 2020 The Knative 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 kvstore 18 19 import ( 20 "context" 21 "encoding/json" 22 "reflect" 23 "testing" 24 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/client-go/kubernetes/fake" 29 v1 "k8s.io/client-go/kubernetes/typed/core/v1" 30 clientgotesting "k8s.io/client-go/testing" 31 ) 32 33 const ( 34 namespace = "mynamespace" 35 name = "mycm" 36 ) 37 38 type testStruct struct { 39 LastThingProcessed string 40 Stuff []string 41 } 42 43 type testClient struct { 44 created *corev1.ConfigMap 45 updated *corev1.ConfigMap 46 clientset v1.CoreV1Interface 47 } 48 49 func newTestClient(objects ...runtime.Object) *testClient { 50 tc := testClient{} 51 cs := fake.NewSimpleClientset(objects...) 52 cs.PrependReactor("create", "*", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { 53 createAction := action.(clientgotesting.CreateAction) 54 tc.created = createAction.GetObject().(*corev1.ConfigMap) 55 return true, tc.created, nil 56 }) 57 cs.PrependReactor("update", "*", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { 58 updateAction := action.(clientgotesting.UpdateAction) 59 tc.updated = updateAction.GetObject().(*corev1.ConfigMap) 60 return true, tc.updated, nil 61 }) 62 tc.clientset = cs.CoreV1() 63 return &tc 64 } 65 66 func TestInitCreates(t *testing.T) { 67 tc := newTestClient() 68 cs := NewConfigMapKVStore(context.Background(), name, namespace, tc.clientset) 69 err := cs.Init(context.Background()) 70 if err != nil { 71 t.Error("Failed to Init ConfigStore:", err) 72 } 73 if tc.created == nil { 74 t.Errorf("ConfigMap not created") 75 } 76 if len(tc.created.Data) != 0 { 77 t.Errorf("ConfigMap data is not empty") 78 } 79 if tc.updated != nil { 80 t.Errorf("ConfigMap updated") 81 } 82 } 83 84 func TestLoadNonexisting(t *testing.T) { 85 tc := newTestClient() 86 if NewConfigMapKVStore(context.Background(), name, namespace, tc.clientset).Load(context.Background()) == nil { 87 t.Error("non-existent store load didn't fail") 88 } 89 } 90 91 func TestInitLoads(t *testing.T) { 92 tc := newTestClient([]runtime.Object{configMap(map[string]string{"foo": marshal(t, "bar")})}...) 93 cs := NewConfigMapKVStore(context.Background(), name, namespace, tc.clientset) 94 err := cs.Init(context.Background()) 95 if err != nil { 96 t.Error("Failed to Init ConfigStore:", err) 97 } 98 if tc.created != nil { 99 t.Errorf("ConfigMap created") 100 } 101 if tc.updated != nil { 102 t.Errorf("ConfigMap updated") 103 } 104 var ret string 105 err = cs.Get(context.Background(), "foo", &ret) 106 if err != nil { 107 t.Error("failed to return string:", err) 108 } 109 if ret != "bar" { 110 t.Errorf("got back unexpected value, wanted %q got %q", "bar", ret) 111 } 112 if cs.Get(context.Background(), "not there", &ret) == nil { 113 t.Error("non-existent key didn't error") 114 } 115 } 116 117 func TestLoadSaveUpdate(t *testing.T) { 118 tc := newTestClient([]runtime.Object{configMap(map[string]string{"foo": marshal(t, "bar")})}...) 119 cs := NewConfigMapKVStore(context.Background(), name, namespace, tc.clientset) 120 err := cs.Init(context.Background()) 121 if err != nil { 122 t.Error("Failed to Init ConfigStore:", err) 123 } 124 cs.Set(context.Background(), "jimmy", "otherbar") 125 cs.Save(context.Background()) 126 if tc.updated == nil { 127 t.Errorf("ConfigMap Not updated") 128 } 129 var ret string 130 err = cs.Get(context.Background(), "jimmy", &ret) 131 if err != nil { 132 t.Error("failed to return string:", err) 133 } 134 if ret != "otherbar" { 135 t.Errorf("got back unexpected value, wanted %q got %q", "bar", ret) 136 } 137 } 138 139 func TestLoadSaveUpdateEmptyMap(t *testing.T) { 140 // empty map, i.e. no data field 141 cm := corev1.ConfigMap{ 142 TypeMeta: metav1.TypeMeta{ 143 APIVersion: "v1", 144 Kind: "ConfigMap", 145 }, 146 ObjectMeta: metav1.ObjectMeta{ 147 Name: name, 148 Namespace: namespace, 149 }, 150 } 151 152 tc := newTestClient([]runtime.Object{&cm}...) 153 cs := NewConfigMapKVStore(context.Background(), name, namespace, tc.clientset) 154 if err := cs.Init(context.Background()); err != nil { 155 t.Error("Failed to Init ConfigStore:", err) 156 } 157 158 if err := cs.Set(context.Background(), "jimmy", "otherbar"); err != nil { 159 t.Error("Failed to set key:", err) 160 } 161 162 if err := cs.Save(context.Background()); err != nil { 163 t.Error("Failed to save configmap:", err) 164 } 165 166 if tc.updated == nil { 167 t.Errorf("ConfigMap Not updated") 168 } 169 var ret string 170 err := cs.Get(context.Background(), "jimmy", &ret) 171 if err != nil { 172 t.Error("failed to return string:", err) 173 } 174 if ret != "otherbar" { 175 t.Errorf("got back unexpected value, wanted %q got %q", "bar", ret) 176 } 177 } 178 179 func TestLoadSaveUpdateComplex(t *testing.T) { 180 ts := testStruct{ 181 LastThingProcessed: "somethingie", 182 Stuff: []string{"first", "second", "third"}, 183 } 184 185 tc := newTestClient([]runtime.Object{configMap(map[string]string{"foo": marshal(t, &ts)})}...) 186 cs := NewConfigMapKVStore(context.Background(), name, namespace, tc.clientset) 187 err := cs.Init(context.Background()) 188 if err != nil { 189 t.Error("Failed to Init ConfigStore:", err) 190 } 191 ts2 := testStruct{ 192 LastThingProcessed: "otherthingie", 193 Stuff: []string{"fourth", "fifth", "sixth"}, 194 } 195 cs.Set(context.Background(), "jimmy", &ts2) 196 cs.Save(context.Background()) 197 if tc.updated == nil { 198 t.Errorf("ConfigMap Not updated") 199 } 200 var ret testStruct 201 err = cs.Get(context.Background(), "jimmy", &ret) 202 if err != nil { 203 t.Error("failed to return string:", err) 204 } 205 if !reflect.DeepEqual(ret, ts2) { 206 t.Errorf("got back unexpected value, wanted %+v got %+v", ts2, ret) 207 } 208 } 209 210 func marshal(t *testing.T, value interface{}) string { 211 bytes, err := json.Marshal(value) 212 if err != nil { 213 t.Fatalf("Failed to Marshal %q: %v", value, err) 214 } 215 return string(bytes) 216 } 217 218 func configMap(data map[string]string) *corev1.ConfigMap { 219 return &corev1.ConfigMap{ 220 TypeMeta: metav1.TypeMeta{ 221 APIVersion: "v1", 222 Kind: "ConfigMap", 223 }, 224 ObjectMeta: metav1.ObjectMeta{ 225 Name: name, 226 Namespace: namespace, 227 }, 228 Data: data, 229 } 230 }