From 2722701ab23749bc791c0fdb41f266a99104dd39 Mon Sep 17 00:00:00 2001 From: Zijian Date: Tue, 19 Dec 2023 18:02:07 -0800 Subject: [PATCH] Add unit test for mysql configstore (#5502) --- common/persistence/sql/sqldriver/interface.go | 2 + .../sql/sqldriver/interface_mock.go | 343 ++++++++++++++++++ .../sql/sqlplugin/mysql/configstore.go | 6 - .../sql/sqlplugin/mysql/configstore_sql.go | 29 ++ .../sql/sqlplugin/mysql/configstore_test.go | 157 ++++++++ 5 files changed, 531 insertions(+), 6 deletions(-) create mode 100644 common/persistence/sql/sqldriver/interface_mock.go create mode 100644 common/persistence/sql/sqlplugin/mysql/configstore_sql.go create mode 100644 common/persistence/sql/sqlplugin/mysql/configstore_test.go diff --git a/common/persistence/sql/sqldriver/interface.go b/common/persistence/sql/sqldriver/interface.go index 9493b89cf13..bcad38c3a6a 100644 --- a/common/persistence/sql/sqldriver/interface.go +++ b/common/persistence/sql/sqldriver/interface.go @@ -18,6 +18,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination interface_mock.go -self_package github.com/uber/cadence/common/persistence/sql/sqldriver + package sqldriver import ( diff --git a/common/persistence/sql/sqldriver/interface_mock.go b/common/persistence/sql/sqldriver/interface_mock.go new file mode 100644 index 00000000000..9cc0defd16a --- /dev/null +++ b/common/persistence/sql/sqldriver/interface_mock.go @@ -0,0 +1,343 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Code generated by MockGen. DO NOT EDIT. +// Source: interface.go + +// Package sqldriver is a generated GoMock package. +package sqldriver + +import ( + context "context" + sql "database/sql" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + sqlx "github.com/jmoiron/sqlx" +) + +// MockDriver is a mock of Driver interface. +type MockDriver struct { + ctrl *gomock.Controller + recorder *MockDriverMockRecorder +} + +// MockDriverMockRecorder is the mock recorder for MockDriver. +type MockDriverMockRecorder struct { + mock *MockDriver +} + +// NewMockDriver creates a new mock instance. +func NewMockDriver(ctrl *gomock.Controller) *MockDriver { + mock := &MockDriver{ctrl: ctrl} + mock.recorder = &MockDriverMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDriver) EXPECT() *MockDriverMockRecorder { + return m.recorder +} + +// BeginTxx mocks base method. +func (m *MockDriver) BeginTxx(ctx context.Context, dbShardID int, opts *sql.TxOptions) (*sqlx.Tx, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BeginTxx", ctx, dbShardID, opts) + ret0, _ := ret[0].(*sqlx.Tx) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BeginTxx indicates an expected call of BeginTxx. +func (mr *MockDriverMockRecorder) BeginTxx(ctx, dbShardID, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginTxx", reflect.TypeOf((*MockDriver)(nil).BeginTxx), ctx, dbShardID, opts) +} + +// Close mocks base method. +func (m *MockDriver) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockDriverMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDriver)(nil).Close)) +} + +// Commit mocks base method. +func (m *MockDriver) Commit() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Commit") + ret0, _ := ret[0].(error) + return ret0 +} + +// Commit indicates an expected call of Commit. +func (mr *MockDriverMockRecorder) Commit() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockDriver)(nil).Commit)) +} + +// ExecContext mocks base method. +func (m *MockDriver) ExecContext(ctx context.Context, dbShardID int, query string, args ...interface{}) (sql.Result, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExecContext", varargs...) + ret0, _ := ret[0].(sql.Result) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecContext indicates an expected call of ExecContext. +func (mr *MockDriverMockRecorder) ExecContext(ctx, dbShardID, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecContext", reflect.TypeOf((*MockDriver)(nil).ExecContext), varargs...) +} + +// ExecDDL mocks base method. +func (m *MockDriver) ExecDDL(ctx context.Context, dbShardID int, query string, args ...interface{}) (sql.Result, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExecDDL", varargs...) + ret0, _ := ret[0].(sql.Result) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecDDL indicates an expected call of ExecDDL. +func (mr *MockDriverMockRecorder) ExecDDL(ctx, dbShardID, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecDDL", reflect.TypeOf((*MockDriver)(nil).ExecDDL), varargs...) +} + +// GetContext mocks base method. +func (m *MockDriver) GetContext(ctx context.Context, dbShardID int, dest interface{}, query string, args ...interface{}) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, dest, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetContext", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// GetContext indicates an expected call of GetContext. +func (mr *MockDriverMockRecorder) GetContext(ctx, dbShardID, dest, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, dest, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContext", reflect.TypeOf((*MockDriver)(nil).GetContext), varargs...) +} + +// GetForSchemaQuery mocks base method. +func (m *MockDriver) GetForSchemaQuery(dbShardID int, dest interface{}, query string, args ...interface{}) error { + m.ctrl.T.Helper() + varargs := []interface{}{dbShardID, dest, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetForSchemaQuery", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// GetForSchemaQuery indicates an expected call of GetForSchemaQuery. +func (mr *MockDriverMockRecorder) GetForSchemaQuery(dbShardID, dest, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{dbShardID, dest, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetForSchemaQuery", reflect.TypeOf((*MockDriver)(nil).GetForSchemaQuery), varargs...) +} + +// NamedExecContext mocks base method. +func (m *MockDriver) NamedExecContext(ctx context.Context, dbShardID int, query string, arg interface{}) (sql.Result, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NamedExecContext", ctx, dbShardID, query, arg) + ret0, _ := ret[0].(sql.Result) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NamedExecContext indicates an expected call of NamedExecContext. +func (mr *MockDriverMockRecorder) NamedExecContext(ctx, dbShardID, query, arg interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NamedExecContext", reflect.TypeOf((*MockDriver)(nil).NamedExecContext), ctx, dbShardID, query, arg) +} + +// Rollback mocks base method. +func (m *MockDriver) Rollback() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Rollback") + ret0, _ := ret[0].(error) + return ret0 +} + +// Rollback indicates an expected call of Rollback. +func (mr *MockDriverMockRecorder) Rollback() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockDriver)(nil).Rollback)) +} + +// SelectContext mocks base method. +func (m *MockDriver) SelectContext(ctx context.Context, dbShardID int, dest interface{}, query string, args ...interface{}) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, dest, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SelectContext", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// SelectContext indicates an expected call of SelectContext. +func (mr *MockDriverMockRecorder) SelectContext(ctx, dbShardID, dest, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, dest, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectContext", reflect.TypeOf((*MockDriver)(nil).SelectContext), varargs...) +} + +// SelectForSchemaQuery mocks base method. +func (m *MockDriver) SelectForSchemaQuery(dbShardID int, dest interface{}, query string, args ...interface{}) error { + m.ctrl.T.Helper() + varargs := []interface{}{dbShardID, dest, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SelectForSchemaQuery", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// SelectForSchemaQuery indicates an expected call of SelectForSchemaQuery. +func (mr *MockDriverMockRecorder) SelectForSchemaQuery(dbShardID, dest, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{dbShardID, dest, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectForSchemaQuery", reflect.TypeOf((*MockDriver)(nil).SelectForSchemaQuery), varargs...) +} + +// MockcommonOfDbAndTx is a mock of commonOfDbAndTx interface. +type MockcommonOfDbAndTx struct { + ctrl *gomock.Controller + recorder *MockcommonOfDbAndTxMockRecorder +} + +// MockcommonOfDbAndTxMockRecorder is the mock recorder for MockcommonOfDbAndTx. +type MockcommonOfDbAndTxMockRecorder struct { + mock *MockcommonOfDbAndTx +} + +// NewMockcommonOfDbAndTx creates a new mock instance. +func NewMockcommonOfDbAndTx(ctrl *gomock.Controller) *MockcommonOfDbAndTx { + mock := &MockcommonOfDbAndTx{ctrl: ctrl} + mock.recorder = &MockcommonOfDbAndTxMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockcommonOfDbAndTx) EXPECT() *MockcommonOfDbAndTxMockRecorder { + return m.recorder +} + +// ExecContext mocks base method. +func (m *MockcommonOfDbAndTx) ExecContext(ctx context.Context, dbShardID int, query string, args ...interface{}) (sql.Result, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExecContext", varargs...) + ret0, _ := ret[0].(sql.Result) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecContext indicates an expected call of ExecContext. +func (mr *MockcommonOfDbAndTxMockRecorder) ExecContext(ctx, dbShardID, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecContext", reflect.TypeOf((*MockcommonOfDbAndTx)(nil).ExecContext), varargs...) +} + +// GetContext mocks base method. +func (m *MockcommonOfDbAndTx) GetContext(ctx context.Context, dbShardID int, dest interface{}, query string, args ...interface{}) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, dest, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetContext", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// GetContext indicates an expected call of GetContext. +func (mr *MockcommonOfDbAndTxMockRecorder) GetContext(ctx, dbShardID, dest, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, dest, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContext", reflect.TypeOf((*MockcommonOfDbAndTx)(nil).GetContext), varargs...) +} + +// NamedExecContext mocks base method. +func (m *MockcommonOfDbAndTx) NamedExecContext(ctx context.Context, dbShardID int, query string, arg interface{}) (sql.Result, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NamedExecContext", ctx, dbShardID, query, arg) + ret0, _ := ret[0].(sql.Result) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NamedExecContext indicates an expected call of NamedExecContext. +func (mr *MockcommonOfDbAndTxMockRecorder) NamedExecContext(ctx, dbShardID, query, arg interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NamedExecContext", reflect.TypeOf((*MockcommonOfDbAndTx)(nil).NamedExecContext), ctx, dbShardID, query, arg) +} + +// SelectContext mocks base method. +func (m *MockcommonOfDbAndTx) SelectContext(ctx context.Context, dbShardID int, dest interface{}, query string, args ...interface{}) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, dbShardID, dest, query} + for _, a := range args { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SelectContext", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// SelectContext indicates an expected call of SelectContext. +func (mr *MockcommonOfDbAndTxMockRecorder) SelectContext(ctx, dbShardID, dest, query interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, dbShardID, dest, query}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectContext", reflect.TypeOf((*MockcommonOfDbAndTx)(nil).SelectContext), varargs...) +} diff --git a/common/persistence/sql/sqlplugin/mysql/configstore.go b/common/persistence/sql/sqlplugin/mysql/configstore.go index e69f7145ace..1dbfeca1c01 100644 --- a/common/persistence/sql/sqlplugin/mysql/configstore.go +++ b/common/persistence/sql/sqlplugin/mysql/configstore.go @@ -30,12 +30,6 @@ import ( "github.com/uber/cadence/common/persistence/sql/sqlplugin" ) -const ( - _selectLatestConfigQuery = "SELECT row_type, version, timestamp, data, data_encoding FROM cluster_config WHERE row_type = ? ORDER BY version LIMIT 1;" - - _insertConfigQuery = "INSERT INTO cluster_config (row_type, version, timestamp, data, data_encoding) VALUES(?, ?, ?, ?, ?)" -) - func (mdb *db) InsertConfig(ctx context.Context, row *persistence.InternalConfigStoreEntry) error { _, err := mdb.driver.ExecContext(ctx, sqlplugin.DbDefaultShard, _insertConfigQuery, row.RowType, -1*row.Version, mdb.converter.ToMySQLDateTime(row.Timestamp), row.Values.Data, row.Values.Encoding) return err diff --git a/common/persistence/sql/sqlplugin/mysql/configstore_sql.go b/common/persistence/sql/sqlplugin/mysql/configstore_sql.go new file mode 100644 index 00000000000..38428b60f6c --- /dev/null +++ b/common/persistence/sql/sqlplugin/mysql/configstore_sql.go @@ -0,0 +1,29 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package mysql + +const ( + _selectLatestConfigQuery = "SELECT row_type, version, timestamp, data, data_encoding FROM cluster_config WHERE row_type = ? ORDER BY version LIMIT 1;" + + _insertConfigQuery = "INSERT INTO cluster_config (row_type, version, timestamp, data, data_encoding) VALUES(?, ?, ?, ?, ?)" +) diff --git a/common/persistence/sql/sqlplugin/mysql/configstore_test.go b/common/persistence/sql/sqlplugin/mysql/configstore_test.go new file mode 100644 index 00000000000..f9f59346af7 --- /dev/null +++ b/common/persistence/sql/sqlplugin/mysql/configstore_test.go @@ -0,0 +1,157 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package mysql + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + "github.com/uber/cadence/common" + "github.com/uber/cadence/common/persistence" + "github.com/uber/cadence/common/persistence/sql/sqldriver" + "github.com/uber/cadence/common/persistence/sql/sqlplugin" +) + +func TestInsertConfig(t *testing.T) { + testCases := []struct { + name string + row *persistence.InternalConfigStoreEntry + mockSetup func(*sqldriver.MockDriver) + expectError bool + }{ + { + name: "Success case", + row: &persistence.InternalConfigStoreEntry{ + Values: &persistence.DataBlob{}, + }, + mockSetup: func(mockDriver *sqldriver.MockDriver) { + mockDriver.EXPECT().ExecContext(gomock.Any(), sqlplugin.DbDefaultShard, _insertConfigQuery, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + }, + expectError: false, + }, + { + name: "Error case", + row: &persistence.InternalConfigStoreEntry{ + Values: &persistence.DataBlob{}, + }, + mockSetup: func(mockDriver *sqldriver.MockDriver) { + mockDriver.EXPECT().ExecContext(gomock.Any(), sqlplugin.DbDefaultShard, _insertConfigQuery, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + }, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockDriver := sqldriver.NewMockDriver(ctrl) + mdb := &db{driver: mockDriver, converter: &converter{}} + + // Setup mock expectations + tc.mockSetup(mockDriver) + + err := mdb.InsertConfig(context.Background(), tc.row) + if tc.expectError { + assert.Error(t, err, "Expected an error for test case") + } else { + assert.NoError(t, err, "Did not expect an error for test case") + } + }) + } +} + +func TestSelectLatestConfig(t *testing.T) { + now := time.Now() + testCases := []struct { + name string + rowType int + setupMock func(*sqldriver.MockDriver) + expectError bool + expectedRow *persistence.InternalConfigStoreEntry + }{ + { + name: "Success case", + rowType: 1, + setupMock: func(md *sqldriver.MockDriver) { + row := sqlplugin.ClusterConfigRow{ + RowType: 1, + Version: -2, + Timestamp: now, + Data: []byte("test data"), + DataEncoding: "json", + } + md.EXPECT().GetContext(gomock.Any(), sqlplugin.DbDefaultShard, gomock.Any(), _selectLatestConfigQuery, 1).DoAndReturn( + func(ctx context.Context, shardID int, r *sqlplugin.ClusterConfigRow, query string, args ...interface{}) error { + *r = row + return nil + }, + ) + }, + expectError: false, + expectedRow: &persistence.InternalConfigStoreEntry{ + RowType: 1, + Version: 2, + Timestamp: now, + Values: &persistence.DataBlob{ + Data: []byte("test data"), + Encoding: common.EncodingType("json"), + }, + }, + }, + { + name: "Error case", + rowType: 2, + setupMock: func(md *sqldriver.MockDriver) { + md.EXPECT().GetContext(gomock.Any(), sqlplugin.DbDefaultShard, gomock.Any(), _selectLatestConfigQuery, 2).Return(errors.New("some error")) + }, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockDriver := sqldriver.NewMockDriver(ctrl) + mdb := &db{driver: mockDriver, converter: &converter{}} + + tc.setupMock(mockDriver) + + row, err := mdb.SelectLatestConfig(context.Background(), tc.rowType) + if tc.expectError { + assert.Error(t, err, "Expected an error for test case") + } else { + assert.NoError(t, err, "Did not expect an error for test case") + assert.Equal(t, tc.expectedRow, row, "Expected result to be the same for test case") + } + }) + } +}