mirror of
https://github.com/rancher/steve.git
synced 2025-09-08 10:49:25 +00:00
[v0.4] Move lasso SQL cache in Steve (#473)
* Copy pkg/cache/sql from lasso to pkg/sqlcache * Rename import from github.com/rancher/lasso/pkg/cache/sql to github.com/rancher/steve/pkg/sqlcache * go mod tidy * Fix lint errors * Remove lasso SQL cache mentions * Fix more CI lint errors * fix goimports Signed-off-by: Silvio Moioli <silvio@moioli.net> * Fix imports * Fix more linting errors --------- Signed-off-by: Silvio Moioli <silvio@moioli.net> Co-authored-by: Silvio Moioli <silvio@moioli.net>
This commit is contained in:
204
pkg/sqlcache/store/db_mocks_test.go
Normal file
204
pkg/sqlcache/store/db_mocks_test.go
Normal file
@@ -0,0 +1,204 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/rancher/steve/pkg/sqlcache/db (interfaces: TXClient,Rows)
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen --build_flags=--mod=mod -package store -destination ./db_mocks_test.go github.com/rancher/steve/pkg/sqlcache/db TXClient,Rows
|
||||
//
|
||||
|
||||
// Package store is a generated GoMock package.
|
||||
package store
|
||||
|
||||
import (
|
||||
sql "database/sql"
|
||||
reflect "reflect"
|
||||
|
||||
transaction "github.com/rancher/steve/pkg/sqlcache/db/transaction"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockTXClient is a mock of TXClient interface.
|
||||
type MockTXClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTXClientMockRecorder
|
||||
}
|
||||
|
||||
// MockTXClientMockRecorder is the mock recorder for MockTXClient.
|
||||
type MockTXClientMockRecorder struct {
|
||||
mock *MockTXClient
|
||||
}
|
||||
|
||||
// NewMockTXClient creates a new mock instance.
|
||||
func NewMockTXClient(ctrl *gomock.Controller) *MockTXClient {
|
||||
mock := &MockTXClient{ctrl: ctrl}
|
||||
mock.recorder = &MockTXClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTXClient) EXPECT() *MockTXClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Cancel mocks base method.
|
||||
func (m *MockTXClient) Cancel() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Cancel")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Cancel indicates an expected call of Cancel.
|
||||
func (mr *MockTXClientMockRecorder) Cancel() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cancel", reflect.TypeOf((*MockTXClient)(nil).Cancel))
|
||||
}
|
||||
|
||||
// Commit mocks base method.
|
||||
func (m *MockTXClient) 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 *MockTXClientMockRecorder) Commit() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockTXClient)(nil).Commit))
|
||||
}
|
||||
|
||||
// Exec mocks base method.
|
||||
func (m *MockTXClient) Exec(arg0 string, arg1 ...any) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Exec", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Exec indicates an expected call of Exec.
|
||||
func (mr *MockTXClientMockRecorder) Exec(arg0 any, arg1 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockTXClient)(nil).Exec), varargs...)
|
||||
}
|
||||
|
||||
// Stmt mocks base method.
|
||||
func (m *MockTXClient) Stmt(arg0 *sql.Stmt) transaction.Stmt {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Stmt", arg0)
|
||||
ret0, _ := ret[0].(transaction.Stmt)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Stmt indicates an expected call of Stmt.
|
||||
func (mr *MockTXClientMockRecorder) Stmt(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stmt", reflect.TypeOf((*MockTXClient)(nil).Stmt), arg0)
|
||||
}
|
||||
|
||||
// StmtExec mocks base method.
|
||||
func (m *MockTXClient) StmtExec(arg0 transaction.Stmt, arg1 ...any) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "StmtExec", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StmtExec indicates an expected call of StmtExec.
|
||||
func (mr *MockTXClientMockRecorder) StmtExec(arg0 any, arg1 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StmtExec", reflect.TypeOf((*MockTXClient)(nil).StmtExec), varargs...)
|
||||
}
|
||||
|
||||
// MockRows is a mock of Rows interface.
|
||||
type MockRows struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRowsMockRecorder
|
||||
}
|
||||
|
||||
// MockRowsMockRecorder is the mock recorder for MockRows.
|
||||
type MockRowsMockRecorder struct {
|
||||
mock *MockRows
|
||||
}
|
||||
|
||||
// NewMockRows creates a new mock instance.
|
||||
func NewMockRows(ctrl *gomock.Controller) *MockRows {
|
||||
mock := &MockRows{ctrl: ctrl}
|
||||
mock.recorder = &MockRowsMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockRows) EXPECT() *MockRowsMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockRows) 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 *MockRowsMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockRows)(nil).Close))
|
||||
}
|
||||
|
||||
// Err mocks base method.
|
||||
func (m *MockRows) Err() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Err")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Err indicates an expected call of Err.
|
||||
func (mr *MockRowsMockRecorder) Err() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Err", reflect.TypeOf((*MockRows)(nil).Err))
|
||||
}
|
||||
|
||||
// Next mocks base method.
|
||||
func (m *MockRows) Next() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Next")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Next indicates an expected call of Next.
|
||||
func (mr *MockRowsMockRecorder) Next() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Next", reflect.TypeOf((*MockRows)(nil).Next))
|
||||
}
|
||||
|
||||
// Scan mocks base method.
|
||||
func (m *MockRows) Scan(arg0 ...any) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Scan", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Scan indicates an expected call of Scan.
|
||||
func (mr *MockRowsMockRecorder) Scan(arg0 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Scan", reflect.TypeOf((*MockRows)(nil).Scan), arg0...)
|
||||
}
|
351
pkg/sqlcache/store/store.go
Normal file
351
pkg/sqlcache/store/store.go
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
Package store contains the sql backed store. It persists objects to a sqlite database.
|
||||
*/
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/rancher/steve/pkg/sqlcache/db"
|
||||
"github.com/rancher/steve/pkg/sqlcache/db/transaction"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
// needed for drivers
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
const (
|
||||
upsertStmtFmt = `REPLACE INTO "%s"(key, object, objectnonce, dekid) VALUES (?, ?, ?, ?)`
|
||||
deleteStmtFmt = `DELETE FROM "%s" WHERE key = ?`
|
||||
getStmtFmt = `SELECT object, objectnonce, dekid FROM "%s" WHERE key = ?`
|
||||
listStmtFmt = `SELECT object, objectnonce, dekid FROM "%s"`
|
||||
listKeysStmtFmt = `SELECT key FROM "%s"`
|
||||
createTableFmt = `CREATE TABLE IF NOT EXISTS "%s" (
|
||||
key TEXT UNIQUE NOT NULL PRIMARY KEY,
|
||||
object BLOB,
|
||||
objectnonce BLOB,
|
||||
dekid INTEGER
|
||||
)`
|
||||
)
|
||||
|
||||
// Store is a SQLite-backed cache.Store
|
||||
type Store struct {
|
||||
DBClient
|
||||
|
||||
name string
|
||||
typ reflect.Type
|
||||
keyFunc cache.KeyFunc
|
||||
shouldEncrypt bool
|
||||
|
||||
upsertQuery string
|
||||
deleteQuery string
|
||||
getQuery string
|
||||
listQuery string
|
||||
listKeysQuery string
|
||||
|
||||
upsertStmt *sql.Stmt
|
||||
deleteStmt *sql.Stmt
|
||||
getStmt *sql.Stmt
|
||||
listStmt *sql.Stmt
|
||||
listKeysStmt *sql.Stmt
|
||||
|
||||
afterUpsert []func(key string, obj any, tx db.TXClient) error
|
||||
afterDelete []func(key string, tx db.TXClient) error
|
||||
}
|
||||
|
||||
// Test that Store implements cache.Indexer
|
||||
var _ cache.Store = (*Store)(nil)
|
||||
|
||||
type DBClient interface {
|
||||
BeginTx(ctx context.Context, forWriting bool) (db.TXClient, error)
|
||||
Prepare(stmt string) *sql.Stmt
|
||||
QueryForRows(ctx context.Context, stmt transaction.Stmt, params ...any) (*sql.Rows, error)
|
||||
ReadObjects(rows db.Rows, typ reflect.Type, shouldDecrypt bool) ([]any, error)
|
||||
ReadStrings(rows db.Rows) ([]string, error)
|
||||
ReadInt(rows db.Rows) (int, error)
|
||||
Upsert(tx db.TXClient, stmt *sql.Stmt, key string, obj any, shouldEncrypt bool) error
|
||||
CloseStmt(closable db.Closable) error
|
||||
}
|
||||
|
||||
// NewStore creates a SQLite-backed cache.Store for objects of the given example type
|
||||
func NewStore(example any, keyFunc cache.KeyFunc, c DBClient, shouldEncrypt bool, name string) (*Store, error) {
|
||||
s := &Store{
|
||||
name: name,
|
||||
typ: reflect.TypeOf(example),
|
||||
DBClient: c,
|
||||
keyFunc: keyFunc,
|
||||
shouldEncrypt: shouldEncrypt,
|
||||
afterUpsert: []func(key string, obj any, tx db.TXClient) error{},
|
||||
afterDelete: []func(key string, tx db.TXClient) error{},
|
||||
}
|
||||
|
||||
// once multiple informerfactories are needed, this can accept the case where table already exists error is received
|
||||
txC, err := s.BeginTx(context.Background(), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createTableQuery := fmt.Sprintf(createTableFmt, db.Sanitize(s.name))
|
||||
err = txC.Exec(createTableQuery)
|
||||
if err != nil {
|
||||
return nil, &db.QueryError{QueryString: createTableQuery, Err: err}
|
||||
}
|
||||
|
||||
err = txC.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.upsertQuery = fmt.Sprintf(upsertStmtFmt, db.Sanitize(s.name))
|
||||
s.deleteQuery = fmt.Sprintf(deleteStmtFmt, db.Sanitize(s.name))
|
||||
s.getQuery = fmt.Sprintf(getStmtFmt, db.Sanitize(s.name))
|
||||
s.listQuery = fmt.Sprintf(listStmtFmt, db.Sanitize(s.name))
|
||||
s.listKeysQuery = fmt.Sprintf(listKeysStmtFmt, db.Sanitize(s.name))
|
||||
|
||||
s.upsertStmt = s.Prepare(s.upsertQuery)
|
||||
s.deleteStmt = s.Prepare(s.deleteQuery)
|
||||
s.getStmt = s.Prepare(s.getQuery)
|
||||
s.listStmt = s.Prepare(s.listQuery)
|
||||
s.listKeysStmt = s.Prepare(s.listKeysQuery)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
/* Core methods */
|
||||
// upsert saves an obj with its key, or updates key with obj if it exists in this Store
|
||||
func (s *Store) upsert(key string, obj any) error {
|
||||
tx, err := s.BeginTx(context.Background(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.Upsert(tx, s.upsertStmt, key, obj, s.shouldEncrypt)
|
||||
if err != nil {
|
||||
return &db.QueryError{QueryString: s.upsertQuery, Err: err}
|
||||
}
|
||||
|
||||
err = s.runAfterUpsert(key, obj, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// deleteByKey deletes the object associated with key, if it exists in this Store
|
||||
func (s *Store) deleteByKey(key string) error {
|
||||
tx, err := s.BeginTx(context.Background(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.StmtExec(tx.Stmt(s.deleteStmt), key)
|
||||
if err != nil {
|
||||
return &db.QueryError{QueryString: s.deleteQuery, Err: err}
|
||||
}
|
||||
|
||||
err = s.runAfterDelete(key, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// GetByKey returns the object associated with the given object's key
|
||||
func (s *Store) GetByKey(key string) (item any, exists bool, err error) {
|
||||
rows, err := s.QueryForRows(context.TODO(), s.getStmt, key)
|
||||
if err != nil {
|
||||
return nil, false, &db.QueryError{QueryString: s.getQuery, Err: err}
|
||||
}
|
||||
result, err := s.ReadObjects(rows, s.typ, s.shouldEncrypt)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
return result[0], true, nil
|
||||
}
|
||||
|
||||
/* Satisfy cache.Store */
|
||||
|
||||
// Add saves an obj, or updates it if it exists in this Store
|
||||
func (s *Store) Add(obj any) error {
|
||||
key, err := s.keyFunc(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.upsert(key, obj)
|
||||
return err
|
||||
}
|
||||
|
||||
// Update saves an obj, or updates it if it exists in this Store
|
||||
func (s *Store) Update(obj any) error {
|
||||
return s.Add(obj)
|
||||
}
|
||||
|
||||
// Delete deletes the given object, if it exists in this Store
|
||||
func (s *Store) Delete(obj any) error {
|
||||
key, err := s.keyFunc(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.deleteByKey(key)
|
||||
}
|
||||
|
||||
// List returns a list of all the currently known objects
|
||||
// Note: I/O errors will panic this function, as the interface signature does not allow returning errors
|
||||
func (s *Store) List() []any {
|
||||
rows, err := s.QueryForRows(context.TODO(), s.listStmt)
|
||||
if err != nil {
|
||||
panic(&db.QueryError{QueryString: s.listQuery, Err: err})
|
||||
}
|
||||
result, err := s.ReadObjects(rows, s.typ, s.shouldEncrypt)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error in Store.List: %w", err))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ListKeys returns a list of all the keys currently in this Store
|
||||
// Note: Atm it doesn't appear returning nil in the case of an error has any detrimental effects. An error is not
|
||||
// uncommon enough nor does it appear to necessitate a panic.
|
||||
func (s *Store) ListKeys() []string {
|
||||
rows, err := s.QueryForRows(context.TODO(), s.listKeysStmt)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error in store.ListKeys: while executing query: %s got error: %v", s.listKeysQuery, err)
|
||||
return []string{}
|
||||
}
|
||||
result, err := s.ReadStrings(rows)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error in store.ListKeys: %v\n", err)
|
||||
return []string{}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Get returns the object with the same key as obj
|
||||
func (s *Store) Get(obj any) (item any, exists bool, err error) {
|
||||
key, err := s.keyFunc(obj)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return s.GetByKey(key)
|
||||
}
|
||||
|
||||
// Replace will delete the contents of the Store, using instead the given list
|
||||
func (s *Store) Replace(objects []any, _ string) error {
|
||||
objectMap := map[string]any{}
|
||||
|
||||
for _, object := range objects {
|
||||
key, err := s.keyFunc(object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objectMap[key] = object
|
||||
}
|
||||
return s.replaceByKey(objectMap)
|
||||
}
|
||||
|
||||
// replaceByKey will delete the contents of the Store, using instead the given key to obj map
|
||||
func (s *Store) replaceByKey(objects map[string]any) error {
|
||||
txC, err := s.BeginTx(context.Background(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txCListKeys := txC.Stmt(s.listKeysStmt)
|
||||
|
||||
rows, err := s.QueryForRows(context.TODO(), txCListKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keys, err := s.ReadStrings(rows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
err = txC.StmtExec(txC.Stmt(s.deleteStmt), key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.runAfterDelete(key, txC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for key, obj := range objects {
|
||||
err = s.Upsert(txC, s.upsertStmt, key, obj, s.shouldEncrypt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.runAfterUpsert(key, obj, txC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return txC.Commit()
|
||||
}
|
||||
|
||||
// Resync is a no-op and is deprecated
|
||||
func (s *Store) Resync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
|
||||
// RegisterAfterUpsert registers a func to be called after each upsert
|
||||
func (s *Store) RegisterAfterUpsert(f func(key string, obj any, txC db.TXClient) error) {
|
||||
s.afterUpsert = append(s.afterUpsert, f)
|
||||
}
|
||||
|
||||
func (s *Store) GetName() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
func (s *Store) GetShouldEncrypt() bool {
|
||||
return s.shouldEncrypt
|
||||
}
|
||||
|
||||
func (s *Store) GetType() reflect.Type {
|
||||
return s.typ
|
||||
}
|
||||
|
||||
// keep
|
||||
// runAfterUpsert executes functions registered to run after upsert
|
||||
func (s *Store) runAfterUpsert(key string, obj any, txC db.TXClient) error {
|
||||
for _, f := range s.afterUpsert {
|
||||
err := f(key, obj, txC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterAfterDelete registers a func to be called after each deletion
|
||||
func (s *Store) RegisterAfterDelete(f func(key string, txC db.TXClient) error) {
|
||||
s.afterDelete = append(s.afterDelete, f)
|
||||
}
|
||||
|
||||
// keep
|
||||
// runAfterDelete executes functions registered to run after upsert
|
||||
func (s *Store) runAfterDelete(key string, txC db.TXClient) error {
|
||||
for _, f := range s.afterDelete {
|
||||
err := f(key, txC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
165
pkg/sqlcache/store/store_mocks_test.go
Normal file
165
pkg/sqlcache/store/store_mocks_test.go
Normal file
@@ -0,0 +1,165 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/rancher/steve/pkg/sqlcache/store (interfaces: DBClient)
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen --build_flags=--mod=mod -package store -destination ./store_mocks_test.go github.com/rancher/steve/pkg/sqlcache/store DBClient
|
||||
//
|
||||
|
||||
// Package store is a generated GoMock package.
|
||||
package store
|
||||
|
||||
import (
|
||||
context "context"
|
||||
sql "database/sql"
|
||||
reflect "reflect"
|
||||
|
||||
db "github.com/rancher/steve/pkg/sqlcache/db"
|
||||
transaction "github.com/rancher/steve/pkg/sqlcache/db/transaction"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockDBClient is a mock of DBClient interface.
|
||||
type MockDBClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDBClientMockRecorder
|
||||
}
|
||||
|
||||
// MockDBClientMockRecorder is the mock recorder for MockDBClient.
|
||||
type MockDBClientMockRecorder struct {
|
||||
mock *MockDBClient
|
||||
}
|
||||
|
||||
// NewMockDBClient creates a new mock instance.
|
||||
func NewMockDBClient(ctrl *gomock.Controller) *MockDBClient {
|
||||
mock := &MockDBClient{ctrl: ctrl}
|
||||
mock.recorder = &MockDBClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockDBClient) EXPECT() *MockDBClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BeginTx mocks base method.
|
||||
func (m *MockDBClient) BeginTx(arg0 context.Context, arg1 bool) (db.TXClient, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeginTx", arg0, arg1)
|
||||
ret0, _ := ret[0].(db.TXClient)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// BeginTx indicates an expected call of BeginTx.
|
||||
func (mr *MockDBClientMockRecorder) BeginTx(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginTx", reflect.TypeOf((*MockDBClient)(nil).BeginTx), arg0, arg1)
|
||||
}
|
||||
|
||||
// CloseStmt mocks base method.
|
||||
func (m *MockDBClient) CloseStmt(arg0 db.Closable) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CloseStmt", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CloseStmt indicates an expected call of CloseStmt.
|
||||
func (mr *MockDBClientMockRecorder) CloseStmt(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseStmt", reflect.TypeOf((*MockDBClient)(nil).CloseStmt), arg0)
|
||||
}
|
||||
|
||||
// Prepare mocks base method.
|
||||
func (m *MockDBClient) Prepare(arg0 string) *sql.Stmt {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Prepare", arg0)
|
||||
ret0, _ := ret[0].(*sql.Stmt)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Prepare indicates an expected call of Prepare.
|
||||
func (mr *MockDBClientMockRecorder) Prepare(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockDBClient)(nil).Prepare), arg0)
|
||||
}
|
||||
|
||||
// QueryForRows mocks base method.
|
||||
func (m *MockDBClient) QueryForRows(arg0 context.Context, arg1 transaction.Stmt, arg2 ...any) (*sql.Rows, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "QueryForRows", varargs...)
|
||||
ret0, _ := ret[0].(*sql.Rows)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// QueryForRows indicates an expected call of QueryForRows.
|
||||
func (mr *MockDBClientMockRecorder) QueryForRows(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryForRows", reflect.TypeOf((*MockDBClient)(nil).QueryForRows), varargs...)
|
||||
}
|
||||
|
||||
// ReadInt mocks base method.
|
||||
func (m *MockDBClient) ReadInt(arg0 db.Rows) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReadInt", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ReadInt indicates an expected call of ReadInt.
|
||||
func (mr *MockDBClientMockRecorder) ReadInt(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadInt", reflect.TypeOf((*MockDBClient)(nil).ReadInt), arg0)
|
||||
}
|
||||
|
||||
// ReadObjects mocks base method.
|
||||
func (m *MockDBClient) ReadObjects(arg0 db.Rows, arg1 reflect.Type, arg2 bool) ([]any, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReadObjects", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]any)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ReadObjects indicates an expected call of ReadObjects.
|
||||
func (mr *MockDBClientMockRecorder) ReadObjects(arg0, arg1, arg2 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadObjects", reflect.TypeOf((*MockDBClient)(nil).ReadObjects), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ReadStrings mocks base method.
|
||||
func (m *MockDBClient) ReadStrings(arg0 db.Rows) ([]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReadStrings", arg0)
|
||||
ret0, _ := ret[0].([]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ReadStrings indicates an expected call of ReadStrings.
|
||||
func (mr *MockDBClientMockRecorder) ReadStrings(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadStrings", reflect.TypeOf((*MockDBClient)(nil).ReadStrings), arg0)
|
||||
}
|
||||
|
||||
// Upsert mocks base method.
|
||||
func (m *MockDBClient) Upsert(arg0 db.TXClient, arg1 *sql.Stmt, arg2 string, arg3 any, arg4 bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Upsert", arg0, arg1, arg2, arg3, arg4)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Upsert indicates an expected call of Upsert.
|
||||
func (mr *MockDBClientMockRecorder) Upsert(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upsert", reflect.TypeOf((*MockDBClient)(nil).Upsert), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
649
pkg/sqlcache/store/store_test.go
Normal file
649
pkg/sqlcache/store/store_test.go
Normal file
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
Copyright 2023 SUSE LLC
|
||||
|
||||
Adapted from client-go, Copyright 2014 The Kubernetes Authors.
|
||||
*/
|
||||
|
||||
package store
|
||||
|
||||
// Mocks for this test are generated with the following command.
|
||||
//go:generate mockgen --build_flags=--mod=mod -package store -destination ./store_mocks_test.go github.com/rancher/steve/pkg/sqlcache/store DBClient
|
||||
//go:generate mockgen --build_flags=--mod=mod -package store -destination ./db_mocks_test.go github.com/rancher/steve/pkg/sqlcache/db TXClient,Rows
|
||||
//go:generate mockgen --build_flags=--mod=mod -package store -destination ./tx_mocks_test.go github.com/rancher/steve/pkg/sqlcache/db/transaction Stmt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/rancher/steve/pkg/sqlcache/db"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
const ()
|
||||
const TEST_DB_LOCATION = "./sqlstore.sqlite"
|
||||
|
||||
func testStoreKeyFunc(obj interface{}) (string, error) {
|
||||
return obj.(testStoreObject).Id, nil
|
||||
}
|
||||
|
||||
type testStoreObject struct {
|
||||
Id string
|
||||
Val string
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
|
||||
var tests []testCase
|
||||
|
||||
// Tests with shouldEncryptSet to false
|
||||
tests = append(tests, testCase{description: "Add with no DB Client errors", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
txC.EXPECT().Commit().Return(nil)
|
||||
err := store.Add(testObject)
|
||||
assert.Nil(t, err)
|
||||
// dbclient beginerr
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "Add with no DB Client errors and an afterUpsert function", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
txC.EXPECT().Commit().Return(nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
|
||||
var count int
|
||||
store.afterUpsert = append(store.afterUpsert, func(key string, object any, tx db.TXClient) error {
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
err := store.Add(testObject)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, count, 1)
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "Add with no DB Client errors and an afterUpsert function that returns error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
store.afterUpsert = append(store.afterUpsert, func(key string, object any, txC db.TXClient) error {
|
||||
return fmt.Errorf("error")
|
||||
})
|
||||
err := store.Add(testObject)
|
||||
assert.NotNil(t, err)
|
||||
// dbclient beginerr
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "Add with DB Client BeginTx(gomock.Any(), true) error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(nil, fmt.Errorf("failed"))
|
||||
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
err := store.Add(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
tests = append(tests, testCase{description: "Add with DB Client Upsert() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(fmt.Errorf("failed"))
|
||||
err := store.Add(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
tests = append(tests, testCase{description: "Add with DB Client Upsert() error with following Rollback() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(fmt.Errorf("failed"))
|
||||
err := store.Add(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
tests = append(tests, testCase{description: "Add with DB Client Commit() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
txC.EXPECT().Commit().Return(fmt.Errorf("failed"))
|
||||
|
||||
err := store.Add(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the given object in the accumulator associated with the given object's key
|
||||
func TestUpdate(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
|
||||
var tests []testCase
|
||||
|
||||
// Tests with shouldEncryptSet to false
|
||||
tests = append(tests, testCase{description: "Update with no DB Client errors", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
txC.EXPECT().Commit().Return(nil)
|
||||
err := store.Update(testObject)
|
||||
assert.Nil(t, err)
|
||||
// dbclient beginerr
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "Update with no DB Client errors and an afterUpsert function", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
txC.EXPECT().Commit().Return(nil)
|
||||
|
||||
var count int
|
||||
store.afterUpsert = append(store.afterUpsert, func(key string, object any, txC db.TXClient) error {
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
err := store.Update(testObject)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, count, 1)
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "Update with no DB Client errors and an afterUpsert function that returns error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
|
||||
store.afterUpsert = append(store.afterUpsert, func(key string, object any, txC db.TXClient) error {
|
||||
return fmt.Errorf("error")
|
||||
})
|
||||
err := store.Update(testObject)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "Update with DB Client BeginTx(gomock.Any(), true) error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(nil, fmt.Errorf("failed"))
|
||||
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
err := store.Update(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
tests = append(tests, testCase{description: "Update with DB Client Upsert() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(fmt.Errorf("failed"))
|
||||
err := store.Update(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
tests = append(tests, testCase{description: "Update with DB Client Upsert() error with following Rollback() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(fmt.Errorf("failed"))
|
||||
err := store.Update(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
tests = append(tests, testCase{description: "Update with DB Client Commit() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, "something", testObject, store.shouldEncrypt).Return(nil)
|
||||
txC.EXPECT().Commit().Return(fmt.Errorf("failed"))
|
||||
|
||||
err := store.Update(testObject)
|
||||
assert.NotNil(t, err)
|
||||
}})
|
||||
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// Delete deletes the given object from the accumulator associated with the given object's key
|
||||
func TestDelete(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
|
||||
var tests []testCase
|
||||
|
||||
// Tests with shouldEncryptSet to false
|
||||
tests = append(tests, testCase{description: "Delete with no DB Client errors", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
// deleteStmt here will be an empty string since Prepare mock returns an empty *sql.Stmt
|
||||
txC.EXPECT().Stmt(store.deleteStmt).Return(store.deleteStmt)
|
||||
txC.EXPECT().StmtExec(store.deleteStmt, testObject.Id).Return(nil)
|
||||
txC.EXPECT().Commit().Return(nil)
|
||||
err := store.Delete(testObject)
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Delete with DB Client BeginTx(gomock.Any(), true) error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(nil, fmt.Errorf("error"))
|
||||
// deleteStmt here will be an empty string since Prepare mock returns an empty *sql.Stmt
|
||||
err := store.Delete(testObject)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Delete with TX Client StmtExec() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
txC.EXPECT().Stmt(store.deleteStmt).Return(store.deleteStmt)
|
||||
txC.EXPECT().StmtExec(store.deleteStmt, testObject.Id).Return(fmt.Errorf("error"))
|
||||
// deleteStmt here will be an empty string since Prepare mock returns an empty *sql.Stmt
|
||||
err := store.Delete(testObject)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Delete with DB Client Commit() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
// deleteStmt here will be an empty string since Prepare mock returns an empty *sql.Stmt
|
||||
txC.EXPECT().Stmt(store.deleteStmt).Return(store.deleteStmt)
|
||||
// tx.EXPECT().
|
||||
txC.EXPECT().StmtExec(store.deleteStmt, testObject.Id).Return(nil)
|
||||
txC.EXPECT().Commit().Return(fmt.Errorf("error"))
|
||||
err := store.Delete(testObject)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of all the currently non-empty accumulators
|
||||
func TestList(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
|
||||
var tests []testCase
|
||||
|
||||
tests = append(tests, testCase{description: "List with no DB Client errors and no items", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listStmt).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return([]any{}, nil)
|
||||
items := store.List()
|
||||
assert.Len(t, items, 0)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "List with no DB Client errors and some items", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
fakeItemsToReturn := []any{"something1", 2, false}
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listStmt).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return(fakeItemsToReturn, nil)
|
||||
items := store.List()
|
||||
assert.Equal(t, fakeItemsToReturn, items)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "List with DB Client ReadObjects() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listStmt).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return(nil, fmt.Errorf("error"))
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
_ = store.List()
|
||||
assert.Fail(t, "Store list should panic when ReadObjects returns an error")
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// ListKeys returns a list of all the keys currently associated with non-empty accumulators
|
||||
func TestListKeys(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
var tests []testCase
|
||||
|
||||
tests = append(tests, testCase{description: "ListKeys with no DB Client errors and some items", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return([]string{"a", "b", "c"}, nil)
|
||||
keys := store.ListKeys()
|
||||
assert.Len(t, keys, 3)
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{description: "ListKeys with DB Client ReadStrings() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return(nil, fmt.Errorf("error"))
|
||||
keys := store.ListKeys()
|
||||
assert.Len(t, keys, 0)
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the accumulator associated with the given object's key
|
||||
func TestGet(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
var tests []testCase
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
tests = append(tests, testCase{description: "Get with no DB Client errors and object exists", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.getStmt, testObject.Id).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return([]any{testObject}, nil)
|
||||
item, exists, err := store.Get(testObject)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, item, testObject)
|
||||
assert.True(t, exists)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Get with no DB Client errors and object does not exist", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.getStmt, testObject.Id).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return([]any{}, nil)
|
||||
item, exists, err := store.Get(testObject)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, item, nil)
|
||||
assert.False(t, exists)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Get with DB Client ReadObjects() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.getStmt, testObject.Id).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return(nil, fmt.Errorf("error"))
|
||||
_, _, err := store.Get(testObject)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// GetByKey returns the accumulator associated with the given key
|
||||
func TestGetByKey(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
var tests []testCase
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
tests = append(tests, testCase{description: "GetByKey with no DB Client errors and item exists", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.getStmt, testObject.Id).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return([]any{testObject}, nil)
|
||||
item, exists, err := store.GetByKey(testObject.Id)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, item, testObject)
|
||||
assert.True(t, exists)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "GetByKey with no DB Client errors and item does not exist", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.getStmt, testObject.Id).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return([]any{}, nil)
|
||||
item, exists, err := store.GetByKey(testObject.Id)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, nil, item)
|
||||
assert.False(t, exists)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "GetByKey with DB Client ReadObjects() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.getStmt, testObject.Id).Return(r, nil)
|
||||
c.EXPECT().ReadObjects(r, reflect.TypeOf(testObject), store.shouldEncrypt).Return(nil, fmt.Errorf("error"))
|
||||
_, _, err := store.GetByKey(testObject.Id)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// Replace will delete the contents of the store, using instead the
|
||||
// given list. Store takes ownership of the list, you should not reference
|
||||
// it after calling this function.
|
||||
func TestReplace(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
var tests []testCase
|
||||
testObject := testStoreObject{Id: "something", Val: "a"}
|
||||
tests = append(tests, testCase{description: "Replace with no DB Client errors and some items", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
txC.EXPECT().Stmt(store.listKeysStmt).Return(store.listKeysStmt)
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return([]string{testObject.Id}, nil)
|
||||
txC.EXPECT().Stmt(store.deleteStmt).Return(store.deleteStmt)
|
||||
txC.EXPECT().StmtExec(store.deleteStmt, testObject.Id)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, testObject.Id, testObject, store.shouldEncrypt)
|
||||
txC.EXPECT().Commit()
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Replace with no DB Client errors and no items", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, tx := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(tx, nil)
|
||||
tx.EXPECT().Stmt(store.listKeysStmt).Return(store.listKeysStmt)
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return([]string{}, nil)
|
||||
c.EXPECT().Upsert(tx, store.upsertStmt, testObject.Id, testObject, store.shouldEncrypt)
|
||||
tx.EXPECT().Commit()
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Replace with DB Client BeginTx(gomock.Any(), true) error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(nil, fmt.Errorf("error"))
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Replace with no DB Client ReadStrings() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, tx := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(tx, nil)
|
||||
tx.EXPECT().Stmt(store.listKeysStmt).Return(store.listKeysStmt)
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return(nil, fmt.Errorf("error"))
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Replace with ReadStrings() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, tx := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(tx, nil)
|
||||
tx.EXPECT().Stmt(store.listKeysStmt).Return(store.listKeysStmt)
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return(nil, fmt.Errorf("error"))
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Replace with TX Client StmtExec() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
txC.EXPECT().Stmt(store.listKeysStmt).Return(store.listKeysStmt)
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return([]string{testObject.Id}, nil)
|
||||
txC.EXPECT().Stmt(store.deleteStmt).Return(store.deleteStmt)
|
||||
txC.EXPECT().StmtExec(store.deleteStmt, testObject.Id).Return(fmt.Errorf("error"))
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{description: "Replace with DB Client Upsert() error", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, txC := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
r := &sql.Rows{}
|
||||
c.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
txC.EXPECT().Stmt(store.listKeysStmt).Return(store.listKeysStmt)
|
||||
c.EXPECT().QueryForRows(context.TODO(), store.listKeysStmt).Return(r, nil)
|
||||
c.EXPECT().ReadStrings(r).Return([]string{testObject.Id}, nil)
|
||||
txC.EXPECT().Stmt(store.deleteStmt).Return(store.deleteStmt)
|
||||
txC.EXPECT().StmtExec(store.deleteStmt, testObject.Id).Return(nil)
|
||||
c.EXPECT().Upsert(txC, store.upsertStmt, testObject.Id, testObject, store.shouldEncrypt).Return(fmt.Errorf("error"))
|
||||
err := store.Replace([]any{testObject}, testObject.Id)
|
||||
assert.NotNil(t, err)
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
// Resync is meaningless in the terms appearing here but has
|
||||
// meaning in some implementations that have non-trivial
|
||||
// additional behavior (e.g., DeltaFIFO).
|
||||
func TestResync(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
test func(t *testing.T, shouldEncrypt bool)
|
||||
}
|
||||
|
||||
var tests []testCase
|
||||
tests = append(tests, testCase{description: "Resync shouldn't call the client, panic, or do anything else", test: func(t *testing.T, shouldEncrypt bool) {
|
||||
c, _ := SetupMockDB(t)
|
||||
store := SetupStore(t, c, shouldEncrypt)
|
||||
err := store.Resync()
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
})
|
||||
t.Parallel()
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) { test.test(t, false) })
|
||||
t.Run(fmt.Sprintf("%s with encryption", test.description), func(t *testing.T) { test.test(t, true) })
|
||||
}
|
||||
}
|
||||
|
||||
func SetupMockDB(t *testing.T) (*MockDBClient, *MockTXClient) {
|
||||
dbC := NewMockDBClient(gomock.NewController(t)) // add functionality once store expectation are known
|
||||
txC := NewMockTXClient(gomock.NewController(t))
|
||||
// stmt := NewMockStmt(gomock.NewController())
|
||||
txC.EXPECT().Exec(fmt.Sprintf(createTableFmt, "testStoreObject")).Return(nil)
|
||||
txC.EXPECT().Commit().Return(nil)
|
||||
dbC.EXPECT().BeginTx(gomock.Any(), true).Return(txC, nil)
|
||||
|
||||
// use stmt mock here
|
||||
dbC.EXPECT().Prepare(fmt.Sprintf(upsertStmtFmt, "testStoreObject")).Return(&sql.Stmt{})
|
||||
dbC.EXPECT().Prepare(fmt.Sprintf(deleteStmtFmt, "testStoreObject")).Return(&sql.Stmt{})
|
||||
dbC.EXPECT().Prepare(fmt.Sprintf(getStmtFmt, "testStoreObject")).Return(&sql.Stmt{})
|
||||
dbC.EXPECT().Prepare(fmt.Sprintf(listStmtFmt, "testStoreObject")).Return(&sql.Stmt{})
|
||||
dbC.EXPECT().Prepare(fmt.Sprintf(listKeysStmtFmt, "testStoreObject")).Return(&sql.Stmt{})
|
||||
|
||||
return dbC, txC
|
||||
}
|
||||
func SetupStore(t *testing.T, client *MockDBClient, shouldEncrypt bool) *Store {
|
||||
store, err := NewStore(testStoreObject{}, testStoreKeyFunc, client, shouldEncrypt, "testStoreObject")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return store
|
||||
}
|
99
pkg/sqlcache/store/tx_mocks_test.go
Normal file
99
pkg/sqlcache/store/tx_mocks_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/rancher/steve/pkg/sqlcache/db/transaction (interfaces: Stmt)
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen --build_flags=--mod=mod -package store -destination ./tx_mocks_test.go github.com/rancher/steve/pkg/sqlcache/db/transaction Stmt
|
||||
//
|
||||
|
||||
// Package store is a generated GoMock package.
|
||||
package store
|
||||
|
||||
import (
|
||||
context "context"
|
||||
sql "database/sql"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockStmt is a mock of Stmt interface.
|
||||
type MockStmt struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockStmtMockRecorder
|
||||
}
|
||||
|
||||
// MockStmtMockRecorder is the mock recorder for MockStmt.
|
||||
type MockStmtMockRecorder struct {
|
||||
mock *MockStmt
|
||||
}
|
||||
|
||||
// NewMockStmt creates a new mock instance.
|
||||
func NewMockStmt(ctrl *gomock.Controller) *MockStmt {
|
||||
mock := &MockStmt{ctrl: ctrl}
|
||||
mock.recorder = &MockStmtMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockStmt) EXPECT() *MockStmtMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Exec mocks base method.
|
||||
func (m *MockStmt) Exec(arg0 ...any) (sql.Result, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Exec", varargs...)
|
||||
ret0, _ := ret[0].(sql.Result)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Exec indicates an expected call of Exec.
|
||||
func (mr *MockStmtMockRecorder) Exec(arg0 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockStmt)(nil).Exec), arg0...)
|
||||
}
|
||||
|
||||
// Query mocks base method.
|
||||
func (m *MockStmt) Query(arg0 ...any) (*sql.Rows, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Query", varargs...)
|
||||
ret0, _ := ret[0].(*sql.Rows)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Query indicates an expected call of Query.
|
||||
func (mr *MockStmtMockRecorder) Query(arg0 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Query", reflect.TypeOf((*MockStmt)(nil).Query), arg0...)
|
||||
}
|
||||
|
||||
// QueryContext mocks base method.
|
||||
func (m *MockStmt) QueryContext(arg0 context.Context, arg1 ...any) (*sql.Rows, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "QueryContext", varargs...)
|
||||
ret0, _ := ret[0].(*sql.Rows)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// QueryContext indicates an expected call of QueryContext.
|
||||
func (mr *MockStmtMockRecorder) QueryContext(arg0 any, arg1 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryContext", reflect.TypeOf((*MockStmt)(nil).QueryContext), varargs...)
|
||||
}
|
Reference in New Issue
Block a user