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  }