github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/common/user_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 package common 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 clientv3 "github.com/lfch/etcd-io/client/v3" 23 "github.com/lfch/etcd-io/tests/v3/framework" 24 "github.com/lfch/etcd-io/tests/v3/framework/config" 25 "github.com/lfch/etcd-io/tests/v3/framework/testutils" 26 "github.com/stretchr/testify/assert" 27 ) 28 29 func TestUserAdd_Simple(t *testing.T) { 30 testRunner.BeforeTest(t) 31 tcs := []struct { 32 name string 33 username string 34 password string 35 noPassword bool 36 expectedError string 37 }{ 38 { 39 name: "empty_username_not_allowed", 40 username: "", 41 password: "foobar", 42 // Very Vague error expectation because the CLI and the API return very 43 // different error structures. 44 expectedError: "user name", 45 }, 46 { 47 // Can create a user with no password, restricted to CN auth 48 name: "no_password_with_noPassword_set", 49 username: "foo", 50 password: "", 51 noPassword: true, 52 }, 53 { 54 // Can create a user with no password, but not restricted to CN auth 55 name: "no_password_without_noPassword_set", 56 username: "foo", 57 password: "", 58 noPassword: false, 59 }, 60 { 61 name: "regular_user_with_password", 62 username: "foo", 63 password: "bar", 64 }, 65 } 66 for _, tc := range clusterTestCases { 67 for _, nc := range tcs { 68 t.Run(tc.name+"/"+nc.name, func(t *testing.T) { 69 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 70 defer cancel() 71 clus := testRunner.NewCluster(ctx, t, tc.config) 72 defer clus.Close() 73 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 74 75 testutils.ExecuteUntil(ctx, t, func() { 76 resp, err := cc.UserAdd(ctx, nc.username, nc.password, config.UserAddOptions{NoPassword: nc.noPassword}) 77 if nc.expectedError != "" { 78 if err != nil { 79 assert.Contains(t, err.Error(), nc.expectedError) 80 return 81 } 82 83 t.Fatalf("expected user creation to fail") 84 } 85 86 if err != nil { 87 t.Fatalf("expected no error, err: %v", err) 88 } 89 90 if resp == nil { 91 t.Fatalf("unexpected nil response to successful user creation") 92 } 93 }) 94 }) 95 } 96 } 97 } 98 99 func TestUserAdd_DuplicateUserNotAllowed(t *testing.T) { 100 testRunner.BeforeTest(t) 101 for _, tc := range clusterTestCases { 102 t.Run(tc.name, func(t *testing.T) { 103 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 104 defer cancel() 105 clus := testRunner.NewCluster(ctx, t, tc.config) 106 defer clus.Close() 107 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 108 109 testutils.ExecuteUntil(ctx, t, func() { 110 user := "barb" 111 password := "rhubarb" 112 113 _, err := cc.UserAdd(ctx, user, password, config.UserAddOptions{}) 114 if err != nil { 115 t.Fatalf("first user creation should succeed, err: %v", err) 116 } 117 118 _, err = cc.UserAdd(ctx, user, password, config.UserAddOptions{}) 119 if err == nil { 120 t.Fatalf("duplicate user creation should fail") 121 } 122 assert.Contains(t, err.Error(), "etcdserver: user name already exists") 123 }) 124 }) 125 } 126 } 127 128 func TestUserList(t *testing.T) { 129 testRunner.BeforeTest(t) 130 for _, tc := range clusterTestCases { 131 t.Run(tc.name, func(t *testing.T) { 132 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 133 defer cancel() 134 clus := testRunner.NewCluster(ctx, t, tc.config) 135 defer clus.Close() 136 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 137 138 testutils.ExecuteUntil(ctx, t, func() { 139 // No Users Yet 140 resp, err := cc.UserList(ctx) 141 if err != nil { 142 t.Fatalf("user listing should succeed, err: %v", err) 143 } 144 if len(resp.Users) != 0 { 145 t.Fatalf("expected no pre-existing users, found: %q", resp.Users) 146 } 147 148 user := "barb" 149 password := "rhubarb" 150 151 _, err = cc.UserAdd(ctx, user, password, config.UserAddOptions{}) 152 if err != nil { 153 t.Fatalf("user creation should succeed, err: %v", err) 154 } 155 156 // Users! 157 resp, err = cc.UserList(ctx) 158 if err != nil { 159 t.Fatalf("user listing should succeed, err: %v", err) 160 } 161 if len(resp.Users) != 1 { 162 t.Fatalf("expected one user, found: %q", resp.Users) 163 } 164 }) 165 }) 166 } 167 } 168 169 func TestUserDelete(t *testing.T) { 170 testRunner.BeforeTest(t) 171 for _, tc := range clusterTestCases { 172 t.Run(tc.name, func(t *testing.T) { 173 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 174 defer cancel() 175 clus := testRunner.NewCluster(ctx, t, tc.config) 176 defer clus.Close() 177 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 178 179 testutils.ExecuteUntil(ctx, t, func() { 180 user := "barb" 181 password := "rhubarb" 182 183 _, err := cc.UserAdd(ctx, user, password, config.UserAddOptions{}) 184 if err != nil { 185 t.Fatalf("user creation should succeed, err: %v", err) 186 } 187 188 resp, err := cc.UserList(ctx) 189 if err != nil { 190 t.Fatalf("user listing should succeed, err: %v", err) 191 } 192 if len(resp.Users) != 1 { 193 t.Fatalf("expected one user, found: %q", resp.Users) 194 } 195 196 // Delete barb, sorry barb! 197 _, err = cc.UserDelete(ctx, user) 198 if err != nil { 199 t.Fatalf("user deletion should succeed at first, err: %v", err) 200 } 201 202 resp, err = cc.UserList(ctx) 203 if err != nil { 204 t.Fatalf("user listing should succeed, err: %v", err) 205 } 206 if len(resp.Users) != 0 { 207 t.Fatalf("expected no users after deletion, found: %q", resp.Users) 208 } 209 210 // Try to delete barb again 211 _, err = cc.UserDelete(ctx, user) 212 if err == nil { 213 t.Fatalf("deleting a non-existent user should fail") 214 } 215 assert.Contains(t, err.Error(), "user name not found") 216 }) 217 }) 218 } 219 } 220 221 func TestUserChangePassword(t *testing.T) { 222 testRunner.BeforeTest(t) 223 for _, tc := range clusterTestCases { 224 t.Run(tc.name, func(t *testing.T) { 225 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 226 defer cancel() 227 clus := testRunner.NewCluster(ctx, t, tc.config) 228 defer clus.Close() 229 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 230 231 testutils.ExecuteUntil(ctx, t, func() { 232 user := "barb" 233 password := "rhubarb" 234 newPassword := "potato" 235 236 _, err := cc.UserAdd(ctx, user, password, config.UserAddOptions{}) 237 if err != nil { 238 t.Fatalf("user creation should succeed, err: %v", err) 239 } 240 241 err = cc.UserChangePass(ctx, user, newPassword) 242 if err != nil { 243 t.Fatalf("user password change should succeed, err: %v", err) 244 } 245 246 err = cc.UserChangePass(ctx, "non-existent-user", newPassword) 247 if err == nil { 248 t.Fatalf("user password change for non-existent user should fail") 249 } 250 assert.Contains(t, err.Error(), "user name not found") 251 }) 252 }) 253 } 254 }