k8s.io/apiserver@v0.31.1/pkg/storage/etcd3/linearized_read_test.go (about) 1 /* 2 Copyright 2022 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 etcd3 18 19 import ( 20 "testing" 21 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/apiserver/pkg/apis/example" 24 "k8s.io/apiserver/pkg/storage" 25 ) 26 27 func TestLinearizedReadRevisionInvariant(t *testing.T) { 28 // The etcd documentation [1] states that "linearized requests must go through the Raft consensus process." 29 // A full round of Raft consensus adds a new item to the Raft log, some of which is surfaced by etcd as a 30 // higher store revision in the response header. Kubernetes exposes this header revision in e.g. List calls, 31 // so it is ultimately client-facing. By default, all the requests that our *etcd3.store{} issues are 32 // linearized. However, this also includes *read* requests, and we would not expect non-mutating requests 33 // against etcd to, by "go[ing] through the Raft consensus process," result in a higher resource version on 34 // List calls. Today, the mechanism etcd uses to increment the store revision ensures that linearized reads 35 // do *not* bump the key-value store revision. This test exists to ensure that we notice if this implementation 36 // detail ever changes. 37 // [1] https://etcd.io/docs/v3.5/learning/api_guarantees/#isolation-level-and-consistency-of-replicas 38 ctx, store, etcdClient := testSetup(t) 39 40 dir := "/testing" 41 key := dir + "/testkey" 42 out := &example.Pod{} 43 obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", SelfLink: "testlink"}} 44 45 if err := store.Create(ctx, key, obj, out, 0); err != nil { 46 t.Fatalf("Set failed: %v", err) 47 } 48 originalRevision := out.ResourceVersion 49 50 for i := 0; i < 5; i++ { 51 if _, err := etcdClient.KV.Get(ctx, key); err != nil { // this is by default linearizable, the only option the client library exposes is WithSerializable() to make it *not* a linearized read 52 t.Fatalf("failed to get key: %v", err) 53 } 54 } 55 56 list := &example.PodList{} 57 if err := store.GetList(ctx, dir, storage.ListOptions{Predicate: storage.Everything, Recursive: true}, list); err != nil { 58 t.Errorf("Unexpected List error: %v", err) 59 } 60 finalRevision := list.ResourceVersion 61 62 if originalRevision != finalRevision { 63 t.Fatalf("original revision (%s) did not match final revision after linearized reads (%s)", originalRevision, finalRevision) 64 } 65 }