2025-01-17 14:34:48 +00:00
/ *
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.
2025-02-05 09:05:52 +00:00
//go:generate mockgen --build_flags=--mod=mod -package store -destination ./db_mocks_test.go github.com/rancher/steve/pkg/sqlcache/db Rows,Client
//go:generate mockgen --build_flags=--mod=mod -package store -destination ./transaction_mocks_test.go -mock_names Client=MockTXClient github.com/rancher/steve/pkg/sqlcache/db/transaction Stmt,Client
2025-01-17 14:34:48 +00:00
import (
"context"
"database/sql"
"fmt"
"reflect"
2025-06-25 23:10:48 +00:00
"regexp"
"strings"
2025-01-17 14:34:48 +00:00
"testing"
"github.com/rancher/steve/pkg/sqlcache/db"
2025-02-05 09:05:52 +00:00
"github.com/rancher/steve/pkg/sqlcache/db/transaction"
2025-07-03 21:35:09 +00:00
"github.com/rancher/steve/pkg/sqlcache/sqltypes"
2025-01-17 14:34:48 +00:00
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
2025-06-25 23:10:48 +00:00
"k8s.io/apimachinery/pkg/runtime/schema"
2025-01-17 14:34:48 +00:00
)
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
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Add with no DB client errors" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Add ( testObject )
assert . Nil ( t , err )
} ,
} )
2025-05-30 12:25:12 +00:00
tests = append ( tests , testCase { description : "Add with no DB client errors and an afterAdd function" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
var count int
2025-05-30 12:25:12 +00:00
store . afterAdd = append ( store . afterAdd , func ( key string , object any , tx transaction . Client ) error {
2025-01-17 14:34:48 +00:00
count ++
return nil
} )
err := store . Add ( testObject )
assert . Nil ( t , err )
assert . Equal ( t , count , 1 )
} ,
} )
2025-05-30 12:25:12 +00:00
tests = append ( tests , testCase { description : "Add with no DB client errors and an afterAdd function that returns error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-05-30 12:25:12 +00:00
store . afterAdd = append ( store . afterAdd , func ( key string , object any , txC transaction . Client ) error {
2025-01-17 14:34:48 +00:00
return fmt . Errorf ( "error" )
} )
err := store . Add ( testObject )
assert . NotNil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Add with DB client WithTransaction error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "failed" ) )
2025-01-17 14:34:48 +00:00
store := SetupStore ( t , c , shouldEncrypt )
err := store . Add ( testObject )
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Add with DB client Upsert() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( fmt . Errorf ( "failed" ) )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "failed" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Add ( testObject )
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Add with DB client Commit() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "failed" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
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
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Update with no DB client errors" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Update ( testObject )
assert . Nil ( t , err )
} ,
} )
2025-05-30 12:25:12 +00:00
tests = append ( tests , testCase { description : "Update with no DB client errors and an afterUpdate function" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
var count int
2025-05-30 12:25:12 +00:00
store . afterUpdate = append ( store . afterUpdate , func ( key string , object any , txC transaction . Client ) error {
2025-01-17 14:34:48 +00:00
count ++
return nil
} )
err := store . Update ( testObject )
assert . Nil ( t , err )
assert . Equal ( t , count , 1 )
} ,
} )
2025-05-30 12:25:12 +00:00
tests = append ( tests , testCase { description : "Update with no DB client errors and an afterUpdate function that returns error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( nil )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-05-30 12:25:12 +00:00
store . afterUpdate = append ( store . afterUpdate , func ( key string , object any , txC transaction . Client ) error {
2025-01-17 14:34:48 +00:00
return fmt . Errorf ( "error" )
} )
err := store . Update ( testObject )
assert . NotNil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Update with DB client WithTransaction returning error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
store := SetupStore ( t , c , shouldEncrypt )
err := store . Update ( testObject )
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Update with DB client Upsert() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "something" , testObject , store . shouldEncrypt ) . Return ( fmt . Errorf ( "failed" ) )
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
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
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Delete with no DB client errors" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
stmt := NewMockStmt ( gomock . NewController ( t ) )
txC . EXPECT ( ) . Stmt ( store . deleteStmt ) . Return ( stmt )
stmt . EXPECT ( ) . Exec ( testObject . Id ) . Return ( nil , nil )
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Delete ( testObject )
assert . Nil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Delete with DB client WithTransaction returning error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
err := store . Delete ( testObject )
assert . NotNil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Delete with TX client Exec() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
stmt := NewMockStmt ( gomock . NewController ( t ) )
txC . EXPECT ( ) . Stmt ( store . deleteStmt ) . Return ( stmt )
stmt . EXPECT ( ) . Exec ( testObject . Id ) . Return ( nil , fmt . Errorf ( "error" ) )
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Delete ( testObject )
assert . NotNil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Delete with DB client Commit() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
stmt := NewMockStmt ( gomock . NewController ( t ) )
txC . EXPECT ( ) . Stmt ( store . deleteStmt ) . Return ( stmt )
stmt . EXPECT ( ) . Exec ( testObject . Id ) . Return ( nil , nil )
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
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
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "List with no DB client errors and no items" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . listStmt ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . ReadObjects ( r , reflect . TypeOf ( testObject ) , store . shouldEncrypt ) . Return ( [ ] any { } , nil )
items := store . List ( )
assert . Len ( t , items , 0 )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "List with no DB client errors and some items" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
fakeItemsToReturn := [ ] any { "something1" , 2 , false }
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . listStmt ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . ReadObjects ( r , reflect . TypeOf ( testObject ) , store . shouldEncrypt ) . Return ( fakeItemsToReturn , nil )
items := store . List ( )
assert . Equal ( t , fakeItemsToReturn , items )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "List with DB client ReadObjects() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . listStmt ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "ListKeys with no DB client errors and some items" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . listKeysStmt ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . ReadStrings ( r ) . Return ( [ ] string { "a" , "b" , "c" } , nil )
keys := store . ListKeys ( )
assert . Len ( t , keys , 3 )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "ListKeys with DB client ReadStrings() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . listKeysStmt ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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" }
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Get with no DB client errors and object exists" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . getStmt , testObject . Id ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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 )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Get with no DB client errors and object does not exist" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . getStmt , testObject . Id ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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 )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Get with DB client ReadObjects() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . getStmt , testObject . Id ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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" }
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "GetByKey with no DB client errors and item exists" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . getStmt , testObject . Id ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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 )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "GetByKey with no DB client errors and item does not exist" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . getStmt , testObject . Id ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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 )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "GetByKey with DB client ReadObjects() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
r := & sql . Rows { }
2025-02-12 08:46:10 +00:00
c . EXPECT ( ) . QueryForRows ( context . Background ( ) , store . getStmt , testObject . Id ) . Return ( r , nil )
2025-01-17 14:34:48 +00:00
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" }
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Replace with no DB client errors and some items" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
stmt := NewMockStmt ( gomock . NewController ( t ) )
2025-06-03 21:32:43 +00:00
txC . EXPECT ( ) . Stmt ( store . deleteAllStmt ) . Return ( stmt )
stmt . EXPECT ( ) . Exec ( )
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , testObject . Id , testObject , store . shouldEncrypt )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Replace ( [ ] any { testObject } , testObject . Id )
assert . Nil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Replace with no DB client errors and no items" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-06-03 21:32:43 +00:00
stmt := NewMockStmt ( gomock . NewController ( t ) )
txC . EXPECT ( ) . Stmt ( store . deleteAllStmt ) . Return ( stmt )
stmt . EXPECT ( ) . Exec ( )
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , testObject . Id , testObject , store . shouldEncrypt )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Replace ( [ ] any { testObject } , testObject . Id )
assert . Nil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Replace with DB client WithTransaction returning error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , _ := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
err := store . Replace ( [ ] any { testObject } , testObject . Id )
assert . NotNil ( t , err )
} ,
} )
2025-06-03 21:32:43 +00:00
tests = append ( tests , testCase { description : "Replace with DB client deleteAllStmt error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-02-05 09:05:52 +00:00
2025-06-03 21:32:43 +00:00
deleteAllStmt := NewMockStmt ( gomock . NewController ( t ) )
2025-02-05 09:05:52 +00:00
2025-06-03 21:32:43 +00:00
txC . EXPECT ( ) . Stmt ( store . deleteAllStmt ) . Return ( deleteAllStmt )
deleteAllStmt . EXPECT ( ) . Exec ( ) . Return ( nil , fmt . Errorf ( "error" ) )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
err := store . Replace ( [ ] any { testObject } , testObject . Id )
assert . NotNil ( t , err )
} ,
} )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "Replace with DB client Upsert() error" , test : func ( t * testing . T , shouldEncrypt bool ) {
2025-01-17 14:34:48 +00:00
c , txC := SetupMockDB ( t )
store := SetupStore ( t , c , shouldEncrypt )
2025-06-03 21:32:43 +00:00
deleteAllStmt := NewMockStmt ( gomock . NewController ( t ) )
txC . EXPECT ( ) . Stmt ( store . deleteAllStmt ) . Return ( deleteAllStmt )
deleteAllStmt . EXPECT ( ) . Exec ( )
2025-01-17 14:34:48 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , testObject . Id , testObject , store . shouldEncrypt ) . Return ( fmt . Errorf ( "error" ) )
2025-02-05 09:05:52 +00:00
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err == nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
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 ) } )
}
}
2025-06-25 23:10:48 +00:00
type StringMatcher struct {
expected string
}
var ptn = regexp . MustCompile ( ` \s\s+ ` )
func dropWhiteSpace ( s string ) string {
s1 := strings . TrimSpace ( s )
s2 := strings . ReplaceAll ( s1 , "\n" , " " )
s3 := strings . ReplaceAll ( s2 , "\r" , " " )
return ptn . ReplaceAllString ( s3 , " " )
}
func ( m StringMatcher ) Matches ( x any ) bool {
s , ok := x . ( string )
if ! ok {
return false
}
return dropWhiteSpace ( s ) == m . expected
}
func ( m StringMatcher ) String ( ) string {
return m . expected
}
func WSIgnoringMatcher ( expected string ) gomock . Matcher {
return StringMatcher {
expected : dropWhiteSpace ( expected ) ,
}
}
2025-07-03 21:35:09 +00:00
func TestAddWithOneUpdate ( t * testing . T ) {
type testCase struct {
description string
updateExternal bool
updateSelf bool
}
testObject := testStoreObject { Id : "testStoreObject" , Val : "a" }
var tests [ ] testCase
tests = append ( tests ,
testCase { description : "Add external update" ,
updateExternal : true ,
updateSelf : false ,
} )
tests = append ( tests ,
testCase { description : "Add self update" ,
updateExternal : false ,
updateSelf : true ,
} )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) {
c , txC := SetupMockDB ( t )
stmts := NewMockStmt ( gomock . NewController ( t ) )
store := SetupStoreWithExternalDependencies ( t , c , test . updateExternal , test . updateSelf )
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "testStoreObject" , testObject , store . shouldEncrypt ) . Return ( nil )
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} ) . Times ( 2 )
rawStmt := ` SELECT DISTINCT f . key , ex2 . "spec.displayName" FROM "_v1_Namespace_fields" f
LEFT OUTER JOIN "_v1_Namespace_labels" lt1 ON f . key = lt1 . key
JOIN "management.cattle.io_v3_Project_fields" ex2 ON lt1 . value = ex2 . "metadata.name"
WHERE lt1 . label = ? AND f . "spec.displayName" != ex2 . "spec.displayName" `
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt ) )
results1 := "field.cattle.io/projectId"
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , results1 )
c . EXPECT ( ) . ReadStrings2 ( gomock . Any ( ) ) . Return ( [ ] [ ] string { { "lego.cattle.io/fields1" , "moose1" } } , nil )
// Override check:
rawStmt2 := ` SELECT f."spec.displayName" FROM "_v1_Namespace_fields" f WHERE f.key = ? `
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt2 ) )
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) )
c . EXPECT ( ) . ReadStrings ( gomock . Any ( ) )
rawStmt2a := ` UPDATE "_v1_Namespace_fields" SET "spec.displayName" = ? WHERE key = ? `
c . EXPECT ( ) . Prepare ( rawStmt2a )
txC . EXPECT ( ) . Stmt ( gomock . Any ( ) ) . Return ( stmts )
stmts . EXPECT ( ) . Exec ( "moose1" , "lego.cattle.io/fields1" )
rawStmt3 := ` SELECT f . key , ex2 . "spec.projectName" FROM "_v1_Pods_fields" f
JOIN "provisioner.cattle.io_v3_Cluster_fields" ex2 ON f . "field.cattle.io/fixer" = ex2 . "metadata.name"
WHERE f . "spec.projectName" != ex2 . "spec.projectName" `
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt3 ) )
results2 := [ ] any { "lego.cattle.io/fields2" }
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , results2 )
c . EXPECT ( ) . ReadStrings2 ( gomock . Any ( ) ) . Return ( [ ] [ ] string { { "lego.cattle.io/fields2" , "moose2" } } , nil )
// Override check:
rawStmt2 = ` SELECT f."spec.projectName" FROM "_v1_Pods_fields" f WHERE f.key = ? `
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt2 ) )
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) )
c . EXPECT ( ) . ReadStrings ( gomock . Any ( ) )
rawStmt4 := ` UPDATE "_v1_Pods_fields" SET "spec.projectName" = ? WHERE key = ? `
c . EXPECT ( ) . Prepare ( rawStmt4 )
txC . EXPECT ( ) . Stmt ( gomock . Any ( ) ) . Return ( stmts )
stmts . EXPECT ( ) . Exec ( "moose2" , "lego.cattle.io/fields2" )
err := store . Add ( testObject )
assert . Nil ( t , err )
} )
}
}
func TestAddWithBothUpdates ( t * testing . T ) {
2025-06-25 23:10:48 +00:00
type testCase struct {
description string
test func ( t * testing . T )
}
testObject := testStoreObject { Id : "testStoreObject" , Val : "a" }
var tests [ ] testCase
2025-07-03 21:35:09 +00:00
tests = append ( tests , testCase { description : "Update both external and self" , test : func ( t * testing . T ) {
2025-06-25 23:10:48 +00:00
c , txC := SetupMockDB ( t )
stmts := NewMockStmt ( gomock . NewController ( t ) )
2025-07-03 21:35:09 +00:00
store := SetupStoreWithExternalDependencies ( t , c , true , true )
2025-06-25 23:10:48 +00:00
rawStmt := ` SELECT DISTINCT f . key , ex2 . "spec.displayName" FROM "_v1_Namespace_fields" f
LEFT OUTER JOIN "_v1_Namespace_labels" lt1 ON f . key = lt1 . key
JOIN "management.cattle.io_v3_Project_fields" ex2 ON lt1 . value = ex2 . "metadata.name"
WHERE lt1 . label = ? AND f . "spec.displayName" != ex2 . "spec.displayName" `
rawStmt3 := ` SELECT f . key , ex2 . "spec.projectName" FROM "_v1_Pods_fields" f
JOIN "provisioner.cattle.io_v3_Cluster_fields" ex2 ON f . "field.cattle.io/fixer" = ex2 . "metadata.name"
WHERE f . "spec.projectName" != ex2 . "spec.projectName" `
2025-07-03 21:35:09 +00:00
c . EXPECT ( ) . Upsert ( txC , store . upsertStmt , "testStoreObject" , testObject , store . shouldEncrypt ) . Return ( nil )
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
for _ = range 2 {
c . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt ) )
results1 := "field.cattle.io/projectId"
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , results1 )
c . EXPECT ( ) . ReadStrings2 ( gomock . Any ( ) ) . Return ( [ ] [ ] string { { "lego.cattle.io/fields1" , "moose1" } } , nil )
// Override check:
rawStmt2 := ` SELECT f."spec.displayName" FROM "_v1_Namespace_fields" f WHERE f.key = ? `
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt2 ) )
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) )
c . EXPECT ( ) . ReadStrings ( gomock . Any ( ) )
rawStmt2a := ` UPDATE "_v1_Namespace_fields" SET "spec.displayName" = ? WHERE key = ? `
c . EXPECT ( ) . Prepare ( rawStmt2a )
txC . EXPECT ( ) . Stmt ( gomock . Any ( ) ) . Return ( stmts )
stmts . EXPECT ( ) . Exec ( "moose1" , "lego.cattle.io/fields1" )
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt3 ) )
results2 := [ ] any { "field.cattle.io/fixer" }
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , results2 )
c . EXPECT ( ) . ReadStrings2 ( gomock . Any ( ) ) . Return ( [ ] [ ] string { { "lego.cattle.io/fields2" , "moose2" } } , nil )
// Override check:
rawStmt2 = ` SELECT f."spec.projectName" FROM "_v1_Pods_fields" f WHERE f.key = ? `
c . EXPECT ( ) . Prepare ( WSIgnoringMatcher ( rawStmt2 ) )
c . EXPECT ( ) . QueryForRows ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) )
c . EXPECT ( ) . ReadStrings ( gomock . Any ( ) )
rawStmt4 := ` UPDATE "_v1_Pods_fields" SET "spec.projectName" = ? WHERE key = ? `
c . EXPECT ( ) . Prepare ( rawStmt4 )
txC . EXPECT ( ) . Stmt ( gomock . Any ( ) ) . Return ( stmts )
stmts . EXPECT ( ) . Exec ( "moose2" , "lego.cattle.io/fields2" )
// And again for the other object
}
2025-06-25 23:10:48 +00:00
err := store . Add ( testObject )
assert . Nil ( t , err )
} ,
} )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) {
test . test ( t )
} )
}
}
2025-02-05 09:05:52 +00:00
func SetupMockDB ( t * testing . T ) ( * MockClient , * MockTXClient ) {
dbC := NewMockClient ( gomock . NewController ( t ) ) // add functionality once store expectation are known
2025-01-17 14:34:48 +00:00
txC := NewMockTXClient ( gomock . NewController ( t ) )
2025-02-05 09:05:52 +00:00
txC . EXPECT ( ) . Exec ( fmt . Sprintf ( createTableFmt , "testStoreObject" ) ) . Return ( nil , nil )
dbC . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( txC )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
// use stmt mock here
dbC . EXPECT ( ) . Prepare ( fmt . Sprintf ( upsertStmtFmt , "testStoreObject" ) ) . Return ( & sql . Stmt { } )
dbC . EXPECT ( ) . Prepare ( fmt . Sprintf ( deleteStmtFmt , "testStoreObject" ) ) . Return ( & sql . Stmt { } )
2025-06-03 21:32:43 +00:00
dbC . EXPECT ( ) . Prepare ( fmt . Sprintf ( deleteAllStmtFmt , "testStoreObject" ) ) . Return ( & sql . Stmt { } )
2025-01-17 14:34:48 +00:00
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
}
2025-02-05 09:05:52 +00:00
func SetupStore ( t * testing . T , client * MockClient , shouldEncrypt bool ) * Store {
2025-06-25 23:10:48 +00:00
name := "testStoreObject"
gvk := schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : name }
2025-07-03 21:35:09 +00:00
store , err := NewStore ( context . Background ( ) , testStoreObject { } , testStoreKeyFunc , client , shouldEncrypt , gvk , name , nil , nil )
2025-06-25 23:10:48 +00:00
if err != nil {
t . Error ( err )
}
return store
}
func gvkKey ( group , version , kind string ) string {
return group + "_" + version + "_" + kind
}
2025-07-03 21:35:09 +00:00
func SetupStoreWithExternalDependencies ( t * testing . T , client * MockClient , updateExternal bool , updateSelf bool ) * Store {
2025-06-25 23:10:48 +00:00
name := "testStoreObject"
gvk := schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : name }
namespaceProjectLabelDep := sqltypes . ExternalLabelDependency {
SourceGVK : gvkKey ( "" , "v1" , "Namespace" ) ,
SourceLabelName : "field.cattle.io/projectId" ,
TargetGVK : gvkKey ( "management.cattle.io" , "v3" , "Project" ) ,
TargetKeyFieldName : "metadata.name" ,
TargetFinalFieldName : "spec.displayName" ,
}
namespaceNonLabelDep := sqltypes . ExternalDependency {
SourceGVK : gvkKey ( "" , "v1" , "Pods" ) ,
SourceFieldName : "field.cattle.io/fixer" ,
TargetGVK : gvkKey ( "provisioner.cattle.io" , "v3" , "Cluster" ) ,
TargetKeyFieldName : "metadata.name" ,
TargetFinalFieldName : "spec.projectName" ,
}
updateInfo := sqltypes . ExternalGVKUpdates {
AffectedGVK : schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : "Pod" } ,
ExternalDependencies : [ ] sqltypes . ExternalDependency { namespaceNonLabelDep } ,
ExternalLabelDependencies : [ ] sqltypes . ExternalLabelDependency { namespaceProjectLabelDep } ,
}
2025-07-03 21:35:09 +00:00
externalUpdateInfo := & updateInfo
selfUpdateInfo := & updateInfo
if ! updateExternal {
externalUpdateInfo = nil
}
if ! updateSelf {
selfUpdateInfo = nil
}
store , err := NewStore ( context . Background ( ) , testStoreObject { } , testStoreKeyFunc , client , false , gvk , name , externalUpdateInfo , selfUpdateInfo )
2025-01-17 14:34:48 +00:00
if err != nil {
t . Error ( err )
}
return store
}