github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/testdb/generic_repo_exist_tests.go (about)

     1  package testdb
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    10  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    11  	"github.com/pkg/errors"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  // RepoExistTestSuite represents a generic test suite for repository Exists method of any entity that has externally managed tenants in m2m table/view.
    16  // This test suite is not suitable for global entities or entities with embedded tenant in them.
    17  type RepoExistTestSuite struct {
    18  	Name                  string
    19  	SQLQueryDetails       []SQLQueryDetails
    20  	ConverterMockProvider func() Mock
    21  	RepoConstructorFunc   interface{}
    22  	TargetID              string
    23  	TenantID              string
    24  	RefEntity             interface{}
    25  	IsGlobal              bool
    26  	MethodName            string
    27  	MethodArgs            []interface{}
    28  }
    29  
    30  // Run runs the generic repo exists test suite
    31  func (suite *RepoExistTestSuite) Run(t *testing.T) bool {
    32  	for _, queryDetails := range suite.SQLQueryDetails {
    33  		if !queryDetails.IsSelect {
    34  			panic("exist suite should expect only select SQL statements")
    35  		}
    36  	}
    37  
    38  	return t.Run(suite.Name, func(t *testing.T) {
    39  		testErr := errors.New("test error")
    40  
    41  		t.Run("success", func(t *testing.T) {
    42  			sqlxDB, sqlMock := MockDatabase(t)
    43  			ctx := persistence.SaveToContext(context.TODO(), sqlxDB)
    44  
    45  			configureValidSQLQueries(sqlMock, suite.SQLQueryDetails)
    46  
    47  			convMock := suite.ConverterMockProvider()
    48  			pgRepository := createRepo(suite.RepoConstructorFunc, convMock)
    49  			// WHEN
    50  			found, err := callExists(pgRepository, ctx, suite.MethodName, suite.MethodArgs)
    51  			// THEN
    52  			require.NoError(t, err)
    53  			require.True(t, found)
    54  
    55  			sqlMock.AssertExpectations(t)
    56  			convMock.AssertExpectations(t)
    57  		})
    58  
    59  		t.Run("returns false if entity does not exist", func(t *testing.T) {
    60  			sqlxDB, sqlMock := MockDatabase(t)
    61  			ctx := persistence.SaveToContext(context.TODO(), sqlxDB)
    62  
    63  			configureInvalidSelect(sqlMock, suite.SQLQueryDetails)
    64  
    65  			convMock := suite.ConverterMockProvider()
    66  			pgRepository := createRepo(suite.RepoConstructorFunc, convMock)
    67  			// WHEN
    68  			found, err := callExists(pgRepository, ctx, suite.MethodName, suite.MethodArgs)
    69  			// THEN
    70  			require.NoError(t, err)
    71  			require.False(t, found)
    72  
    73  			sqlMock.AssertExpectations(t)
    74  			convMock.AssertExpectations(t)
    75  		})
    76  
    77  		for i := range suite.SQLQueryDetails {
    78  			t.Run(fmt.Sprintf("error if SQL query %d fail", i), func(t *testing.T) {
    79  				sqlxDB, sqlMock := MockDatabase(t)
    80  				ctx := persistence.SaveToContext(context.TODO(), sqlxDB)
    81  
    82  				configureFailureForSQLQueryOnIndex(sqlMock, suite.SQLQueryDetails, i, testErr)
    83  
    84  				convMock := suite.ConverterMockProvider()
    85  				pgRepository := createRepo(suite.RepoConstructorFunc, convMock)
    86  				// WHEN
    87  				found, err := callExists(pgRepository, ctx, suite.MethodName, suite.MethodArgs)
    88  				// THEN
    89  				require.Error(t, err)
    90  				require.Equal(t, apperrors.InternalError, apperrors.ErrorCode(err))
    91  				require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query")
    92  
    93  				require.False(t, found)
    94  
    95  				sqlMock.AssertExpectations(t)
    96  				convMock.AssertExpectations(t)
    97  			})
    98  		}
    99  	})
   100  }
   101  
   102  func callExists(repo interface{}, ctx context.Context, methodName string, args []interface{}) (bool, error) {
   103  	argsVals := make([]reflect.Value, 1, len(args))
   104  	argsVals[0] = reflect.ValueOf(ctx)
   105  	for _, arg := range args {
   106  		argsVals = append(argsVals, reflect.ValueOf(arg))
   107  	}
   108  
   109  	results := reflect.ValueOf(repo).MethodByName(methodName).Call(argsVals)
   110  	if len(results) != 2 {
   111  		panic("Exists should return two arguments")
   112  	}
   113  
   114  	found := results[0].Bool()
   115  	errResult := results[1].Interface()
   116  	if errResult == nil {
   117  		return found, nil
   118  	}
   119  	err, ok := errResult.(error)
   120  	if !ok {
   121  		panic("Expected result to be an error")
   122  	}
   123  	return found, err
   124  }