github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/lorry/engines/mysql/manager_test.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package mysql
    21  
    22  import (
    23  	. "github.com/onsi/ginkgo/v2"
    24  	. "github.com/onsi/gomega"
    25  	"github.com/spf13/viper"
    26  
    27  	"github.com/1aal/kubeblocks/pkg/lorry/engines"
    28  )
    29  
    30  const (
    31  	urlWithPort   = "root:@tcp(127.0.0.1:3306)/mysql?multiStatements=true"
    32  	urlWithNoPort = "root:@tcp(127.0.0.1)/mysql?multiStatements=true"
    33  )
    34  
    35  // Test case for Init() function
    36  var _ = Describe("MySQL DBManager", func() {
    37  	// Set up relevant viper config variables
    38  	viper.Set("KB_SERVICE_USER", "testuser")
    39  	viper.Set("KB_SERVICE_PASSWORD", "testpassword")
    40  	Context("new db manager", func() {
    41  		It("with rigth configurations", func() {
    42  			properties := engines.Properties{
    43  				"url": urlWithPort,
    44  			}
    45  			dbManger, err := NewManager(properties)
    46  			Expect(err).Should(Succeed())
    47  			Expect(dbManger).ShouldNot(BeNil())
    48  		})
    49  
    50  		It("with wrong configurations", func() {
    51  			properties := engines.Properties{
    52  				"url": "wrong-url-format",
    53  			}
    54  			dbManger, err := NewManager(properties)
    55  			Expect(err).Should(HaveOccurred())
    56  			Expect(dbManger).Should(BeNil())
    57  		})
    58  	})
    59  })
    60  
    61  // func TestGetRole(t *testing.T) {
    62  // 	mysqlOps, mock, _ := mockDatabase(t)
    63  //
    64  // 	t.Run("GetRole succeed", func(t *testing.T) {
    65  // 		col1 := sqlmock.NewColumn("CURRENT_LEADER").OfType("VARCHAR", "")
    66  // 		col2 := sqlmock.NewColumn("ROLE").OfType("VARCHAR", "")
    67  // 		col3 := sqlmock.NewColumn("SERVER_ID").OfType("INT", 0)
    68  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1, col2, col3).AddRow("wesql-main-1.wesql-main-headless:13306", "Follower", 1)
    69  // 		mock.ExpectQuery("select .* from information_schema.wesql_cluster_local").WillReturnRows(rows)
    70  //
    71  // 		role, err := mysqlOps.GetRole(context.Background(), &ProbeRequest{}, &ProbeResponse{})
    72  // 		assert.Nil(t, err)
    73  // 		assert.Equal(t, "Follower", role)
    74  // 	})
    75  //
    76  // 	t.Run("GetRole fails", func(t *testing.T) {
    77  // 		mock.ExpectQuery("select .* from information_schema.wesql_cluster_local").WillReturnError(errors.New("no record"))
    78  //
    79  // 		role, err := mysqlOps.GetRole(context.Background(), &ProbeRequest{}, &ProbeResponse{})
    80  // 		assert.Equal(t, "", role)
    81  // 		assert.NotNil(t, err)
    82  // 	})
    83  // }
    84  //
    85  // func TestGetLagOps(t *testing.T) {
    86  // 	mysqlOps, mock, _ := mockDatabase(t)
    87  // 	req := &ProbeRequest{}
    88  //
    89  // 	t.Run("GetLagOps succeed", func(t *testing.T) {
    90  // 		col1 := sqlmock.NewColumn("CURRENT_LEADER").OfType("VARCHAR", "")
    91  // 		col2 := sqlmock.NewColumn("ROLE").OfType("VARCHAR", "")
    92  // 		col3 := sqlmock.NewColumn("SERVER_ID").OfType("INT", 0)
    93  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1, col2, col3).AddRow("wesql-main-1.wesql-main-headless:13306", "Follower", 1)
    94  // 		getRoleRows := sqlmock.NewRowsWithColumnDefinition(col1, col2, col3).AddRow("wesql-main-1.wesql-main-headless:13306", "Follower", 1)
    95  // 		if mysqlOps.OriRole == "" {
    96  // 			mock.ExpectQuery("select .* from information_schema.wesql_cluster_local").WillReturnRows(getRoleRows)
    97  // 		}
    98  // 		mock.ExpectQuery("show slave status").WillReturnRows(rows)
    99  //
   100  // 		result, err := mysqlOps.GetLagOps(context.Background(), req, &ProbeResponse{})
   101  // 		assert.NoError(t, err)
   102  //
   103  // 		// Assert that the event and message are correct
   104  // 		event, ok := result["event"]
   105  // 		assert.True(t, ok)
   106  // 		assert.Equal(t, util.OperationSuccess, event)
   107  // 	})
   108  // }
   109  //
   110  // func TestQueryOps(t *testing.T) {
   111  // 	mysqlOps, mock, _ := mockDatabase(t)
   112  // 	req := &ProbeRequest{Metadata: map[string]string{}}
   113  // 	req.Metadata["sql"] = "select .* from information_schema.wesql_cluster_local"
   114  //
   115  // 	t.Run("QueryOps succeed", func(t *testing.T) {
   116  // 		col1 := sqlmock.NewColumn("CURRENT_LEADER").OfType("VARCHAR", "")
   117  // 		col2 := sqlmock.NewColumn("ROLE").OfType("VARCHAR", "")
   118  // 		col3 := sqlmock.NewColumn("SERVER_ID").OfType("INT", 0)
   119  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1, col2, col3).AddRow("wesql-main-1.wesql-main-headless:13306", "Follower", 1)
   120  // 		mock.ExpectQuery("select .* from information_schema.wesql_cluster_local").WillReturnRows(rows)
   121  //
   122  // 		result, err := mysqlOps.QueryOps(context.Background(), req, &ProbeResponse{})
   123  // 		assert.NoError(t, err)
   124  //
   125  // 		// Assert that the event and message are correct
   126  // 		event, ok := result["event"]
   127  // 		assert.True(t, ok)
   128  // 		assert.Equal(t, util.OperationSuccess, event)
   129  //
   130  // 		message, ok := result["message"]
   131  // 		assert.True(t, ok)
   132  // 		t.Logf("query message: %s", message)
   133  // 	})
   134  //
   135  // 	t.Run("QueryOps fails", func(t *testing.T) {
   136  // 		mock.ExpectQuery("select .* from information_schema.wesql_cluster_local").WillReturnError(errors.New("no record"))
   137  //
   138  // 		result, err := mysqlOps.QueryOps(context.Background(), req, &ProbeResponse{})
   139  // 		assert.NoError(t, err)
   140  //
   141  // 		// Assert that the event and message are correct
   142  // 		event, ok := result["event"]
   143  // 		assert.True(t, ok)
   144  // 		assert.Equal(t, util.OperationFailed, event)
   145  //
   146  // 		message, ok := result["message"]
   147  // 		assert.True(t, ok)
   148  // 		t.Logf("query message: %s", message)
   149  // 	})
   150  // }
   151  //
   152  // func TestExecOps(t *testing.T) {
   153  // 	mysqlOps, mock, _ := mockDatabase(t)
   154  // 	req := &ProbeRequest{Metadata: map[string]string{}}
   155  // 	req.Metadata["sql"] = "INSERT INTO foo (id, v1, ts) VALUES (1, 'test-1', '2021-01-22')"
   156  //
   157  // 	t.Run("ExecOps succeed", func(t *testing.T) {
   158  // 		mock.ExpectExec("INSERT INTO foo \\(id, v1, ts\\) VALUES \\(.*\\)").WillReturnResult(sqlmock.NewResult(1, 1))
   159  //
   160  // 		result, err := mysqlOps.ExecOps(context.Background(), req, &ProbeResponse{})
   161  // 		assert.NoError(t, err)
   162  //
   163  // 		// Assert that the event and message are correct
   164  // 		event, ok := result["event"]
   165  // 		assert.True(t, ok)
   166  // 		assert.Equal(t, util.OperationSuccess, event)
   167  //
   168  // 		count, ok := result["count"]
   169  // 		assert.True(t, ok)
   170  // 		assert.Equal(t, int64(1), count.(int64))
   171  // 	})
   172  //
   173  // 	t.Run("ExecOps fails", func(t *testing.T) {
   174  // 		mock.ExpectExec("INSERT INTO foo \\(id, v1, ts\\) VALUES \\(.*\\)").WillReturnError(errors.New("insert error"))
   175  //
   176  // 		result, err := mysqlOps.ExecOps(context.Background(), req, &ProbeResponse{})
   177  // 		assert.NoError(t, err)
   178  //
   179  // 		// Assert that the event and message are correct
   180  // 		event, ok := result["event"]
   181  // 		assert.True(t, ok)
   182  // 		assert.Equal(t, util.OperationFailed, event)
   183  //
   184  // 		message, ok := result["message"]
   185  // 		assert.True(t, ok)
   186  // 		t.Logf("exec error message: %s", message)
   187  // 	})
   188  // }
   189  //
   190  // func TestCheckStatusOps(t *testing.T) {
   191  // 	ctx := context.Background()
   192  // 	req := &ProbeRequest{}
   193  // 	resp := &ProbeResponse{Metadata: map[string]string{}}
   194  // 	mysqlOps, mock, _ := mockDatabase(t)
   195  //
   196  // 	t.Run("Check follower", func(t *testing.T) {
   197  // 		mysqlOps.OriRole = "follower"
   198  // 		col1 := sqlmock.NewColumn("id").OfType("BIGINT", 1)
   199  // 		col2 := sqlmock.NewColumn("type").OfType("BIGINT", 1)
   200  // 		col3 := sqlmock.NewColumn("check_ts").OfType("TIME", time.Now())
   201  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1, col2, col3).
   202  // 			AddRow(1, 1, time.Now())
   203  //
   204  // 		roSQL := fmt.Sprintf(`select check_ts from kb_health_check where type=%d limit 1;`, component.CheckStatusType)
   205  // 		mock.ExpectQuery(roSQL).WillReturnRows(rows)
   206  // 		// Call CheckStatusOps
   207  // 		result, err := mysqlOps.CheckStatusOps(ctx, req, resp)
   208  // 		assert.NoError(t, err)
   209  //
   210  // 		// Assert that the event and message are correct
   211  // 		event, ok := result["event"]
   212  // 		assert.True(t, ok)
   213  // 		assert.Equal(t, util.OperationSuccess, event)
   214  //
   215  // 		message, ok := result["message"]
   216  // 		assert.True(t, ok)
   217  // 		t.Logf("check status message: %s", message)
   218  // 	})
   219  //
   220  // 	t.Run("Check leader", func(t *testing.T) {
   221  // 		mysqlOps.OriRole = "leader"
   222  // 		rwSQL := fmt.Sprintf(`begin;
   223  // 	create table if not exists kb_health_check(type int, check_ts bigint, primary key(type));
   224  // 	insert into kb_health_check values(%d, now()) on duplicate key update check_ts = now();
   225  // 	commit;
   226  // 	select check_ts from kb_health_check where type=%d limit 1;`, component.CheckStatusType, component.CheckStatusType)
   227  // 		mock.ExpectExec(regexp.QuoteMeta(rwSQL)).WillReturnResult(sqlmock.NewResult(1, 1))
   228  // 		// Call CheckStatusOps
   229  // 		result, err := mysqlOps.CheckStatusOps(ctx, req, resp)
   230  // 		assert.NoError(t, err)
   231  //
   232  // 		// Assert that the event and message are correct
   233  // 		event, ok := result["event"]
   234  // 		assert.True(t, ok)
   235  // 		assert.Equal(t, util.OperationSuccess, event)
   236  //
   237  // 		message, ok := result["message"]
   238  // 		assert.True(t, ok)
   239  // 		t.Logf("check status message: %s", message)
   240  // 	})
   241  //
   242  // 	t.Run("Role not configured", func(t *testing.T) {
   243  // 		mysqlOps.OriRole = "leader1"
   244  // 		// Call CheckStatusOps
   245  // 		result, err := mysqlOps.CheckStatusOps(ctx, req, resp)
   246  // 		assert.NoError(t, err)
   247  //
   248  // 		// Assert that the event and message are correct
   249  // 		event, ok := result["event"]
   250  // 		assert.True(t, ok)
   251  // 		assert.Equal(t, util.OperationSuccess, event)
   252  //
   253  // 		message, ok := result["message"]
   254  // 		assert.True(t, ok)
   255  // 		assert.True(t, strings.HasPrefix(message.(string), "unknown access mode for role"))
   256  // 		t.Logf("check status message: %s", message)
   257  // 	})
   258  //
   259  // 	t.Run("Check failed", func(t *testing.T) {
   260  // 		mysqlOps.OriRole = "leader"
   261  // 		rwSQL := fmt.Sprintf(`begin;
   262  // 	create table if not exists kb_health_check(type int, check_ts bigint, primary key(type));
   263  // 	insert into kb_health_check values(%d, now()) on duplicate key update check_ts = now();
   264  // 	commit;
   265  // 	select check_ts from kb_health_check where type=%d limit 1;`, component.CheckStatusType, component.CheckStatusType)
   266  // 		mock.ExpectExec(regexp.QuoteMeta(rwSQL)).WillReturnError(errors.New("insert error"))
   267  // 		// Call CheckStatusOps
   268  // 		result, err := mysqlOps.CheckStatusOps(ctx, req, resp)
   269  // 		assert.NoError(t, err)
   270  //
   271  // 		// Assert that the event and message are correct
   272  // 		event, ok := result["event"]
   273  // 		assert.True(t, ok)
   274  // 		assert.Equal(t, util.OperationFailed, event)
   275  //
   276  // 		message, ok := result["message"]
   277  // 		assert.True(t, ok)
   278  // 		t.Logf("check status message: %s", message)
   279  // 	})
   280  // }
   281  //
   282  // func TestMySQLAccounts(t *testing.T) {
   283  // 	ctx := context.Background()
   284  // 	resp := &ProbeResponse{}
   285  // 	mysqlOps, mock, _ := mockDatabase(t)
   286  //
   287  // 	const (
   288  // 		userName = "turning"
   289  // 		password = "red"
   290  // 		roleName = "readOnly"
   291  // 	)
   292  // 	t.Run("Create account", func(t *testing.T) {
   293  // 		var err error
   294  // 		var result OpsResult
   295  //
   296  // 		req := &ProbeRequest{}
   297  // 		req.Operation = util.CreateUserOp
   298  // 		req.Metadata = map[string]string{}
   299  //
   300  // 		result, err = mysqlOps.createUserOps(ctx, req, resp)
   301  // 		assert.Nil(t, err)
   302  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   303  // 		assert.Equal(t, ErrNoUserName.Error(), result[util.RespFieldMessage])
   304  //
   305  // 		req.Metadata["userName"] = userName
   306  // 		result, err = mysqlOps.createUserOps(ctx, req, resp)
   307  // 		assert.Nil(t, err)
   308  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   309  // 		assert.Equal(t, ErrNoPassword.Error(), result[util.RespFieldMessage])
   310  //
   311  // 		req.Metadata["password"] = password
   312  //
   313  // 		createUserCmd := fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", req.Metadata["userName"], req.Metadata["password"])
   314  // 		mock.ExpectExec(createUserCmd).WillReturnResult(sqlmock.NewResult(1, 1))
   315  // 		result, err = mysqlOps.createUserOps(ctx, req, resp)
   316  // 		assert.Nil(t, err)
   317  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent], result[util.RespFieldMessage])
   318  // 	})
   319  //
   320  // 	t.Run("Delete account", func(t *testing.T) {
   321  // 		var err error
   322  // 		var result OpsResult
   323  //
   324  // 		req := &ProbeRequest{}
   325  // 		req.Operation = util.CreateUserOp
   326  // 		req.Metadata = map[string]string{}
   327  //
   328  // 		result, err = mysqlOps.deleteUserOps(ctx, req, resp)
   329  // 		assert.Nil(t, err)
   330  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   331  // 		assert.Equal(t, ErrNoUserName.Error(), result[util.RespFieldMessage])
   332  //
   333  // 		req.Metadata["userName"] = userName
   334  // 		deleteUserCmd := fmt.Sprintf("DROP USER IF EXISTS '%s'@'%%';", req.Metadata["userName"])
   335  // 		mock.ExpectExec(deleteUserCmd).WillReturnResult(sqlmock.NewResult(1, 1))
   336  //
   337  // 		result, err = mysqlOps.deleteUserOps(ctx, req, resp)
   338  // 		assert.Nil(t, err)
   339  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent], result[util.RespFieldMessage])
   340  // 	})
   341  // 	t.Run("Describe account", func(t *testing.T) {
   342  // 		var err error
   343  // 		var result OpsResult
   344  //
   345  // 		req := &ProbeRequest{}
   346  // 		req.Operation = util.CreateUserOp
   347  // 		req.Metadata = map[string]string{}
   348  //
   349  // 		col1 := sqlmock.NewColumn("Grants for "+userName+"@%").OfType("STRING", "turning")
   350  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1).AddRow(readOnlyRPriv)
   351  //
   352  // 		result, err = mysqlOps.describeUserOps(ctx, req, resp)
   353  // 		assert.Nil(t, err)
   354  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   355  // 		assert.Equal(t, ErrNoUserName.Error(), result[util.RespFieldMessage])
   356  //
   357  // 		req.Metadata["userName"] = userName
   358  //
   359  // 		showGrantTpl := "SHOW GRANTS FOR '%s'@'%%';"
   360  // 		descUserCmd := fmt.Sprintf(showGrantTpl, req.Metadata["userName"])
   361  // 		mock.ExpectQuery(descUserCmd).WillReturnRows(rows)
   362  //
   363  // 		result, err = mysqlOps.describeUserOps(ctx, req, resp)
   364  // 		assert.Nil(t, err)
   365  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent])
   366  //
   367  // 		data := result[util.RespFieldMessage].(string)
   368  // 		users := []util.UserInfo{}
   369  // 		err = json.Unmarshal([]byte(data), &users)
   370  // 		assert.Nil(t, err)
   371  // 		assert.Equal(t, 1, len(users))
   372  // 		assert.Equal(t, userName, users[0].UserName)
   373  // 		assert.NotEmpty(t, users[0].RoleName)
   374  // 		assert.True(t, util.ReadOnlyRole.EqualTo(users[0].RoleName))
   375  // 	})
   376  //
   377  // 	t.Run("List accounts", func(t *testing.T) {
   378  // 		var err error
   379  // 		var result OpsResult
   380  //
   381  // 		req := &ProbeRequest{}
   382  // 		req.Operation = util.CreateUserOp
   383  // 		req.Metadata = map[string]string{}
   384  //
   385  // 		col1 := sqlmock.NewColumn("userName").OfType("STRING", "turning")
   386  // 		col2 := sqlmock.NewColumn("expired").OfType("STRING", "T")
   387  //
   388  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1, col2).
   389  // 			AddRow(userName, "T").AddRow("testuser", "F")
   390  //
   391  // 		listUserCmd := "SELECT user AS userName, CASE password_expired WHEN 'N' THEN 'F' ELSE 'T' END as expired FROM mysql.user WHERE host = '%' and user <> 'root' and user not like 'kb%';"
   392  // 		mock.ExpectQuery(regexp.QuoteMeta(listUserCmd)).WillReturnRows(rows)
   393  //
   394  // 		result, err = mysqlOps.listUsersOps(ctx, req, resp)
   395  // 		assert.Nil(t, err)
   396  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent], result[util.RespFieldMessage])
   397  // 		data := result[util.RespFieldMessage].(string)
   398  // 		users := []util.UserInfo{}
   399  // 		err = json.Unmarshal([]byte(data), &users)
   400  // 		assert.Nil(t, err)
   401  // 		assert.Equal(t, 2, len(users))
   402  // 		assert.Equal(t, userName, users[0].UserName)
   403  // 	})
   404  //
   405  // 	t.Run("Grant Roles", func(t *testing.T) {
   406  // 		var err error
   407  // 		var result OpsResult
   408  //
   409  // 		req := &ProbeRequest{}
   410  // 		req.Operation = util.CreateUserOp
   411  // 		req.Metadata = map[string]string{}
   412  //
   413  // 		result, err = mysqlOps.grantUserRoleOps(ctx, req, resp)
   414  // 		assert.Nil(t, err)
   415  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   416  // 		assert.Equal(t, ErrNoUserName.Error(), result[util.RespFieldMessage])
   417  //
   418  // 		req.Metadata["userName"] = userName
   419  // 		result, err = mysqlOps.grantUserRoleOps(ctx, req, resp)
   420  // 		assert.Nil(t, err)
   421  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   422  // 		assert.Equal(t, ErrNoRoleName.Error(), result[util.RespFieldMessage])
   423  //
   424  // 		req.Metadata["roleName"] = roleName
   425  // 		roleDesc, err := mysqlOps.role2Priv(req.Metadata["roleName"])
   426  // 		assert.Nil(t, err)
   427  // 		grantRoleCmd := fmt.Sprintf("GRANT %s TO '%s'@'%%';", roleDesc, req.Metadata["userName"])
   428  //
   429  // 		mock.ExpectExec(grantRoleCmd).WillReturnResult(sqlmock.NewResult(1, 1))
   430  // 		result, err = mysqlOps.grantUserRoleOps(ctx, req, resp)
   431  // 		assert.Nil(t, err)
   432  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent], result[util.RespFieldMessage])
   433  // 	})
   434  //
   435  // 	t.Run("Revoke Roles", func(t *testing.T) {
   436  // 		var err error
   437  // 		var result OpsResult
   438  //
   439  // 		req := &ProbeRequest{}
   440  // 		req.Operation = util.CreateUserOp
   441  // 		req.Metadata = map[string]string{}
   442  //
   443  // 		result, err = mysqlOps.revokeUserRoleOps(ctx, req, resp)
   444  // 		assert.Nil(t, err)
   445  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   446  // 		assert.Equal(t, ErrNoUserName.Error(), result[util.RespFieldMessage])
   447  //
   448  // 		req.Metadata["userName"] = userName
   449  // 		result, err = mysqlOps.revokeUserRoleOps(ctx, req, resp)
   450  // 		assert.Nil(t, err)
   451  // 		assert.Equal(t, util.RespEveFail, result[util.RespFieldEvent])
   452  // 		assert.Equal(t, ErrNoRoleName.Error(), result[util.RespFieldMessage])
   453  //
   454  // 		req.Metadata["roleName"] = roleName
   455  // 		roleDesc, err := mysqlOps.role2Priv(req.Metadata["roleName"])
   456  // 		assert.Nil(t, err)
   457  // 		revokeRoleCmd := fmt.Sprintf("REVOKE %s FROM '%s'@'%%';", roleDesc, req.Metadata["userName"])
   458  //
   459  // 		mock.ExpectExec(revokeRoleCmd).WillReturnResult(sqlmock.NewResult(1, 1))
   460  // 		result, err = mysqlOps.revokeUserRoleOps(ctx, req, resp)
   461  // 		assert.Nil(t, err)
   462  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent], result[util.RespFieldMessage])
   463  // 	})
   464  // 	t.Run("List System Accounts", func(t *testing.T) {
   465  // 		var err error
   466  // 		var result OpsResult
   467  //
   468  // 		req := &ProbeRequest{}
   469  // 		req.Operation = util.CreateUserOp
   470  // 		req.Metadata = map[string]string{}
   471  //
   472  // 		col1 := sqlmock.NewColumn("userName").OfType("STRING", "turning")
   473  //
   474  // 		rows := sqlmock.NewRowsWithColumnDefinition(col1).
   475  // 			AddRow("kbadmin")
   476  //
   477  // 		stmt := "SELECT user AS userName FROM mysql.user WHERE host = '%' and user like 'kb%';"
   478  // 		mock.ExpectQuery(regexp.QuoteMeta(stmt)).WillReturnRows(rows)
   479  //
   480  // 		result, err = mysqlOps.listSystemAccountsOps(ctx, req, resp)
   481  // 		assert.Nil(t, err)
   482  // 		assert.Equal(t, util.RespEveSucc, result[util.RespFieldEvent], result[util.RespFieldMessage])
   483  // 		data := result[util.RespFieldMessage].(string)
   484  // 		users := []string{}
   485  // 		err = json.Unmarshal([]byte(data), &users)
   486  // 		assert.Nil(t, err)
   487  // 		assert.Equal(t, 1, len(users))
   488  // 		assert.Equal(t, "kbadmin", users[0])
   489  // 	})
   490  // }
   491  // func mockDatabase(t *testing.T) (*MysqlOperations, sqlmock.Sqlmock, error) {
   492  // 	viper.SetDefault("KB_SERVICE_ROLES", "{\"follower\":\"Readonly\",\"leader\":\"ReadWrite\"}")
   493  // 	viper.Set("KB_POD_NAME", "test-pod-0")
   494  // 	viper.Set(constant.KBEnvWorkloadType, "consensus")
   495  // 	db, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
   496  // 	if err != nil {
   497  // 		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
   498  // 	}
   499  //
   500  // 	properties := make(component.Properties)
   501  // 	properties["url"] = urlWithPort
   502  // 	mysqlOps := NewMysql()
   503  // 	_ = mysqlOps.Init(properties)
   504  // 	mysqlOps.Manager.(*mysql.WesqlManager).DB = db
   505  //
   506  // 	return mysqlOps, mock, err
   507  // }
   508  //