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 }