github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/application/repository_test.go (about)

     1  package application_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"database/sql/driver"
     7  	"errors"
     8  	"fmt"
     9  	"regexp"
    10  	"strconv"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/google/uuid"
    15  	"github.com/kyma-incubator/compass/components/director/internal/labelfilter"
    16  	"github.com/kyma-incubator/compass/components/director/pkg/pagination"
    17  
    18  	"github.com/DATA-DOG/go-sqlmock"
    19  	"github.com/kyma-incubator/compass/components/director/internal/domain/application"
    20  	"github.com/kyma-incubator/compass/components/director/internal/domain/application/automock"
    21  	"github.com/kyma-incubator/compass/components/director/internal/model"
    22  	"github.com/kyma-incubator/compass/components/director/internal/repo"
    23  	"github.com/kyma-incubator/compass/components/director/internal/repo/testdb"
    24  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    25  	"github.com/kyma-incubator/compass/components/director/pkg/operation"
    26  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    27  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  func TestRepository_Exists(t *testing.T) {
    33  	suite := testdb.RepoExistTestSuite{
    34  		Name: "Application Exists",
    35  		SQLQueryDetails: []testdb.SQLQueryDetails{
    36  			{
    37  				Query:    regexp.QuoteMeta(`SELECT 1 FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`),
    38  				Args:     []driver.Value{givenID(), givenTenant()},
    39  				IsSelect: true,
    40  				ValidRowsProvider: func() []*sqlmock.Rows {
    41  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
    42  				},
    43  				InvalidRowsProvider: func() []*sqlmock.Rows {
    44  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
    45  				},
    46  			},
    47  		},
    48  		ConverterMockProvider: func() testdb.Mock {
    49  			return &automock.EntityConverter{}
    50  		},
    51  		RepoConstructorFunc: application.NewRepository,
    52  		TargetID:            givenID(),
    53  		TenantID:            givenTenant(),
    54  		MethodName:          "Exists",
    55  		MethodArgs:          []interface{}{givenTenant(), givenID()},
    56  	}
    57  
    58  	suite.Run(t)
    59  }
    60  
    61  func TestRepository_OwnerExists(t *testing.T) {
    62  	suite := testdb.RepoExistTestSuite{
    63  		Name: "Application Exists",
    64  		SQLQueryDetails: []testdb.SQLQueryDetails{
    65  			{
    66  				Query:    regexp.QuoteMeta(`SELECT 1 FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2 AND owner = true))`),
    67  				Args:     []driver.Value{givenID(), givenTenant()},
    68  				IsSelect: true,
    69  				ValidRowsProvider: func() []*sqlmock.Rows {
    70  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
    71  				},
    72  				InvalidRowsProvider: func() []*sqlmock.Rows {
    73  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
    74  				},
    75  			},
    76  		},
    77  		ConverterMockProvider: func() testdb.Mock {
    78  			return &automock.EntityConverter{}
    79  		},
    80  		RepoConstructorFunc: application.NewRepository,
    81  		TargetID:            givenID(),
    82  		TenantID:            givenTenant(),
    83  		MethodName:          "OwnerExists",
    84  		MethodArgs:          []interface{}{givenTenant(), givenID()},
    85  	}
    86  
    87  	suite.Run(t)
    88  }
    89  
    90  func TestRepository_Delete(t *testing.T) {
    91  	suite := testdb.RepoDeleteTestSuite{
    92  		Name: "Application Delete",
    93  		SQLQueryDetails: []testdb.SQLQueryDetails{
    94  			{
    95  				Query:         regexp.QuoteMeta(`DELETE FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2 AND owner = true))`),
    96  				Args:          []driver.Value{givenID(), givenTenant()},
    97  				ValidResult:   sqlmock.NewResult(-1, 1),
    98  				InvalidResult: sqlmock.NewResult(-1, 2),
    99  			},
   100  		},
   101  		ConverterMockProvider: func() testdb.Mock {
   102  			return &automock.EntityConverter{}
   103  		},
   104  		RepoConstructorFunc: application.NewRepository,
   105  		MethodArgs:          []interface{}{givenTenant(), givenID()},
   106  	}
   107  
   108  	suite.Run(t)
   109  
   110  	// Additional tests - async deletion
   111  	t.Run("Success when operation mode is set to async explicitly and operation is in the context", func(t *testing.T) {
   112  		ctx := context.Background()
   113  		ctx = operation.SaveModeToContext(ctx, graphql.OperationModeAsync)
   114  
   115  		op := &operation.Operation{
   116  			OperationType:     operation.OperationTypeDelete,
   117  			OperationCategory: "unregisterApplication",
   118  		}
   119  		ctx = operation.SaveToContext(ctx, &[]*operation.Operation{op})
   120  
   121  		deletedAt := time.Now()
   122  
   123  		appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   124  		appModel.DeletedAt = &deletedAt
   125  		entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   126  
   127  		db, dbMock := testdb.MockDatabase(t)
   128  		defer dbMock.AssertExpectations(t)
   129  
   130  		rows := sqlmock.NewRows(fixAppColumns()).
   131  			AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID)
   132  
   133  		dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`)).
   134  			WithArgs(givenID(), givenTenant()).
   135  			WillReturnRows(rows)
   136  
   137  		mockConverter := &automock.EntityConverter{}
   138  		mockConverter.On("FromEntity", entity).Return(appModel).Once()
   139  
   140  		appEntityWithDeletedTimestamp := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   141  		appEntityWithDeletedTimestamp.Ready = false
   142  		appEntityWithDeletedTimestamp.DeletedAt = &deletedAt
   143  		mockConverter.On("ToEntity", appModel).Return(appEntityWithDeletedTimestamp, nil).Once()
   144  		defer mockConverter.AssertExpectations(t)
   145  
   146  		updateStmt := regexp.QuoteMeta(`UPDATE public.applications SET name = ?, description = ?, status_condition = ?, status_timestamp = ?, system_status = ?, healthcheck_url = ?, integration_system_id = ?, provider_name = ?, base_url = ?, application_namespace = ?, labels = ?, ready = ?, created_at = ?, updated_at = ?, deleted_at = ?, error = ?, correlation_ids = ?, tags = ?, documentation_labels = ?, system_number = ?, local_tenant_id = ? WHERE id = ? AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = ? AND owner = true))`)
   147  
   148  		dbMock.ExpectExec(updateStmt).
   149  			WithArgs(appEntityWithDeletedTimestamp.Name, appEntityWithDeletedTimestamp.Description, appEntityWithDeletedTimestamp.StatusCondition, appEntityWithDeletedTimestamp.StatusTimestamp, appEntityWithDeletedTimestamp.SystemStatus, appEntityWithDeletedTimestamp.HealthCheckURL, appEntityWithDeletedTimestamp.IntegrationSystemID, appEntityWithDeletedTimestamp.ProviderName, appEntityWithDeletedTimestamp.BaseURL, appEntityWithDeletedTimestamp.ApplicationNamespace, appEntityWithDeletedTimestamp.OrdLabels, appEntityWithDeletedTimestamp.Ready, appEntityWithDeletedTimestamp.CreatedAt, appEntityWithDeletedTimestamp.UpdatedAt, appEntityWithDeletedTimestamp.DeletedAt, appEntityWithDeletedTimestamp.Error, appEntityWithDeletedTimestamp.CorrelationIDs, appEntityWithDeletedTimestamp.Tags, appEntityWithDeletedTimestamp.DocumentationLabels, appEntityWithDeletedTimestamp.SystemNumber, appEntityWithDeletedTimestamp.LocalTenantID, givenID(), givenTenant()).
   150  			WillReturnResult(sqlmock.NewResult(-1, 1))
   151  
   152  		ctx = persistence.SaveToContext(ctx, db)
   153  
   154  		repo := application.NewRepository(mockConverter)
   155  
   156  		// WHEN
   157  		err := repo.Delete(ctx, givenTenant(), givenID())
   158  
   159  		// then
   160  		assert.NoError(t, err)
   161  		assert.Empty(t, appModel.Error)
   162  		assert.False(t, appModel.Ready)
   163  	})
   164  
   165  	t.Run("Success when operation mode is set to async explicitly and operation is in the context, and previous error exists", func(t *testing.T) {
   166  		ctx := context.Background()
   167  		ctx = operation.SaveModeToContext(ctx, graphql.OperationModeAsync)
   168  
   169  		op := &operation.Operation{
   170  			OperationType:     operation.OperationTypeDelete,
   171  			OperationCategory: "unregisterApplication",
   172  		}
   173  		ctx = operation.SaveToContext(ctx, &[]*operation.Operation{op})
   174  
   175  		deletedAt := time.Now()
   176  
   177  		appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   178  		appModel.DeletedAt = &deletedAt
   179  		appModel.Error = str.Ptr("error")
   180  		entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   181  
   182  		db, dbMock := testdb.MockDatabase(t)
   183  		defer dbMock.AssertExpectations(t)
   184  
   185  		rows := sqlmock.NewRows(fixAppColumns()).
   186  			AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID)
   187  		dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`)).
   188  			WithArgs(givenID(), givenTenant()).
   189  			WillReturnRows(rows)
   190  
   191  		mockConverter := &automock.EntityConverter{}
   192  		mockConverter.On("FromEntity", entity).Return(appModel).Once()
   193  
   194  		appEntityWithDeletedTimestamp := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   195  		appEntityWithDeletedTimestamp.Ready = false
   196  		appEntityWithDeletedTimestamp.DeletedAt = &deletedAt
   197  		mockConverter.On("ToEntity", appModel).Return(appEntityWithDeletedTimestamp, nil).Once()
   198  		defer mockConverter.AssertExpectations(t)
   199  
   200  		updateStmt := regexp.QuoteMeta(`UPDATE public.applications SET name = ?, description = ?, status_condition = ?, status_timestamp = ?, system_status = ?, healthcheck_url = ?, integration_system_id = ?, provider_name = ?, base_url = ?, application_namespace = ?, labels = ?, ready = ?, created_at = ?, updated_at = ?, deleted_at = ?, error = ?, correlation_ids = ?, tags = ?,  documentation_labels = ?, system_number = ?, local_tenant_id = ? WHERE id = ? AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = ? AND owner = true))`)
   201  
   202  		dbMock.ExpectExec(updateStmt).
   203  			WithArgs(appEntityWithDeletedTimestamp.Name, appEntityWithDeletedTimestamp.Description, appEntityWithDeletedTimestamp.StatusCondition, appEntityWithDeletedTimestamp.StatusTimestamp, appEntityWithDeletedTimestamp.SystemStatus, appEntityWithDeletedTimestamp.HealthCheckURL, appEntityWithDeletedTimestamp.IntegrationSystemID, appEntityWithDeletedTimestamp.ProviderName, appEntityWithDeletedTimestamp.BaseURL, appEntityWithDeletedTimestamp.ApplicationNamespace, appEntityWithDeletedTimestamp.OrdLabels, appEntityWithDeletedTimestamp.Ready, appEntityWithDeletedTimestamp.CreatedAt, appEntityWithDeletedTimestamp.UpdatedAt, appEntityWithDeletedTimestamp.DeletedAt, appEntityWithDeletedTimestamp.Error, appEntityWithDeletedTimestamp.CorrelationIDs, appEntityWithDeletedTimestamp.Tags, appEntityWithDeletedTimestamp.DocumentationLabels, appEntityWithDeletedTimestamp.SystemNumber, appEntityWithDeletedTimestamp.LocalTenantID, givenID(), givenTenant()).
   204  			WillReturnResult(sqlmock.NewResult(-1, 1))
   205  
   206  		ctx = persistence.SaveToContext(ctx, db)
   207  
   208  		repo := application.NewRepository(mockConverter)
   209  
   210  		// WHEN
   211  		err := repo.Delete(ctx, givenTenant(), givenID())
   212  		// then
   213  		assert.NoError(t, err)
   214  		assert.Empty(t, appModel.Error)
   215  		assert.False(t, appModel.Ready)
   216  	})
   217  
   218  	t.Run("Failure when operation mode is set to async, operation is in the context but fetch application fails", func(t *testing.T) {
   219  		ctx := context.Background()
   220  		ctx = operation.SaveModeToContext(ctx, graphql.OperationModeAsync)
   221  
   222  		op := &operation.Operation{
   223  			OperationType:     operation.OperationTypeDelete,
   224  			OperationCategory: "unregisterApplication",
   225  		}
   226  		ctx = operation.SaveToContext(ctx, &[]*operation.Operation{op})
   227  
   228  		db, dbMock := testdb.MockDatabase(t)
   229  		defer dbMock.AssertExpectations(t)
   230  
   231  		dbMock.ExpectQuery("SELECT .*").
   232  			WithArgs(givenID(), givenTenant()).WillReturnError(givenError())
   233  
   234  		ctx = persistence.SaveToContext(ctx, db)
   235  
   236  		repo := application.NewRepository(nil)
   237  
   238  		// WHEN
   239  		err := repo.Delete(ctx, givenTenant(), givenID())
   240  
   241  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   242  	})
   243  
   244  	t.Run("Failure when operation mode is set to async, operation is in the context but update application fails", func(t *testing.T) {
   245  		ctx := context.Background()
   246  		ctx = operation.SaveModeToContext(ctx, graphql.OperationModeAsync)
   247  
   248  		op := &operation.Operation{
   249  			OperationType:     operation.OperationTypeDelete,
   250  			OperationCategory: "unregisterApplication",
   251  		}
   252  		ctx = operation.SaveToContext(ctx, &[]*operation.Operation{op})
   253  
   254  		deletedAt := time.Now()
   255  
   256  		appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   257  		appModel.Ready = false
   258  		appModel.DeletedAt = &deletedAt
   259  		entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   260  
   261  		db, dbMock := testdb.MockDatabase(t)
   262  		defer dbMock.AssertExpectations(t)
   263  
   264  		rows := sqlmock.NewRows(fixAppColumns()).
   265  			AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID)
   266  
   267  		dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`)).
   268  			WithArgs(givenID(), givenTenant()).
   269  			WillReturnRows(rows)
   270  
   271  		mockConverter := &automock.EntityConverter{}
   272  		mockConverter.On("FromEntity", entity).Return(appModel, nil).Once()
   273  
   274  		appEntityWithDeletedTimestamp := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   275  		appEntityWithDeletedTimestamp.Ready = false
   276  		appEntityWithDeletedTimestamp.DeletedAt = &deletedAt
   277  		mockConverter.On("ToEntity", appModel).Return(appEntityWithDeletedTimestamp, nil).Once()
   278  		defer mockConverter.AssertExpectations(t)
   279  
   280  		updateStmt := regexp.QuoteMeta(`UPDATE public.applications SET name = ?, description = ?, status_condition = ?, status_timestamp = ?, system_status = ?, healthcheck_url = ?, integration_system_id = ?, provider_name = ?, base_url = ?, application_namespace = ?, labels = ?, ready = ?, created_at = ?, updated_at = ?, deleted_at = ?, error = ?, correlation_ids = ?, tags = ?, documentation_labels = ?, system_number = ?, local_tenant_id = ? WHERE id = ? AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = ? AND owner = true))`)
   281  
   282  		dbMock.ExpectExec(updateStmt).
   283  			WithArgs(appEntityWithDeletedTimestamp.Name, appEntityWithDeletedTimestamp.Description, appEntityWithDeletedTimestamp.StatusCondition, appEntityWithDeletedTimestamp.StatusTimestamp, appEntityWithDeletedTimestamp.SystemStatus, appEntityWithDeletedTimestamp.HealthCheckURL, appEntityWithDeletedTimestamp.IntegrationSystemID, appEntityWithDeletedTimestamp.ProviderName, appEntityWithDeletedTimestamp.BaseURL, appEntityWithDeletedTimestamp.ApplicationNamespace, appEntityWithDeletedTimestamp.OrdLabels, appEntityWithDeletedTimestamp.Ready, appEntityWithDeletedTimestamp.CreatedAt, appEntityWithDeletedTimestamp.UpdatedAt, appEntityWithDeletedTimestamp.DeletedAt, appEntityWithDeletedTimestamp.Error, appEntityWithDeletedTimestamp.CorrelationIDs, appEntityWithDeletedTimestamp.Tags, appEntityWithDeletedTimestamp.DocumentationLabels, appEntityWithDeletedTimestamp.SystemNumber, appEntityWithDeletedTimestamp.LocalTenantID, givenID(), givenTenant()).
   284  			WillReturnError(givenError())
   285  
   286  		ctx = persistence.SaveToContext(ctx, db)
   287  
   288  		repo := application.NewRepository(mockConverter)
   289  
   290  		// WHEN
   291  		err := repo.Delete(ctx, givenTenant(), givenID())
   292  
   293  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   294  	})
   295  }
   296  
   297  func TestRepository_Create(t *testing.T) {
   298  	var nilAppModel *model.Application
   299  	appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   300  	appEntity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   301  
   302  	suite := testdb.RepoCreateTestSuite{
   303  		Name: "Generic Create Application",
   304  		SQLQueryDetails: []testdb.SQLQueryDetails{
   305  			{
   306  				Query:       regexp.QuoteMeta(`INSERT INTO public.applications ( id, app_template_id, system_number, local_tenant_id,  name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )`),
   307  				Args:        []driver.Value{givenID(), nil, appModel.SystemNumber, appModel.LocalTenantID, appModel.Name, appModel.Description, appModel.Status.Condition, appModel.Status.Timestamp, appModel.SystemStatus, appModel.HealthCheckURL, appModel.IntegrationSystemID, appModel.ProviderName, appModel.BaseURL, appModel.ApplicationNamespace, repo.NewNullableStringFromJSONRawMessage(appModel.OrdLabels), appModel.Ready, appModel.CreatedAt, appModel.UpdatedAt, appModel.DeletedAt, appModel.Error, repo.NewNullableStringFromJSONRawMessage(appModel.CorrelationIDs), repo.NewNullableStringFromJSONRawMessage(appModel.Tags), repo.NewNullableStringFromJSONRawMessage(appModel.DocumentationLabels), appModel.TenantBusinessTypeID},
   308  				ValidResult: sqlmock.NewResult(-1, 1),
   309  			},
   310  			{
   311  				Query:       regexp.QuoteMeta(`WITH RECURSIVE parents AS (SELECT t1.id, t1.parent FROM business_tenant_mappings t1 WHERE id = ? UNION ALL SELECT t2.id, t2.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2.id = t.parent) INSERT INTO tenant_applications ( tenant_id, id, owner ) (SELECT parents.id AS tenant_id, ? as id, ? AS owner FROM parents)`),
   312  				Args:        []driver.Value{givenTenant(), givenID(), true},
   313  				ValidResult: sqlmock.NewResult(-1, 1),
   314  			},
   315  		},
   316  		ConverterMockProvider: func() testdb.Mock {
   317  			return &automock.EntityConverter{}
   318  		},
   319  		RepoConstructorFunc: application.NewRepository,
   320  		ModelEntity:         appModel,
   321  		DBEntity:            appEntity,
   322  		NilModelEntity:      nilAppModel,
   323  		TenantID:            givenTenant(),
   324  		IsTopLevelEntity:    true,
   325  	}
   326  
   327  	suite.Run(t)
   328  
   329  	// Additional tests
   330  
   331  	t.Run("Success when operation mode is set to async explicitly and operation is in the context", func(t *testing.T) {
   332  		ctx := context.Background()
   333  		ctx = operation.SaveModeToContext(ctx, graphql.OperationModeAsync)
   334  
   335  		op := &operation.Operation{
   336  			OperationType:     operation.OperationTypeCreate,
   337  			OperationCategory: "registerApplication",
   338  		}
   339  		ctx = operation.SaveToContext(ctx, &[]*operation.Operation{op})
   340  
   341  		appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   342  		appEntity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   343  
   344  		appModel.Ready = false
   345  		appEntity.Ready = false
   346  
   347  		mockConverter := &automock.EntityConverter{}
   348  		mockConverter.On("ToEntity", appModel).Return(appEntity, nil).Once()
   349  		defer mockConverter.AssertExpectations(t)
   350  
   351  		db, dbMock := testdb.MockDatabase(t)
   352  		defer dbMock.AssertExpectations(t)
   353  
   354  		dbMock.ExpectExec(regexp.QuoteMeta(`INSERT INTO public.applications ( id, app_template_id, system_number, local_tenant_id,  name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )`)).
   355  			WithArgs(givenID(), nil, appModel.SystemNumber, appModel.LocalTenantID, appModel.Name, appModel.Description, appModel.Status.Condition, appModel.Status.Timestamp, appModel.SystemStatus, appModel.HealthCheckURL, appModel.IntegrationSystemID, appModel.ProviderName, appModel.BaseURL, appModel.ApplicationNamespace, repo.NewNullableStringFromJSONRawMessage(appModel.OrdLabels), appModel.Ready, appModel.CreatedAt, appModel.UpdatedAt, appModel.DeletedAt, appModel.Error, repo.NewNullableStringFromJSONRawMessage(appModel.CorrelationIDs), repo.NewNullableStringFromJSONRawMessage(appModel.Tags), repo.NewNullableStringFromJSONRawMessage(appModel.DocumentationLabels), appModel.TenantBusinessTypeID).
   356  			WillReturnResult(sqlmock.NewResult(-1, 1))
   357  
   358  		dbMock.ExpectExec(regexp.QuoteMeta(`WITH RECURSIVE parents AS (SELECT t1.id, t1.parent FROM business_tenant_mappings t1 WHERE id = ? UNION ALL SELECT t2.id, t2.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2.id = t.parent) INSERT INTO tenant_applications ( tenant_id, id, owner ) (SELECT parents.id AS tenant_id, ? as id, ? AS owner FROM parents)`)).
   359  			WithArgs(givenTenant(), givenID(), true).
   360  			WillReturnResult(sqlmock.NewResult(-1, 1))
   361  
   362  		ctx = persistence.SaveToContext(ctx, db)
   363  
   364  		repo := application.NewRepository(mockConverter)
   365  
   366  		// WHEN
   367  		err := repo.Create(ctx, givenTenant(), appModel)
   368  
   369  		// then
   370  		assert.NoError(t, err)
   371  	})
   372  }
   373  
   374  func TestRepository_Update(t *testing.T) {
   375  	updateStmt := regexp.QuoteMeta(`UPDATE public.applications SET name = ?, description = ?, status_condition = ?, status_timestamp = ?, system_status = ?,  healthcheck_url = ?, integration_system_id = ?, provider_name = ?, base_url = ?, application_namespace = ?, labels = ?, ready = ?, created_at = ?, updated_at = ?, deleted_at = ?, error = ?, correlation_ids = ?, tags = ?, documentation_labels = ?, system_number = ?, local_tenant_id = ? WHERE id = ? AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = ? AND owner = true))`)
   376  
   377  	var nilAppModel *model.Application
   378  	appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   379  	appEntity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   380  	appEntity.UpdatedAt = &fixedTimestamp
   381  	appEntity.DeletedAt = &fixedTimestamp // This is needed as workaround so that updatedAt timestamp is not updated
   382  
   383  	suite := testdb.RepoUpdateTestSuite{
   384  		Name: "Update Application",
   385  		SQLQueryDetails: []testdb.SQLQueryDetails{
   386  			{
   387  				Query:         updateStmt,
   388  				Args:          []driver.Value{appModel.Name, appModel.Description, appModel.Status.Condition, appModel.Status.Timestamp, appModel.SystemStatus, appModel.HealthCheckURL, appModel.IntegrationSystemID, appModel.ProviderName, appModel.BaseURL, appModel.ApplicationNamespace, repo.NewNullableStringFromJSONRawMessage(appModel.OrdLabels), appEntity.Ready, appEntity.CreatedAt, appEntity.UpdatedAt, appEntity.DeletedAt, appEntity.Error, appEntity.CorrelationIDs, repo.NewNullableStringFromJSONRawMessage(appModel.Tags), repo.NewNullableStringFromJSONRawMessage(appModel.DocumentationLabels), appEntity.SystemNumber, appEntity.LocalTenantID, givenID(), givenTenant()},
   389  				ValidResult:   sqlmock.NewResult(-1, 1),
   390  				InvalidResult: sqlmock.NewResult(-1, 0),
   391  			},
   392  		},
   393  		ConverterMockProvider: func() testdb.Mock {
   394  			return &automock.EntityConverter{}
   395  		},
   396  		RepoConstructorFunc: application.NewRepository,
   397  		ModelEntity:         appModel,
   398  		DBEntity:            appEntity,
   399  		NilModelEntity:      nilAppModel,
   400  		TenantID:            givenTenant(),
   401  	}
   402  
   403  	suite.Run(t)
   404  }
   405  
   406  func TestRepository_Upsert(t *testing.T) {
   407  	upsertStmt := regexp.QuoteMeta(`INSERT INTO public.applications ( id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24 ) ON CONFLICT ( system_number ) DO UPDATE SET name=EXCLUDED.name, description=EXCLUDED.description, status_condition=EXCLUDED.status_condition, system_status=EXCLUDED.system_status, provider_name=EXCLUDED.provider_name, base_url=EXCLUDED.base_url, application_namespace=EXCLUDED.application_namespace, labels=EXCLUDED.labels, tenant_business_type_id=EXCLUDED.tenant_business_type_id WHERE (public.applications.id IN (SELECT id FROM tenant_applications WHERE tenant_id = $25 AND owner = true)) RETURNING id;`)
   408  
   409  	var nilAppModel *model.Application
   410  	appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   411  	appEntity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   412  
   413  	suite := testdb.RepoUpsertTestSuite{
   414  		Name: "Upsert Application",
   415  		SQLQueryDetails: []testdb.SQLQueryDetails{
   416  			{
   417  				Query: upsertStmt,
   418  				Args:  []driver.Value{givenID(), sql.NullString{}, appModel.SystemNumber, appModel.LocalTenantID, appModel.Name, appModel.Description, appModel.Status.Condition, appModel.Status.Timestamp, appModel.SystemStatus, appModel.HealthCheckURL, appModel.IntegrationSystemID, appModel.ProviderName, appModel.BaseURL, appModel.ApplicationNamespace, repo.NewNullableStringFromJSONRawMessage(appModel.OrdLabels), appEntity.Ready, appEntity.CreatedAt, appEntity.UpdatedAt, appEntity.DeletedAt, appEntity.Error, appEntity.CorrelationIDs, appEntity.Tags, appEntity.DocumentationLabels, appEntity.TenantBusinessTypeID, givenTenant()},
   419  				ValidRowsProvider: func() []*sqlmock.Rows {
   420  					return []*sqlmock.Rows{
   421  						sqlmock.NewRows([]string{"id"}).
   422  							AddRow(givenID()),
   423  					}
   424  				},
   425  				InvalidRowsProvider: func() []*sqlmock.Rows {
   426  					return []*sqlmock.Rows{
   427  						sqlmock.NewRows([]string{"id"}),
   428  					}
   429  				},
   430  				IsSelect: true,
   431  			},
   432  			{
   433  				Query:       regexp.QuoteMeta(`WITH RECURSIVE parents AS (SELECT t1.id, t1.parent FROM business_tenant_mappings t1 WHERE id = ? UNION ALL SELECT t2.id, t2.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2.id = t.parent) INSERT INTO tenant_applications ( tenant_id, id, owner ) (SELECT parents.id AS tenant_id, ? as id, ? AS owner FROM parents)`),
   434  				Args:        []driver.Value{givenTenant(), givenID(), true},
   435  				ValidResult: sqlmock.NewResult(-1, 1),
   436  			},
   437  		},
   438  		ConverterMockProvider: func() testdb.Mock {
   439  			return &automock.EntityConverter{}
   440  		},
   441  		RepoConstructorFunc: application.NewRepository,
   442  		ModelEntity:         appModel,
   443  		DBEntity:            appEntity,
   444  		NilModelEntity:      nilAppModel,
   445  		TenantID:            givenTenant(),
   446  	}
   447  
   448  	suite.Run(t)
   449  }
   450  
   451  func TestRepository_TrustedUpsert(t *testing.T) {
   452  	upsertStmt := regexp.QuoteMeta(`INSERT INTO public.applications ( id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24 ) ON CONFLICT ( system_number ) DO UPDATE SET name=EXCLUDED.name, description=EXCLUDED.description, status_condition=EXCLUDED.status_condition, system_status=EXCLUDED.system_status, provider_name=EXCLUDED.provider_name, base_url=EXCLUDED.base_url, application_namespace=EXCLUDED.application_namespace, labels=EXCLUDED.labels, tenant_business_type_id=EXCLUDED.tenant_business_type_id RETURNING id;`)
   453  
   454  	var nilAppModel *model.Application
   455  	appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   456  	appEntity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   457  
   458  	suite := testdb.RepoUpsertTestSuite{
   459  		Name: "Trusted Upsert Application",
   460  		SQLQueryDetails: []testdb.SQLQueryDetails{
   461  			{
   462  				Query: upsertStmt,
   463  				Args:  []driver.Value{givenID(), sql.NullString{}, appModel.SystemNumber, appModel.LocalTenantID, appModel.Name, appModel.Description, appModel.Status.Condition, appModel.Status.Timestamp, appModel.SystemStatus, appModel.HealthCheckURL, appModel.IntegrationSystemID, appModel.ProviderName, appModel.BaseURL, appModel.ApplicationNamespace, repo.NewNullableStringFromJSONRawMessage(appModel.OrdLabels), appEntity.Ready, appEntity.CreatedAt, appEntity.UpdatedAt, appEntity.DeletedAt, appEntity.Error, appEntity.CorrelationIDs, appEntity.Tags, appEntity.DocumentationLabels, appModel.TenantBusinessTypeID},
   464  				ValidRowsProvider: func() []*sqlmock.Rows {
   465  					return []*sqlmock.Rows{
   466  						sqlmock.NewRows([]string{"id"}).
   467  							AddRow(givenID()),
   468  					}
   469  				},
   470  				InvalidRowsProvider: func() []*sqlmock.Rows {
   471  					return []*sqlmock.Rows{
   472  						sqlmock.NewRows([]string{"id"}),
   473  					}
   474  				},
   475  				IsSelect: true,
   476  			},
   477  			{
   478  				Query:       regexp.QuoteMeta(`WITH RECURSIVE parents AS (SELECT t1.id, t1.parent FROM business_tenant_mappings t1 WHERE id = ? UNION ALL SELECT t2.id, t2.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2.id = t.parent) INSERT INTO tenant_applications ( tenant_id, id, owner ) (SELECT parents.id AS tenant_id, ? as id, ? AS owner FROM parents)`),
   479  				Args:        []driver.Value{givenTenant(), givenID(), true},
   480  				ValidResult: sqlmock.NewResult(-1, 1),
   481  			},
   482  		},
   483  		ConverterMockProvider: func() testdb.Mock {
   484  			return &automock.EntityConverter{}
   485  		},
   486  		RepoConstructorFunc: application.NewRepository,
   487  		ModelEntity:         appModel,
   488  		DBEntity:            appEntity,
   489  		NilModelEntity:      nilAppModel,
   490  		TenantID:            givenTenant(),
   491  		UpsertMethodName:    "TrustedUpsert",
   492  	}
   493  
   494  	suite.Run(t)
   495  }
   496  
   497  func TestRepository_GetByID(t *testing.T) {
   498  	entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   499  	suite := testdb.RepoGetTestSuite{
   500  		Name: "Get Application",
   501  		SQLQueryDetails: []testdb.SQLQueryDetails{
   502  			{
   503  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`),
   504  				Args:     []driver.Value{givenID(), givenTenant()},
   505  				IsSelect: true,
   506  				ValidRowsProvider: func() []*sqlmock.Rows {
   507  					return []*sqlmock.Rows{
   508  						sqlmock.NewRows(fixAppColumns()).
   509  							AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID),
   510  					}
   511  				},
   512  				InvalidRowsProvider: func() []*sqlmock.Rows {
   513  					return []*sqlmock.Rows{
   514  						sqlmock.NewRows(fixAppColumns()),
   515  					}
   516  				},
   517  			},
   518  		},
   519  		ConverterMockProvider: func() testdb.Mock {
   520  			return &automock.EntityConverter{}
   521  		},
   522  		RepoConstructorFunc:       application.NewRepository,
   523  		ExpectedModelEntity:       fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description"),
   524  		ExpectedDBEntity:          entity,
   525  		MethodArgs:                []interface{}{givenTenant(), givenID()},
   526  		DisableConverterErrorTest: true,
   527  	}
   528  
   529  	suite.Run(t)
   530  }
   531  
   532  func TestRepository_GetGlobalByIDForUpdate(t *testing.T) {
   533  	entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "Test app", "Test app description")
   534  	suite := testdb.RepoGetTestSuite{
   535  		Name: "Get Application",
   536  		SQLQueryDetails: []testdb.SQLQueryDetails{
   537  			{
   538  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2)) FOR UPDATE`),
   539  				Args:     []driver.Value{givenID(), givenTenant()},
   540  				IsSelect: true,
   541  				ValidRowsProvider: func() []*sqlmock.Rows {
   542  					return []*sqlmock.Rows{
   543  						sqlmock.NewRows(fixAppColumns()).
   544  							AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition,
   545  								entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace,
   546  								entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID),
   547  					}
   548  				},
   549  				InvalidRowsProvider: func() []*sqlmock.Rows {
   550  					return []*sqlmock.Rows{
   551  						sqlmock.NewRows(fixAppColumns()),
   552  					}
   553  				},
   554  			},
   555  		},
   556  		ConverterMockProvider: func() testdb.Mock {
   557  			return &automock.EntityConverter{}
   558  		},
   559  		RepoConstructorFunc:       application.NewRepository,
   560  		ExpectedModelEntity:       fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description"),
   561  		ExpectedDBEntity:          entity,
   562  		MethodArgs:                []interface{}{givenTenant(), givenID()},
   563  		DisableConverterErrorTest: true,
   564  		MethodName:                "GetByIDForUpdate",
   565  	}
   566  
   567  	suite.Run(t)
   568  }
   569  
   570  func TestPgRepository_ListAllByApplicationTemplateID(t *testing.T) {
   571  	appID := givenID()
   572  	appTemplateID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   573  	entity := fixDetailedEntityApplication(t, appID, givenTenant(), "App", "App desc")
   574  	entity.ApplicationTemplateID = repo.NewValidNullableString(appTemplateID)
   575  
   576  	appModel := fixDetailedModelApplication(t, appID, givenTenant(), "App", "App desc")
   577  	appModel.ApplicationTemplateID = str.Ptr(appTemplateID)
   578  	suite := testdb.RepoListTestSuite{
   579  		Name: "List applications by app template id",
   580  		SQLQueryDetails: []testdb.SQLQueryDetails{
   581  			{
   582  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE app_template_id = $1`),
   583  				Args:     []driver.Value{appTemplateID},
   584  				IsSelect: true,
   585  				ValidRowsProvider: func() []*sqlmock.Rows {
   586  					return []*sqlmock.Rows{
   587  						sqlmock.NewRows(fixAppColumns()).
   588  							AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID),
   589  					}
   590  				},
   591  				InvalidRowsProvider: func() []*sqlmock.Rows {
   592  					return []*sqlmock.Rows{
   593  						sqlmock.NewRows(fixAppColumns()),
   594  					}
   595  				},
   596  			},
   597  		},
   598  		ConverterMockProvider: func() testdb.Mock {
   599  			return &automock.EntityConverter{}
   600  		},
   601  		RepoConstructorFunc:       application.NewRepository,
   602  		ExpectedModelEntities:     []interface{}{appModel},
   603  		ExpectedDBEntities:        []interface{}{entity},
   604  		MethodName:                "ListAllByApplicationTemplateID",
   605  		MethodArgs:                []interface{}{appTemplateID},
   606  		DisableConverterErrorTest: true,
   607  	}
   608  
   609  	suite.Run(t)
   610  }
   611  
   612  func TestPgRepository_List(t *testing.T) {
   613  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
   614  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   615  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   616  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   617  
   618  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   619  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   620  
   621  	suite := testdb.RepoListPageableTestSuite{
   622  		Name: "List Applications",
   623  		SQLQueryDetails: []testdb.SQLQueryDetails{
   624  			{
   625  				Query: regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications
   626  												WHERE (id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" ?| array[$3])
   627  												AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $4))) ORDER BY id LIMIT 2 OFFSET 0`),
   628  				Args:     []driver.Value{givenTenant(), model.ScenariosKey, "scenario", givenTenant()},
   629  				IsSelect: true,
   630  				ValidRowsProvider: func() []*sqlmock.Rows {
   631  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
   632  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
   633  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
   634  					}
   635  				},
   636  			},
   637  			{
   638  				Query: regexp.QuoteMeta(`SELECT COUNT(*) FROM public.applications
   639  												WHERE (id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" ?| array[$3])
   640  												AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $4)))`),
   641  				Args:     []driver.Value{givenTenant(), model.ScenariosKey, "scenario", givenTenant()},
   642  				IsSelect: true,
   643  				ValidRowsProvider: func() []*sqlmock.Rows {
   644  					return []*sqlmock.Rows{sqlmock.NewRows([]string{"count"}).AddRow(2)}
   645  				},
   646  			},
   647  		},
   648  		Pages: []testdb.PageDetails{
   649  			{
   650  				ExpectedModelEntities: []interface{}{appModel1, appModel2},
   651  				ExpectedDBEntities:    []interface{}{appEntity1, appEntity2},
   652  				ExpectedPage: &model.ApplicationPage{
   653  					Data: []*model.Application{appModel1, appModel2},
   654  					PageInfo: &pagination.Page{
   655  						StartCursor: "",
   656  						EndCursor:   "",
   657  						HasNextPage: false,
   658  					},
   659  					TotalCount: 2,
   660  				},
   661  			},
   662  		},
   663  		ConverterMockProvider: func() testdb.Mock {
   664  			return &automock.EntityConverter{}
   665  		},
   666  		RepoConstructorFunc:       application.NewRepository,
   667  		MethodArgs:                []interface{}{givenTenant(), []*labelfilter.LabelFilter{labelfilter.NewForKeyWithQuery(model.ScenariosKey, `$[*] ? ( @ == "scenario" )`)}, 2, ""},
   668  		MethodName:                "List",
   669  		DisableConverterErrorTest: true,
   670  	}
   671  
   672  	suite.Run(t)
   673  }
   674  
   675  func TestPgRepository_ListGlobal(t *testing.T) {
   676  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
   677  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   678  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   679  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   680  
   681  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   682  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   683  
   684  	inputPageSize := 3
   685  	inputCursor := ""
   686  	totalCount := 2
   687  
   688  	pageableQuery := `SELECT (.+) FROM public\.applications ORDER BY id LIMIT %d OFFSET %d$`
   689  	countQuery := `SELECT COUNT\(\*\) FROM public\.applications`
   690  
   691  	t.Run("Success", func(t *testing.T) {
   692  		// GIVEN
   693  		rows := sqlmock.NewRows([]string{"id", "name", "system_number", "local_tenant_id", "description", "status_condition", "status_timestamp", "system_status", "healthcheck_url", "integration_system_id", "provider_name", "base_url", "application_namespace", "labels", "ready", "created_at", "updated_at", "deleted_at", "error", "correlation_ids", "tags", "documentation_labels", "tenant_business_type_id"}).
   694  			AddRow(appEntity1.ID, appEntity1.Name, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
   695  			AddRow(appEntity2.ID, appEntity2.Name, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID)
   696  
   697  		sqlxDB, sqlMock := testdb.MockDatabase(t)
   698  		defer sqlMock.AssertExpectations(t)
   699  
   700  		sqlMock.ExpectQuery(fmt.Sprintf(pageableQuery, inputPageSize, 0)).
   701  			WithArgs().
   702  			WillReturnRows(rows)
   703  
   704  		sqlMock.ExpectQuery(countQuery).
   705  			WithArgs().
   706  			WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(2))
   707  		ctx := persistence.SaveToContext(context.TODO(), sqlxDB)
   708  
   709  		conv := &automock.EntityConverter{}
   710  		conv.On("FromEntity", appEntity2).Return(appModel2).Once()
   711  		conv.On("FromEntity", appEntity1).Return(appModel1).Once()
   712  		defer conv.AssertExpectations(t)
   713  
   714  		pgRepository := application.NewRepository(conv)
   715  
   716  		// WHEN
   717  		modelApp, err := pgRepository.ListGlobal(ctx, inputPageSize, inputCursor)
   718  
   719  		// then
   720  		require.NoError(t, err)
   721  		require.Len(t, modelApp.Data, 2)
   722  		assert.Equal(t, appEntity1.ID, modelApp.Data[0].ID)
   723  		assert.Equal(t, appEntity2.ID, modelApp.Data[1].ID)
   724  		assert.Equal(t, "", modelApp.PageInfo.StartCursor)
   725  		assert.Equal(t, totalCount, modelApp.TotalCount)
   726  	})
   727  
   728  	t.Run("DB Error", func(t *testing.T) {
   729  		// GIVEN
   730  		sqlxDB, sqlMock := testdb.MockDatabase(t)
   731  		defer sqlMock.AssertExpectations(t)
   732  
   733  		sqlMock.ExpectQuery(fmt.Sprintf(pageableQuery, inputPageSize, 0)).
   734  			WithArgs().
   735  			WillReturnError(givenError())
   736  
   737  		ctx := persistence.SaveToContext(context.TODO(), sqlxDB)
   738  		conv := &automock.EntityConverter{}
   739  		defer conv.AssertExpectations(t)
   740  
   741  		pgRepository := application.NewRepository(conv)
   742  
   743  		// WHEN
   744  		_, err := pgRepository.ListGlobal(ctx, inputPageSize, inputCursor)
   745  
   746  		// THEN
   747  		require.Error(t, err)
   748  		require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query")
   749  	})
   750  }
   751  
   752  func TestPgRepository_ListAll(t *testing.T) {
   753  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
   754  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   755  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   756  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   757  
   758  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   759  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   760  
   761  	suite := testdb.RepoListTestSuite{
   762  		Name: "List Applications",
   763  		SQLQueryDetails: []testdb.SQLQueryDetails{
   764  			{
   765  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $1))`),
   766  				Args:     []driver.Value{givenTenant()},
   767  				IsSelect: true,
   768  				ValidRowsProvider: func() []*sqlmock.Rows {
   769  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
   770  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
   771  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
   772  					}
   773  				},
   774  				InvalidRowsProvider: func() []*sqlmock.Rows {
   775  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns())}
   776  				},
   777  			},
   778  		},
   779  		ConverterMockProvider: func() testdb.Mock {
   780  			return &automock.EntityConverter{}
   781  		},
   782  		RepoConstructorFunc:       application.NewRepository,
   783  		ExpectedModelEntities:     []interface{}{appModel1, appModel2},
   784  		ExpectedDBEntities:        []interface{}{appEntity1, appEntity2},
   785  		MethodArgs:                []interface{}{givenTenant()},
   786  		MethodName:                "ListAll",
   787  		DisableConverterErrorTest: true,
   788  	}
   789  
   790  	suite.Run(t)
   791  }
   792  
   793  func TestPgRepository_ListAllByIDs(t *testing.T) {
   794  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
   795  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   796  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   797  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   798  
   799  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   800  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   801  
   802  	suite := testdb.RepoListTestSuite{
   803  		Name: "List Applications",
   804  		SQLQueryDetails: []testdb.SQLQueryDetails{
   805  			{
   806  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id IN ($1, $2) AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $3))`),
   807  				Args:     []driver.Value{app1ID, app2ID, givenTenant()},
   808  				IsSelect: true,
   809  				ValidRowsProvider: func() []*sqlmock.Rows {
   810  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
   811  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
   812  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
   813  					}
   814  				},
   815  				InvalidRowsProvider: func() []*sqlmock.Rows {
   816  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns())}
   817  				},
   818  			},
   819  		},
   820  		ConverterMockProvider: func() testdb.Mock {
   821  			return &automock.EntityConverter{}
   822  		},
   823  		RepoConstructorFunc:       application.NewRepository,
   824  		ExpectedModelEntities:     []interface{}{appModel1, appModel2},
   825  		ExpectedDBEntities:        []interface{}{appEntity1, appEntity2},
   826  		MethodArgs:                []interface{}{givenTenant(), []string{app1ID, app2ID}},
   827  		MethodName:                "ListAllByIDs",
   828  		DisableConverterErrorTest: true,
   829  	}
   830  
   831  	suite.Run(t)
   832  }
   833  
   834  func TestPgRepository_ListListeningApplications(t *testing.T) {
   835  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
   836  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   837  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   838  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   839  
   840  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   841  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   842  
   843  	suite := testdb.RepoListTestSuite{
   844  		Name: "List listening Applications",
   845  		SQLQueryDetails: []testdb.SQLQueryDetails{
   846  			{
   847  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM listening_applications WHERE webhook_type = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`),
   848  				Args:     []driver.Value{model.WebhookTypeConfigurationChanged, givenTenant()},
   849  				IsSelect: true,
   850  				ValidRowsProvider: func() []*sqlmock.Rows {
   851  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
   852  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
   853  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
   854  					}
   855  				},
   856  				InvalidRowsProvider: func() []*sqlmock.Rows {
   857  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns())}
   858  				},
   859  			},
   860  		},
   861  		ConverterMockProvider: func() testdb.Mock {
   862  			return &automock.EntityConverter{}
   863  		},
   864  		RepoConstructorFunc:       application.NewRepository,
   865  		ExpectedModelEntities:     []interface{}{appModel1, appModel2},
   866  		ExpectedDBEntities:        []interface{}{appEntity1, appEntity2},
   867  		MethodArgs:                []interface{}{givenTenant(), model.WebhookTypeConfigurationChanged},
   868  		MethodName:                "ListListeningApplications",
   869  		DisableConverterErrorTest: true,
   870  	}
   871  
   872  	suite.Run(t)
   873  }
   874  
   875  func TestPgRepository_ListByRuntimeScenarios(t *testing.T) {
   876  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
   877  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
   878  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   879  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   880  
   881  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
   882  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
   883  
   884  	hidingSelectors := map[string][]string{"foo": {"bar", "baz"}}
   885  
   886  	suite := testdb.RepoListPageableTestSuite{
   887  		Name: "List Applications By Scenarios",
   888  		SQLQueryDetails: []testdb.SQLQueryDetails{
   889  			{
   890  
   891  				//SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, documentation_labels FROM public.applications WHERE (id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" ?| array[$3] UNION SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 AND "value" ?| array[$6] UNION SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $7)) AND "key" = $8 AND "value" ?| array[$9] EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $10)) AND "key" = $11 AND "value" @> $12 EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $13)) AND "key" = $14 AND "value" @> $15) AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $16))) ORDER BY id LIMIT 2 OFFSET 0
   892  				//SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, documentation_labels FROM public.applications WHERE (id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" ?| array[$3] UNION SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 AND "value" ?| array[$6] UNION SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $7)) AND "key" = $8 AND "value" ?| array[$9] EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $10)) AND "key" = $11 AND "value" @> $12 EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $13)) AND "key" = $14 AND "value" @> $15) AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $16))) ORDER BY id LIMIT 2 OFFSET 0
   893  				Query: regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications
   894  												WHERE (id IN (SELECT "app_id" FROM public.labels
   895  													WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" ?| array[$3]
   896  													UNION SELECT "app_id" FROM public.labels
   897  													WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 AND "value" ?| array[$6]
   898  													UNION SELECT "app_id" FROM public.labels
   899  													WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $7)) AND "key" = $8 AND "value" ?| array[$9]
   900  													EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $10)) AND "key" = $11 AND "value" @> $12
   901  													EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $13)) AND "key" = $14 AND "value" @> $15)
   902  												AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $16))) ORDER BY id LIMIT 2 OFFSET 0`),
   903  				Args:     []driver.Value{givenTenant(), model.ScenariosKey, "Java", givenTenant(), model.ScenariosKey, "Go", givenTenant(), model.ScenariosKey, "Elixir", givenTenant(), "foo", strconv.Quote("bar"), givenTenant(), "foo", strconv.Quote("baz"), givenTenant()},
   904  				IsSelect: true,
   905  				ValidRowsProvider: func() []*sqlmock.Rows {
   906  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
   907  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
   908  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
   909  					}
   910  				},
   911  			},
   912  			{
   913  				Query: regexp.QuoteMeta(`SELECT COUNT(*) FROM public.applications
   914  												WHERE (id IN (SELECT "app_id" FROM public.labels
   915  													WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" ?| array[$3]
   916  													UNION SELECT "app_id" FROM public.labels
   917  													WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 AND "value" ?| array[$6]
   918  													UNION SELECT "app_id" FROM public.labels
   919  													WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $7)) AND "key" = $8 AND "value" ?| array[$9]
   920  													EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $10)) AND "key" = $11 AND "value" @> $12
   921  													EXCEPT SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $13)) AND "key" = $14 AND "value" @> $15)
   922  												AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $16)))`),
   923  				Args:     []driver.Value{givenTenant(), model.ScenariosKey, "Java", givenTenant(), model.ScenariosKey, "Go", givenTenant(), model.ScenariosKey, "Elixir", givenTenant(), "foo", strconv.Quote("bar"), givenTenant(), "foo", strconv.Quote("baz"), givenTenant()},
   924  				IsSelect: true,
   925  				ValidRowsProvider: func() []*sqlmock.Rows {
   926  					return []*sqlmock.Rows{sqlmock.NewRows([]string{"count"}).AddRow(2)}
   927  				},
   928  			},
   929  		},
   930  		Pages: []testdb.PageDetails{
   931  			{
   932  				ExpectedModelEntities: []interface{}{appModel1, appModel2},
   933  				ExpectedDBEntities:    []interface{}{appEntity1, appEntity2},
   934  				ExpectedPage: &model.ApplicationPage{
   935  					Data: []*model.Application{appModel1, appModel2},
   936  					PageInfo: &pagination.Page{
   937  						StartCursor: "",
   938  						EndCursor:   "",
   939  						HasNextPage: false,
   940  					},
   941  					TotalCount: 2,
   942  				},
   943  			},
   944  		},
   945  		ConverterMockProvider: func() testdb.Mock {
   946  			return &automock.EntityConverter{}
   947  		},
   948  		RepoConstructorFunc:       application.NewRepository,
   949  		MethodArgs:                []interface{}{uuid.MustParse(givenTenant()), []string{"Java", "Go", "Elixir"}, 2, "", hidingSelectors},
   950  		MethodName:                "ListByScenarios",
   951  		DisableConverterErrorTest: true,
   952  	}
   953  
   954  	suite.Run(t)
   955  }
   956  
   957  func TestPgRepository_GetBySystemNumber(t *testing.T) {
   958  	entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), appName, "Test app description")
   959  	suite := testdb.RepoGetTestSuite{
   960  		Name: "Get Application By System Number",
   961  		SQLQueryDetails: []testdb.SQLQueryDetails{
   962  			{
   963  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE system_number = $1 AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $2))`),
   964  				Args:     []driver.Value{systemNumber, givenTenant()},
   965  				IsSelect: true,
   966  				ValidRowsProvider: func() []*sqlmock.Rows {
   967  					return []*sqlmock.Rows{
   968  						sqlmock.NewRows(fixAppColumns()).
   969  							AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID),
   970  					}
   971  				},
   972  				InvalidRowsProvider: func() []*sqlmock.Rows {
   973  					return []*sqlmock.Rows{
   974  						sqlmock.NewRows(fixAppColumns()),
   975  					}
   976  				},
   977  			},
   978  		},
   979  		ConverterMockProvider: func() testdb.Mock {
   980  			return &automock.EntityConverter{}
   981  		},
   982  		RepoConstructorFunc:       application.NewRepository,
   983  		ExpectedModelEntity:       fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description"),
   984  		ExpectedDBEntity:          entity,
   985  		MethodName:                "GetBySystemNumber",
   986  		MethodArgs:                []interface{}{givenTenant(), systemNumber},
   987  		DisableConverterErrorTest: true,
   988  	}
   989  
   990  	suite.Run(t)
   991  }
   992  
   993  func TestPgRepository_GetByFilter(t *testing.T) {
   994  	entity := fixDetailedEntityApplication(t, givenID(), givenTenant(), appName, "Test app description")
   995  	suite := testdb.RepoGetTestSuite{
   996  		Name: "Get Application By filter",
   997  		SQLQueryDetails: []testdb.SQLQueryDetails{
   998  			{
   999  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" @> $3) AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $4))`),
  1000  				Args:     []driver.Value{givenTenantAsUUID(), "SCC", "{\"Subaccount\":\"subacc\", \"LocationID\":\"LocationID\", \"Host\":\"Host\"}", givenTenant()},
  1001  				IsSelect: true,
  1002  				ValidRowsProvider: func() []*sqlmock.Rows {
  1003  					return []*sqlmock.Rows{
  1004  						sqlmock.NewRows(fixAppColumns()).
  1005  							AddRow(entity.ID, entity.ApplicationTemplateID, entity.SystemNumber, entity.LocalTenantID, entity.Name, entity.Description, entity.StatusCondition, entity.StatusTimestamp, entity.SystemStatus, entity.HealthCheckURL, entity.IntegrationSystemID, entity.ProviderName, entity.BaseURL, entity.ApplicationNamespace, entity.OrdLabels, entity.Ready, entity.CreatedAt, entity.UpdatedAt, entity.DeletedAt, entity.Error, entity.CorrelationIDs, entity.Tags, entity.DocumentationLabels, entity.TenantBusinessTypeID),
  1006  					}
  1007  				},
  1008  				InvalidRowsProvider: func() []*sqlmock.Rows {
  1009  					return []*sqlmock.Rows{
  1010  						sqlmock.NewRows(fixAppColumns()),
  1011  					}
  1012  				},
  1013  			},
  1014  		},
  1015  		ConverterMockProvider: func() testdb.Mock {
  1016  			return &automock.EntityConverter{}
  1017  		},
  1018  		RepoConstructorFunc:       application.NewRepository,
  1019  		ExpectedModelEntity:       fixDetailedModelApplication(t, givenID(), givenTenant(), "Test app", "Test app description"),
  1020  		ExpectedDBEntity:          entity,
  1021  		MethodName:                "GetByFilter",
  1022  		MethodArgs:                []interface{}{givenTenant(), []*labelfilter.LabelFilter{labelfilter.NewForKeyWithQuery("SCC", "{\"Subaccount\":\"subacc\", \"LocationID\":\"LocationID\", \"Host\":\"Host\"}")}},
  1023  		DisableConverterErrorTest: true,
  1024  	}
  1025  
  1026  	suite.Run(t)
  1027  }
  1028  
  1029  func TestPgRepository_ListAllByFilter(t *testing.T) {
  1030  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
  1031  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
  1032  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
  1033  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
  1034  
  1035  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
  1036  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
  1037  
  1038  	suite := testdb.RepoListTestSuite{
  1039  		Name: "List Applications",
  1040  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1041  			{
  1042  				Query:    regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications WHERE id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) AND "key" = $2 AND "value" @> $3) AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $4))`),
  1043  				Args:     []driver.Value{givenTenantAsUUID(), "scc", "{\"locationId\":\"locationId\"}", givenTenant()},
  1044  				IsSelect: true,
  1045  				ValidRowsProvider: func() []*sqlmock.Rows {
  1046  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
  1047  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
  1048  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
  1049  					}
  1050  				},
  1051  				InvalidRowsProvider: func() []*sqlmock.Rows {
  1052  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns())}
  1053  				},
  1054  			},
  1055  		},
  1056  		ConverterMockProvider: func() testdb.Mock {
  1057  			return &automock.EntityConverter{}
  1058  		},
  1059  		RepoConstructorFunc:       application.NewRepository,
  1060  		ExpectedModelEntities:     []interface{}{appModel1, appModel2},
  1061  		ExpectedDBEntities:        []interface{}{appEntity1, appEntity2},
  1062  		MethodArgs:                []interface{}{givenTenant(), []*labelfilter.LabelFilter{labelfilter.NewForKeyWithQuery("scc", "{\"locationId\":\"locationId\"}")}},
  1063  		MethodName:                "ListAllByFilter",
  1064  		DisableConverterErrorTest: true,
  1065  	}
  1066  
  1067  	suite.Run(t)
  1068  }
  1069  
  1070  func TestPgRepository_ListByRuntimeScenariosNoPaging(t *testing.T) {
  1071  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
  1072  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
  1073  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
  1074  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
  1075  
  1076  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
  1077  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
  1078  
  1079  	suite := testdb.RepoListTestSuite{
  1080  		Name: "List Applications By Scenarios",
  1081  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1082  			{
  1083  				Query: regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications 
  1084  											   WHERE id IN (SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL 
  1085  											   AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) 
  1086  											   AND "key" = $2 AND "value" ?| array[$3] UNION SELECT "app_id" FROM public.labels WHERE "app_id" IS NOT NULL 
  1087  											   AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 AND "value" ?| array[$6] 
  1088  											   UNION SELECT 
  1089  											   "app_id" FROM public.labels WHERE "app_id" IS NOT NULL 
  1090  											   AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $7)) 
  1091  											   AND "key" = $8 AND "value" ?| array[$9]) 
  1092  											   AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $10))`),
  1093  				Args:     []driver.Value{givenTenant(), model.ScenariosKey, "Java", givenTenant(), model.ScenariosKey, "Go", givenTenant(), model.ScenariosKey, "Elixir", givenTenant()},
  1094  				IsSelect: true,
  1095  				ValidRowsProvider: func() []*sqlmock.Rows {
  1096  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
  1097  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
  1098  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
  1099  					}
  1100  				},
  1101  				InvalidRowsProvider: func() []*sqlmock.Rows {
  1102  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns())}
  1103  				},
  1104  			},
  1105  		},
  1106  		ExpectedModelEntities: []interface{}{appModel1, appModel2},
  1107  		ExpectedDBEntities:    []interface{}{appEntity1, appEntity2},
  1108  		ConverterMockProvider: func() testdb.Mock {
  1109  			return &automock.EntityConverter{}
  1110  		},
  1111  		RepoConstructorFunc:       application.NewRepository,
  1112  		MethodArgs:                []interface{}{givenTenant(), []string{"Java", "Go", "Elixir"}},
  1113  		MethodName:                "ListByScenariosNoPaging",
  1114  		DisableConverterErrorTest: true,
  1115  	}
  1116  
  1117  	suite.Run(t)
  1118  }
  1119  
  1120  func TestPgRepository_ListByScenariosAndIDs(t *testing.T) {
  1121  	scenario1 := "scenario-1"
  1122  	scenario2 := "scenario-2"
  1123  
  1124  	app1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9"
  1125  	app2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4"
  1126  
  1127  	appEntity1 := fixDetailedEntityApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
  1128  	appEntity2 := fixDetailedEntityApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
  1129  
  1130  	appModel1 := fixDetailedModelApplication(t, app1ID, givenTenant(), "App 1", "App desc 1")
  1131  	appModel2 := fixDetailedModelApplication(t, app2ID, givenTenant(), "App 2", "App desc 2")
  1132  
  1133  	suite := testdb.RepoListTestSuite{
  1134  		Name: "List Applications By IDs and scenarios",
  1135  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1136  			{
  1137  				Query: regexp.QuoteMeta(`SELECT id, app_template_id, system_number, local_tenant_id, name, description, status_condition, status_timestamp, system_status, healthcheck_url, integration_system_id, provider_name, base_url, application_namespace, labels, ready, created_at, updated_at, deleted_at, error, correlation_ids, tags, documentation_labels, tenant_business_type_id FROM public.applications 
  1138  									        WHERE id IN (SELECT "app_id" FROM public.labels 
  1139  											WHERE "app_id" IS NOT NULL 
  1140  											AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $1)) 
  1141  											AND "key" = $2 AND "value" ?| array[$3] 
  1142  											UNION SELECT "app_id" FROM public.labels 
  1143  											WHERE "app_id" IS NOT NULL AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $4)) 
  1144  											AND "key" = $5 AND "value" ?| array[$6]) 
  1145  											AND id IN ($7, $8) 
  1146  											AND (id IN (SELECT id FROM tenant_applications WHERE tenant_id = $9))`),
  1147  				Args:     []driver.Value{givenTenant(), model.ScenariosKey, scenario1, givenTenant(), model.ScenariosKey, scenario2, app1ID, app2ID, givenTenant()},
  1148  				IsSelect: true,
  1149  				ValidRowsProvider: func() []*sqlmock.Rows {
  1150  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns()).
  1151  						AddRow(appEntity1.ID, appEntity1.ApplicationTemplateID, appEntity1.SystemNumber, appEntity1.LocalTenantID, appEntity1.Name, appEntity1.Description, appEntity1.StatusCondition, appEntity1.StatusTimestamp, appEntity1.SystemStatus, appEntity1.HealthCheckURL, appEntity1.IntegrationSystemID, appEntity1.ProviderName, appEntity1.BaseURL, appEntity1.ApplicationNamespace, appEntity1.OrdLabels, appEntity1.Ready, appEntity1.CreatedAt, appEntity1.UpdatedAt, appEntity1.DeletedAt, appEntity1.Error, appEntity1.CorrelationIDs, appEntity1.Tags, appEntity1.DocumentationLabels, appEntity1.TenantBusinessTypeID).
  1152  						AddRow(appEntity2.ID, appEntity2.ApplicationTemplateID, appEntity2.SystemNumber, appEntity2.LocalTenantID, appEntity2.Name, appEntity2.Description, appEntity2.StatusCondition, appEntity2.StatusTimestamp, appEntity2.SystemStatus, appEntity2.HealthCheckURL, appEntity2.IntegrationSystemID, appEntity2.ProviderName, appEntity2.BaseURL, appEntity2.ApplicationNamespace, appEntity2.OrdLabels, appEntity2.Ready, appEntity2.CreatedAt, appEntity2.UpdatedAt, appEntity2.DeletedAt, appEntity2.Error, appEntity2.CorrelationIDs, appEntity2.Tags, appEntity2.DocumentationLabels, appEntity2.TenantBusinessTypeID),
  1153  					}
  1154  				},
  1155  				InvalidRowsProvider: func() []*sqlmock.Rows {
  1156  					return []*sqlmock.Rows{sqlmock.NewRows(fixAppColumns())}
  1157  				},
  1158  			},
  1159  		},
  1160  		ExpectedModelEntities: []interface{}{appModel1, appModel2},
  1161  		ExpectedDBEntities:    []interface{}{appEntity1, appEntity2},
  1162  		ConverterMockProvider: func() testdb.Mock {
  1163  			return &automock.EntityConverter{}
  1164  		},
  1165  		RepoConstructorFunc:       application.NewRepository,
  1166  		MethodArgs:                []interface{}{givenTenant(), []string{scenario1, scenario2}, []string{app1ID, app2ID}},
  1167  		MethodName:                "ListByScenariosAndIDs",
  1168  		DisableConverterErrorTest: true,
  1169  	}
  1170  
  1171  	suite.Run(t)
  1172  
  1173  	// Additional test - empty slice because test suite returns empty result given valid query
  1174  	t.Run("returns empty slice given no scenarios", func(t *testing.T) {
  1175  		// GIVEN
  1176  		ctx := context.TODO()
  1177  		repository := application.NewRepository(nil)
  1178  
  1179  		// WHEN
  1180  		actual, err := repository.ListByScenariosAndIDs(ctx, givenTenant(), []string{}, []string{})
  1181  
  1182  		// THEN
  1183  		assert.NoError(t, err)
  1184  		assert.Nil(t, actual)
  1185  	})
  1186  }
  1187  
  1188  func givenError() error {
  1189  	return errors.New("some error")
  1190  }