2025-01-17 14:34:48 +00:00
/ *
Copyright 2023 SUSE LLC
Adapted from client - go , Copyright 2014 The Kubernetes Authors .
* /
package informer
import (
"context"
"database/sql"
"fmt"
"reflect"
"testing"
2025-02-05 09:05:52 +00:00
"github.com/rancher/steve/pkg/sqlcache/db"
2025-01-17 14:34:48 +00:00
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"k8s.io/client-go/tools/cache"
)
//go:generate mockgen --build_flags=--mod=mod -package informer -destination ./sql_mocks_test.go github.com/rancher/steve/pkg/sqlcache/informer Store
2025-02-05 09:05:52 +00:00
//go:generate mockgen --build_flags=--mod=mod -package informer -destination ./db_mocks_test.go github.com/rancher/steve/pkg/sqlcache/db Rows,Client
//go:generate mockgen --build_flags=--mod=mod -package informer -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
type testStoreObject struct {
Id string
Val string
}
func TestNewIndexer ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "NewIndexer() with no errors returned from Store or Client, should return no error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
objKey := "objKey"
indexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
storeName := "someStoreName"
2025-02-05 09:05:52 +00:00
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetName ( ) . AnyTimes ( ) . Return ( storeName )
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createTableFmt , storeName , storeName ) ) . Return ( nil , nil )
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createIndexFmt , storeName , storeName ) ) . Return ( nil , nil )
store . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( nil ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( client )
if err != nil {
t . Fail ( )
}
} )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . RegisterAfterUpsert ( gomock . Any ( ) )
store . EXPECT ( ) . Prepare ( fmt . Sprintf ( deleteIndicesFmt , storeName ) )
store . EXPECT ( ) . Prepare ( fmt . Sprintf ( addIndexFmt , storeName ) )
store . EXPECT ( ) . Prepare ( fmt . Sprintf ( listByIndexFmt , storeName , storeName ) )
store . EXPECT ( ) . Prepare ( fmt . Sprintf ( listKeyByIndexFmt , storeName ) )
store . EXPECT ( ) . Prepare ( fmt . Sprintf ( listIndexValuesFmt , storeName ) )
2025-02-12 08:46:10 +00:00
indexer , err := NewIndexer ( context . Background ( ) , indexers , store )
2025-01-17 14:34:48 +00:00
assert . Nil ( t , err )
assert . Equal ( t , cache . Indexers ( indexers ) , indexer . indexers )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "NewIndexer() with WithTransaction() error, should return error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
objKey := "objKey"
indexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
2025-02-05 09:05:52 +00:00
store . EXPECT ( ) . GetName ( ) . AnyTimes ( ) . Return ( "someStoreName" )
store . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) )
2025-02-12 08:46:10 +00:00
_ , err := NewIndexer ( context . Background ( ) , indexers , store )
2025-01-17 14:34:48 +00:00
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "NewIndexer() with Client Exec() error on first call to Exec(), should return error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
objKey := "objKey"
indexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
storeName := "someStoreName"
store . EXPECT ( ) . GetName ( ) . AnyTimes ( ) . Return ( storeName )
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createTableFmt , storeName , storeName ) ) . Return ( nil , fmt . Errorf ( "error" ) )
store . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( client )
if err == nil {
t . Fail ( )
}
} )
2025-02-12 08:46:10 +00:00
_ , err := NewIndexer ( context . Background ( ) , indexers , store )
2025-01-17 14:34:48 +00:00
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "NewIndexer() with Client Exec() error on second call to Exec(), should return error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
objKey := "objKey"
indexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
storeName := "someStoreName"
store . EXPECT ( ) . GetName ( ) . AnyTimes ( ) . Return ( storeName )
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createTableFmt , storeName , storeName ) ) . Return ( nil , nil )
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createIndexFmt , storeName , storeName ) ) . Return ( nil , fmt . Errorf ( "error" ) )
store . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( client )
if err == nil {
t . Fail ( )
}
} )
2025-02-12 08:46:10 +00:00
_ , err := NewIndexer ( context . Background ( ) , indexers , store )
2025-01-17 14:34:48 +00:00
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "NewIndexer() with Client Commit() error, should return error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
objKey := "objKey"
indexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
storeName := "someStoreName"
store . EXPECT ( ) . GetName ( ) . AnyTimes ( ) . Return ( storeName )
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createTableFmt , storeName , storeName ) ) . Return ( nil , nil )
client . EXPECT ( ) . Exec ( fmt . Sprintf ( createIndexFmt , storeName , storeName ) ) . Return ( nil , nil )
store . EXPECT ( ) . WithTransaction ( gomock . Any ( ) , true , gomock . Any ( ) ) . Return ( fmt . Errorf ( "error" ) ) . Do (
func ( ctx context . Context , shouldEncrypt bool , f db . WithTransactionFunction ) {
err := f ( client )
if err != nil {
t . Fail ( )
}
} )
2025-02-12 08:46:10 +00:00
_ , err := NewIndexer ( context . Background ( ) , indexers , store )
2025-01-17 14:34:48 +00:00
assert . NotNil ( t , err )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}
func TestAfterUpsert ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "AfterUpsert() with no errors returned from Client should return no error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
objKey := "key"
2025-02-05 09:05:52 +00:00
deleteIndicesStmt := NewMockStmt ( gomock . NewController ( t ) )
addIndexStmt := NewMockStmt ( gomock . NewController ( t ) )
2025-01-17 14:34:48 +00:00
indexer := & Indexer {
2025-03-04 17:30:14 +00:00
ctx : context . Background ( ) ,
2025-02-05 09:05:52 +00:00
Store : store ,
2025-01-17 14:34:48 +00:00
indexers : map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
key := "somekey"
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Stmt ( indexer . deleteIndicesStmt ) . Return ( deleteIndicesStmt )
deleteIndicesStmt . EXPECT ( ) . Exec ( key ) . Return ( nil , nil )
client . EXPECT ( ) . Stmt ( indexer . addIndexStmt ) . Return ( addIndexStmt )
addIndexStmt . EXPECT ( ) . Exec ( "a" , objKey , key ) . Return ( nil , nil )
2025-01-17 14:34:48 +00:00
testObject := testStoreObject { Id : "something" , Val : "a" }
err := indexer . AfterUpsert ( key , testObject , client )
assert . Nil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "AfterUpsert() with error returned from Client StmtExec() should return an error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
objKey := "key"
2025-02-05 09:05:52 +00:00
deleteIndicesStmt := NewMockStmt ( gomock . NewController ( t ) )
2025-01-17 14:34:48 +00:00
indexer := & Indexer {
2025-03-04 17:30:14 +00:00
ctx : context . Background ( ) ,
2025-02-05 09:05:52 +00:00
Store : store ,
2025-01-17 14:34:48 +00:00
indexers : map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
key := "somekey"
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Stmt ( indexer . deleteIndicesStmt ) . Return ( deleteIndicesStmt )
deleteIndicesStmt . EXPECT ( ) . Exec ( key ) . Return ( nil , fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
testObject := testStoreObject { Id : "something" , Val : "a" }
err := indexer . AfterUpsert ( key , testObject , client )
assert . NotNil ( t , err )
} } )
2025-02-05 09:05:52 +00:00
tests = append ( tests , testCase { description : "AfterUpsert() with error returned from Client second StmtExec() call should return an error" , test : func ( t * testing . T ) {
2025-01-17 14:34:48 +00:00
store := NewMockStore ( gomock . NewController ( t ) )
client := NewMockTXClient ( gomock . NewController ( t ) )
2025-02-05 09:05:52 +00:00
deleteIndicesStmt := NewMockStmt ( gomock . NewController ( t ) )
addIndexStmt := NewMockStmt ( gomock . NewController ( t ) )
2025-01-17 14:34:48 +00:00
objKey := "key"
indexer := & Indexer {
2025-03-04 17:30:14 +00:00
ctx : context . Background ( ) ,
2025-02-05 09:05:52 +00:00
Store : store ,
2025-01-17 14:34:48 +00:00
indexers : map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
key := "somekey"
2025-02-05 09:05:52 +00:00
client . EXPECT ( ) . Stmt ( indexer . deleteIndicesStmt ) . Return ( deleteIndicesStmt )
deleteIndicesStmt . EXPECT ( ) . Exec ( key ) . Return ( nil , nil )
client . EXPECT ( ) . Stmt ( indexer . addIndexStmt ) . Return ( addIndexStmt )
addIndexStmt . EXPECT ( ) . Exec ( "a" , objKey , key ) . Return ( nil , fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
testObject := testStoreObject { Id : "something" , Val : "a" }
err := indexer . AfterUpsert ( key , testObject , client )
assert . NotNil ( t , err )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}
func TestIndex ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
tests = append ( tests , testCase { description : "Index() with no errors returned from store and 1 object returned by ReadObjects(), should return one obj and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject } , nil )
objs , err := indexer . Index ( indexName , testObject )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { testObject } , objs )
} } )
tests = append ( tests , testCase { description : "Index() with no errors returned from store and multiple objects returned by ReadObjects(), should return multiple objects and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject , testObject } , nil )
objs , err := indexer . Index ( indexName , testObject )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { testObject , testObject } , objs )
} } )
tests = append ( tests , testCase { description : "Index() with no errors returned from store and no objects returned by ReadObjects(), should return no objects and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { } , nil )
objs , err := indexer . Index ( indexName , testObject )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { } , objs )
} } )
tests = append ( tests , testCase { description : "Index() where index name is not in indexers, should return error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
_ , err := indexer . Index ( "someotherindexname" , testObject )
assert . NotNil ( t , err )
} } )
tests = append ( tests , testCase { description : "Index() with an error returned from store QueryForRows, should return an error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( nil , fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
_ , err := indexer . Index ( indexName , testObject )
assert . NotNil ( t , err )
} } )
tests = append ( tests , testCase { description : "Index() with an errors returned from store ReadObjects(), should return an error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject } , fmt . Errorf ( "error" ) )
_ , err := indexer . Index ( indexName , testObject )
assert . NotNil ( t , err )
} } )
tests = append ( tests , testCase { description : "Index() with no errors returned from store and multiple keys returned from index func, should return one obj and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
indexers : map [ string ] cache . IndexFunc {
indexName : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey , objKey + "2" } , nil
} ,
} ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
store . EXPECT ( ) . GetName ( ) . Return ( "name" )
stmt := & sql . Stmt { }
store . EXPECT ( ) . Prepare ( fmt . Sprintf ( selectQueryFmt , "name" , ", ?" ) ) . Return ( stmt )
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey , objKey + "2" ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject } , nil )
store . EXPECT ( ) . CloseStmt ( stmt ) . Return ( nil )
objs , err := indexer . Index ( indexName , testObject )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { testObject } , objs )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}
func TestByIndex ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
tests = append ( tests , testCase { description : "IndexBy() with no errors returned from store and 1 object returned by ReadObjects(), should return one obj and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject } , nil )
objs , err := indexer . ByIndex ( indexName , objKey )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { testObject } , objs )
} } )
tests = append ( tests , testCase { description : "IndexBy() with no errors returned from store and multiple objects returned by ReadObjects(), should return multiple objects and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject , testObject } , nil )
objs , err := indexer . ByIndex ( indexName , objKey )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { testObject , testObject } , objs )
} } )
tests = append ( tests , testCase { description : "IndexBy() with no errors returned from store and no objects returned by ReadObjects(), should return no objects and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { } , nil )
objs , err := indexer . ByIndex ( indexName , objKey )
assert . Nil ( t , err )
assert . Equal ( t , [ ] any { } , objs )
} } )
tests = append ( tests , testCase { description : "IndexBy() with an error returned from store QueryForRows, should return an error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( nil , fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
_ , err := indexer . ByIndex ( indexName , objKey )
assert . NotNil ( t , err )
} } )
tests = append ( tests , testCase { description : "IndexBy() with an errors returned from store ReadObjects(), should return an error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
objKey := "key"
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
testObject := testStoreObject { Id : "something" , Val : "a" }
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listByIndexStmt , indexName , objKey ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . GetType ( ) . Return ( reflect . TypeOf ( testObject ) )
store . EXPECT ( ) . GetShouldEncrypt ( ) . Return ( false )
store . EXPECT ( ) . ReadObjects ( rows , reflect . TypeOf ( testObject ) , false ) . Return ( [ ] any { testObject } , fmt . Errorf ( "error" ) )
_ , err := indexer . ByIndex ( indexName , objKey )
assert . NotNil ( t , err )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}
func TestListIndexFuncValues ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
tests = append ( tests , testCase { description : "ListIndexFuncvalues() with no errors returned from store and 1 object returned by ReadObjects(), should return one obj and no error" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listIndexValuesStmt , indexName ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . ReadStrings ( rows ) . Return ( [ ] string { "somestrings" } , nil )
vals := indexer . ListIndexFuncValues ( indexName )
assert . Equal ( t , [ ] string { "somestrings" } , vals )
} } )
tests = append ( tests , testCase { description : "ListIndexFuncvalues() with QueryForRows() error returned from store, should panic" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
listStmt := & sql . Stmt { }
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listIndexValuesStmt , indexName ) . Return ( nil , fmt . Errorf ( "error" ) )
2025-01-17 14:34:48 +00:00
assert . Panics ( t , func ( ) { indexer . ListIndexFuncValues ( indexName ) } )
} } )
tests = append ( tests , testCase { description : "ListIndexFuncvalues() with ReadStrings() error returned from store, should panic" , test : func ( t * testing . T ) {
store := NewMockStore ( gomock . NewController ( t ) )
rows := & sql . Rows { }
listStmt := & sql . Stmt { }
indexName := "someindexname"
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
Store : store ,
listByIndexStmt : listStmt ,
}
2025-02-12 08:46:10 +00:00
store . EXPECT ( ) . QueryForRows ( context . Background ( ) , indexer . listIndexValuesStmt , indexName ) . Return ( rows , nil )
2025-01-17 14:34:48 +00:00
store . EXPECT ( ) . ReadStrings ( rows ) . Return ( [ ] string { "somestrings" } , fmt . Errorf ( "error" ) )
assert . Panics ( t , func ( ) { indexer . ListIndexFuncValues ( indexName ) } )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}
func TestGetIndexers ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
tests = append ( tests , testCase { description : "GetIndexers() should return indexers fron indexers field" , test : func ( t * testing . T ) {
objKey := "key"
expectedIndexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
indexer := & Indexer {
2025-02-12 08:46:10 +00:00
ctx : context . Background ( ) ,
2025-01-17 14:34:48 +00:00
indexers : expectedIndexers ,
}
indexers := indexer . GetIndexers ( )
assert . Equal ( t , cache . Indexers ( expectedIndexers ) , indexers )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}
func TestAddIndexers ( t * testing . T ) {
type testCase struct {
description string
test func ( t * testing . T )
}
var tests [ ] testCase
tests = append ( tests , testCase { description : "GetIndexers() should return indexers fron indexers field" , test : func ( t * testing . T ) {
objKey := "key"
expectedIndexers := map [ string ] cache . IndexFunc {
"a" : func ( obj interface { } ) ( [ ] string , error ) {
return [ ] string { objKey } , nil
} ,
}
indexer := & Indexer { }
err := indexer . AddIndexers ( expectedIndexers )
assert . Nil ( t , err )
assert . ObjectsAreEqual ( cache . Indexers ( expectedIndexers ) , indexer . indexers )
} } )
t . Parallel ( )
for _ , test := range tests {
t . Run ( test . description , func ( t * testing . T ) { test . test ( t ) } )
}
}