github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/integration/clientv3/mirror_auth_test.go (about) 1 // Copyright 2022 The etcd 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 //go:build !cluster_proxy 16 // +build !cluster_proxy 17 18 package clientv3test 19 20 import ( 21 "context" 22 "reflect" 23 "testing" 24 "time" 25 26 "github.com/lfch/etcd-io/api/v3/mvccpb" 27 clientv3 "github.com/lfch/etcd-io/client/v3" 28 "github.com/lfch/etcd-io/client/v3/mirror" 29 integration2 "github.com/lfch/etcd-io/tests/v3/framework/integration" 30 "google.golang.org/grpc" 31 ) 32 33 func TestMirrorSync_Authenticated(t *testing.T) { 34 integration2.BeforeTest(t) 35 clus := integration2.NewCluster(t, &integration2.ClusterConfig{Size: 1}) 36 defer clus.Terminate(t) 37 38 initialClient := clus.Client(0) 39 40 // Create a user to run the mirror process that only has access to /syncpath 41 initialClient.RoleAdd(context.Background(), "syncer") 42 initialClient.RoleGrantPermission(context.Background(), "syncer", "/syncpath", clientv3.GetPrefixRangeEnd("/syncpath"), clientv3.PermissionType(clientv3.PermReadWrite)) 43 initialClient.UserAdd(context.Background(), "syncer", "syncfoo") 44 initialClient.UserGrantRole(context.Background(), "syncer", "syncer") 45 46 // Seed /syncpath with some initial data 47 _, err := initialClient.KV.Put(context.TODO(), "/syncpath/foo", "bar") 48 if err != nil { 49 t.Fatal(err) 50 } 51 52 // Require authentication 53 authSetupRoot(t, initialClient.Auth) 54 55 // Create a client as the `syncer` user. 56 cfg := clientv3.Config{ 57 Endpoints: initialClient.Endpoints(), 58 DialTimeout: 5 * time.Second, 59 DialOptions: []grpc.DialOption{grpc.WithBlock()}, 60 Username: "syncer", 61 Password: "syncfoo", 62 } 63 syncClient, err := integration2.NewClient(t, cfg) 64 if err != nil { 65 t.Fatal(err) 66 } 67 defer syncClient.Close() 68 69 // Now run the sync process, create changes, and get the initial sync state 70 syncer := mirror.NewSyncer(syncClient, "/syncpath", 0) 71 gch, ech := syncer.SyncBase(context.TODO()) 72 wkvs := []*mvccpb.KeyValue{{Key: []byte("/syncpath/foo"), Value: []byte("bar"), CreateRevision: 2, ModRevision: 2, Version: 1}} 73 74 for g := range gch { 75 if !reflect.DeepEqual(g.Kvs, wkvs) { 76 t.Fatalf("kv = %v, want %v", g.Kvs, wkvs) 77 } 78 } 79 80 for e := range ech { 81 t.Fatalf("unexpected error %v", e) 82 } 83 84 // Start a continuous sync 85 wch := syncer.SyncUpdates(context.TODO()) 86 87 // Update state 88 _, err = syncClient.KV.Put(context.TODO(), "/syncpath/foo", "baz") 89 if err != nil { 90 t.Fatal(err) 91 } 92 93 // Wait for the updated state to sync 94 select { 95 case r := <-wch: 96 wkv := &mvccpb.KeyValue{Key: []byte("/syncpath/foo"), Value: []byte("baz"), CreateRevision: 2, ModRevision: 3, Version: 2} 97 if !reflect.DeepEqual(r.Events[0].Kv, wkv) { 98 t.Fatalf("kv = %v, want %v", r.Events[0].Kv, wkv) 99 } 100 case <-time.After(time.Second): 101 t.Fatal("failed to receive update in one second") 102 } 103 }