github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/runtime_context/repository_test.go (about) 1 package runtimectx_test 2 3 import ( 4 "context" 5 "database/sql/driver" 6 "regexp" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 11 "github.com/kyma-incubator/compass/components/director/pkg/pagination" 12 13 "github.com/DATA-DOG/go-sqlmock" 14 runtimectx "github.com/kyma-incubator/compass/components/director/internal/domain/runtime_context" 15 "github.com/kyma-incubator/compass/components/director/internal/domain/runtime_context/automock" 16 "github.com/kyma-incubator/compass/components/director/internal/labelfilter" 17 "github.com/kyma-incubator/compass/components/director/internal/model" 18 "github.com/kyma-incubator/compass/components/director/internal/repo/testdb" 19 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 20 "github.com/stretchr/testify/require" 21 ) 22 23 func TestPgRepository_GetByID(t *testing.T) { 24 runtimeCtxModel := fixModelRuntimeCtx() 25 runtimeCtxEntity := fixEntityRuntimeCtx() 26 27 suite := testdb.RepoGetTestSuite{ 28 Name: "Get Runtime Context By ID", 29 SQLQueryDetails: []testdb.SQLQueryDetails{ 30 { 31 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE id = $1 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $2))`), 32 Args: []driver.Value{runtimeCtxID, tenantID}, 33 IsSelect: true, 34 ValidRowsProvider: func() []*sqlmock.Rows { 35 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).AddRow(runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value)} 36 }, 37 InvalidRowsProvider: func() []*sqlmock.Rows { 38 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 39 }, 40 }, 41 }, 42 ConverterMockProvider: func() testdb.Mock { 43 return &automock.EntityConverter{} 44 }, 45 RepoConstructorFunc: runtimectx.NewRepository, 46 ExpectedModelEntity: runtimeCtxModel, 47 ExpectedDBEntity: runtimeCtxEntity, 48 MethodArgs: []interface{}{tenantID, runtimeCtxID}, 49 DisableConverterErrorTest: true, 50 } 51 52 suite.Run(t) 53 } 54 55 func TestPgRepository_GetGlobalByID(t *testing.T) { 56 runtimeCtxModel := fixModelRuntimeCtx() 57 runtimeCtxEntity := fixEntityRuntimeCtx() 58 59 suite := testdb.RepoGetTestSuite{ 60 Name: "Get Runtime Context Globally by ID", 61 SQLQueryDetails: []testdb.SQLQueryDetails{ 62 { 63 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE id = $1`), 64 Args: []driver.Value{runtimeCtxID}, 65 IsSelect: true, 66 ValidRowsProvider: func() []*sqlmock.Rows { 67 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).AddRow(runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value)} 68 }, 69 InvalidRowsProvider: func() []*sqlmock.Rows { 70 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 71 }, 72 }, 73 }, 74 ConverterMockProvider: func() testdb.Mock { 75 return &automock.EntityConverter{} 76 }, 77 RepoConstructorFunc: runtimectx.NewRepository, 78 ExpectedModelEntity: runtimeCtxModel, 79 ExpectedDBEntity: runtimeCtxEntity, 80 MethodName: "GetGlobalByID", 81 MethodArgs: []interface{}{runtimeCtxID}, 82 DisableConverterErrorTest: true, 83 } 84 85 suite.Run(t) 86 } 87 88 func TestPgRepository_GetByRuntimeID(t *testing.T) { 89 runtimeCtxModel := fixModelRuntimeCtx() 90 runtimeCtxEntity := fixEntityRuntimeCtx() 91 92 suite := testdb.RepoGetTestSuite{ 93 Name: "Get Runtime Context By runtime ID", 94 SQLQueryDetails: []testdb.SQLQueryDetails{ 95 { 96 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE runtime_id = $1 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $2))`), 97 Args: []driver.Value{runtimeID, tenantID}, 98 IsSelect: true, 99 ValidRowsProvider: func() []*sqlmock.Rows { 100 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).AddRow(runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value)} 101 }, 102 InvalidRowsProvider: func() []*sqlmock.Rows { 103 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 104 }, 105 }, 106 }, 107 ConverterMockProvider: func() testdb.Mock { 108 return &automock.EntityConverter{} 109 }, 110 RepoConstructorFunc: runtimectx.NewRepository, 111 ExpectedModelEntity: runtimeCtxModel, 112 ExpectedDBEntity: runtimeCtxEntity, 113 MethodName: "GetByRuntimeID", 114 MethodArgs: []interface{}{tenantID, runtimeID}, 115 DisableConverterErrorTest: true, 116 } 117 118 suite.Run(t) 119 } 120 121 func TestPgRepository_GetForRuntime(t *testing.T) { 122 runtimeCtxModel := fixModelRuntimeCtx() 123 runtimeCtxEntity := fixEntityRuntimeCtx() 124 125 suite := testdb.RepoGetTestSuite{ 126 Name: "Get RuntimeContext For Runtime", 127 SQLQueryDetails: []testdb.SQLQueryDetails{ 128 { 129 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE id = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $3))`), 130 Args: []driver.Value{runtimeCtxID, runtimeID, tenantID}, 131 IsSelect: true, 132 ValidRowsProvider: func() []*sqlmock.Rows { 133 return []*sqlmock.Rows{ 134 sqlmock.NewRows(fixColumns). 135 AddRow(runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value), 136 } 137 }, 138 InvalidRowsProvider: func() []*sqlmock.Rows { 139 return []*sqlmock.Rows{ 140 sqlmock.NewRows(fixColumns), 141 } 142 }, 143 }, 144 }, 145 ConverterMockProvider: func() testdb.Mock { 146 return &automock.EntityConverter{} 147 }, 148 RepoConstructorFunc: runtimectx.NewRepository, 149 ExpectedModelEntity: runtimeCtxModel, 150 ExpectedDBEntity: runtimeCtxEntity, 151 MethodArgs: []interface{}{tenantID, runtimeCtxID, runtimeID}, 152 MethodName: "GetForRuntime", 153 DisableConverterErrorTest: true, 154 } 155 156 suite.Run(t) 157 } 158 159 func TestPgRepository_GetByFiltersAndID(t *testing.T) { 160 runtimeCtxModel := fixModelRuntimeCtx() 161 runtimeCtxEntity := fixEntityRuntimeCtx() 162 163 suite := testdb.RepoGetTestSuite{ 164 Name: "Get Runtime Context By Filters and ID", 165 SQLQueryDetails: []testdb.SQLQueryDetails{ 166 { 167 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE id = $1 168 AND id IN (SELECT "runtime_context_id" FROM public.labels WHERE "runtime_context_id" IS NOT NULL AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2)) AND "key" = $3 AND "value" ?| array[$4]) 169 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $5))`), 170 Args: []driver.Value{runtimeCtxID, tenantID, model.ScenariosKey, "scenario", tenantID}, 171 IsSelect: true, 172 ValidRowsProvider: func() []*sqlmock.Rows { 173 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).AddRow(runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value)} 174 }, 175 InvalidRowsProvider: func() []*sqlmock.Rows { 176 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 177 }, 178 }, 179 }, 180 ConverterMockProvider: func() testdb.Mock { 181 return &automock.EntityConverter{} 182 }, 183 RepoConstructorFunc: runtimectx.NewRepository, 184 ExpectedModelEntity: runtimeCtxModel, 185 ExpectedDBEntity: runtimeCtxEntity, 186 MethodName: "GetByFiltersAndID", 187 MethodArgs: []interface{}{tenantID, runtimeCtxID, []*labelfilter.LabelFilter{labelfilter.NewForKeyWithQuery(model.ScenariosKey, `$[*] ? ( @ == "scenario" )`)}}, 188 DisableConverterErrorTest: true, 189 } 190 191 suite.Run(t) 192 } 193 194 func TestPgRepository_GetByFiltersGlobal_ShouldReturnRuntimeContextModelForRuntimeContextEntity(t *testing.T) { 195 // GIVEN 196 runtimeCtxModel := fixModelRuntimeCtx() 197 runtimeCtxEntity := fixEntityRuntimeCtx() 198 199 sqlxDB, sqlMock := testdb.MockDatabase(t) 200 defer sqlMock.AssertExpectations(t) 201 202 rows := sqlmock.NewRows(fixColumns).AddRow(runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value) 203 204 sqlMock.ExpectQuery(`^SELECT (.+) FROM public.runtime_contexts WHERE id IN \(SELECT "runtime_context_id" FROM public\.labels WHERE "runtime_context_id" IS NOT NULL AND "key" = \$1\)$`). 205 WithArgs("someKey"). 206 WillReturnRows(rows) 207 208 ctx := persistence.SaveToContext(context.TODO(), sqlxDB) 209 210 mockConverter := &automock.EntityConverter{} 211 mockConverter.On("FromEntity", runtimeCtxEntity).Return(runtimeCtxModel, nil).Once() 212 pgRepository := runtimectx.NewRepository(mockConverter) 213 214 // WHEN 215 filters := []*labelfilter.LabelFilter{labelfilter.NewForKey("someKey")} 216 modelRuntimeCtx, err := pgRepository.GetByFiltersGlobal(ctx, filters) 217 218 // THEN 219 require.NoError(t, err) 220 require.Equal(t, runtimeCtxModel, modelRuntimeCtx) 221 mockConverter.AssertExpectations(t) 222 } 223 224 func TestPgRepository_List(t *testing.T) { 225 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 226 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 227 runtimeCtxEntity1 := fixEntityRuntimeCtxWithID(runtimeCtx1ID) 228 runtimeCtxEntity2 := fixEntityRuntimeCtxWithID(runtimeCtx2ID) 229 230 runtimeCtxModel1 := fixModelRuntimeCtxWithID(runtimeCtx1ID) 231 runtimeCtxModel2 := fixModelRuntimeCtxWithID(runtimeCtx2ID) 232 233 suite := testdb.RepoListPageableTestSuite{ 234 Name: "List Runtime Contexts", 235 SQLQueryDetails: []testdb.SQLQueryDetails{ 236 { 237 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE (runtime_id = $1 238 AND id IN (SELECT "runtime_context_id" FROM public.labels WHERE "runtime_context_id" IS NOT NULL AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2)) AND "key" = $3 AND "value" ?| array[$4]) 239 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $5))) ORDER BY id LIMIT 2 OFFSET 0`), 240 Args: []driver.Value{runtimeID, tenantID, model.ScenariosKey, "scenario", tenantID}, 241 IsSelect: true, 242 ValidRowsProvider: func() []*sqlmock.Rows { 243 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 244 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 245 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 246 } 247 }, 248 }, 249 { 250 Query: regexp.QuoteMeta(`SELECT COUNT(*) FROM public.runtime_contexts WHERE (runtime_id = $1 251 AND id IN (SELECT "runtime_context_id" FROM public.labels WHERE "runtime_context_id" IS NOT NULL AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2)) AND "key" = $3 AND "value" ?| array[$4]) 252 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $5)))`), 253 Args: []driver.Value{runtimeID, tenantID, model.ScenariosKey, "scenario", tenantID}, 254 IsSelect: true, 255 ValidRowsProvider: func() []*sqlmock.Rows { 256 return []*sqlmock.Rows{sqlmock.NewRows([]string{"count"}).AddRow(2)} 257 }, 258 }, 259 }, 260 Pages: []testdb.PageDetails{ 261 { 262 ExpectedModelEntities: []interface{}{runtimeCtxModel1, runtimeCtxModel2}, 263 ExpectedDBEntities: []interface{}{runtimeCtxEntity1, runtimeCtxEntity2}, 264 ExpectedPage: &model.RuntimeContextPage{ 265 Data: []*model.RuntimeContext{runtimeCtxModel1, runtimeCtxModel2}, 266 PageInfo: &pagination.Page{ 267 StartCursor: "", 268 EndCursor: "", 269 HasNextPage: false, 270 }, 271 TotalCount: 2, 272 }, 273 }, 274 }, 275 ConverterMockProvider: func() testdb.Mock { 276 return &automock.EntityConverter{} 277 }, 278 RepoConstructorFunc: runtimectx.NewRepository, 279 MethodArgs: []interface{}{runtimeID, tenantID, []*labelfilter.LabelFilter{labelfilter.NewForKeyWithQuery(model.ScenariosKey, `$[*] ? ( @ == "scenario" )`)}, 2, ""}, 280 MethodName: "List", 281 DisableConverterErrorTest: true, 282 } 283 284 suite.Run(t) 285 } 286 287 func TestPgRepository_ListByRuntimeIDs(t *testing.T) { 288 pageSize := 1 289 cursor := "" 290 291 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 292 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 293 runtimeCtxEntity1 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, onePageRuntimeID) 294 runtimeCtxEntity2 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, multiplePagesRuntimeID) 295 296 runtimeCtxModel1 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, onePageRuntimeID) 297 runtimeCtxModel2 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, multiplePagesRuntimeID) 298 299 suite := testdb.RepoListPageableTestSuite{ 300 Name: "ListByRuntimeIDs Runtime Contexts", 301 SQLQueryDetails: []testdb.SQLQueryDetails{ 302 { 303 Query: regexp.QuoteMeta(`(SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $1)) AND runtime_id = $2 ORDER BY runtime_id ASC, id ASC LIMIT $3 OFFSET $4) 304 UNION 305 (SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $5)) AND runtime_id = $6 ORDER BY runtime_id ASC, id ASC LIMIT $7 OFFSET $8) 306 UNION 307 (SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $9)) AND runtime_id = $10 ORDER BY runtime_id ASC, id ASC LIMIT $11 OFFSET $12)`), 308 Args: []driver.Value{tenantID, emptyPageRuntimeID, pageSize, 0, tenantID, onePageRuntimeID, pageSize, 0, tenantID, multiplePagesRuntimeID, pageSize, 0}, 309 IsSelect: true, 310 ValidRowsProvider: func() []*sqlmock.Rows { 311 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 312 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 313 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 314 } 315 }, 316 }, 317 { 318 Query: regexp.QuoteMeta(`SELECT runtime_id AS id, COUNT(*) AS total_count FROM public.runtime_contexts WHERE (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $1)) GROUP BY runtime_id ORDER BY runtime_id ASC`), 319 Args: []driver.Value{tenantID}, 320 IsSelect: true, 321 ValidRowsProvider: func() []*sqlmock.Rows { 322 return []*sqlmock.Rows{sqlmock.NewRows([]string{"id", "total_count"}).AddRow(emptyPageRuntimeID, 0).AddRow(onePageRuntimeID, 1).AddRow(multiplePagesRuntimeID, 2)} 323 }, 324 }, 325 }, 326 Pages: []testdb.PageDetails{ 327 { 328 ExpectedModelEntities: nil, 329 ExpectedDBEntities: nil, 330 ExpectedPage: &model.RuntimeContextPage{ 331 Data: nil, 332 PageInfo: &pagination.Page{ 333 StartCursor: "", 334 EndCursor: "", 335 HasNextPage: false, 336 }, 337 TotalCount: 0, 338 }, 339 }, 340 { 341 ExpectedModelEntities: []interface{}{runtimeCtxModel1}, 342 ExpectedDBEntities: []interface{}{runtimeCtxEntity1}, 343 ExpectedPage: &model.RuntimeContextPage{ 344 Data: []*model.RuntimeContext{runtimeCtxModel1}, 345 PageInfo: &pagination.Page{ 346 StartCursor: "", 347 EndCursor: "", 348 HasNextPage: false, 349 }, 350 TotalCount: 1, 351 }, 352 }, 353 { 354 ExpectedModelEntities: []interface{}{runtimeCtxModel2}, 355 ExpectedDBEntities: []interface{}{runtimeCtxEntity2}, 356 ExpectedPage: &model.RuntimeContextPage{ 357 Data: []*model.RuntimeContext{runtimeCtxModel2}, 358 PageInfo: &pagination.Page{ 359 StartCursor: "", 360 EndCursor: pagination.EncodeNextOffsetCursor(0, pageSize), 361 HasNextPage: true, 362 }, 363 TotalCount: 2, 364 }, 365 }, 366 }, 367 ConverterMockProvider: func() testdb.Mock { 368 return &automock.EntityConverter{} 369 }, 370 RepoConstructorFunc: runtimectx.NewRepository, 371 MethodArgs: []interface{}{tenantID, []string{emptyPageRuntimeID, onePageRuntimeID, multiplePagesRuntimeID}, pageSize, cursor}, 372 MethodName: "ListByRuntimeIDs", 373 DisableConverterErrorTest: true, 374 } 375 376 suite.Run(t) 377 } 378 379 func TestPgRepository_ListByScenariosAndRuntimeIDs(t *testing.T) { 380 scenario1 := "scenario-1" 381 scenario2 := "scenario-2" 382 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 383 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 384 runtimeCtxEntity1 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, runtimeID) 385 runtimeCtxEntity2 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, runtimeID2) 386 387 runtimeCtxModel1 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, runtimeID) 388 runtimeCtxModel2 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, runtimeID2) 389 390 suite := testdb.RepoListTestSuite{ 391 Name: "ListByScenariosAndRuntimeIDs Runtime Contexts", 392 SQLQueryDetails: []testdb.SQLQueryDetails{ 393 { 394 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts 395 WHERE id IN (SELECT "runtime_context_id" FROM public.labels 396 WHERE "runtime_context_id" IS NOT NULL 397 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $1)) 398 AND "key" = $2 AND "value" ?| array[$3] UNION SELECT "runtime_context_id" FROM public.labels WHERE "runtime_context_id" IS NOT NULL 399 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 400 AND "value" ?| array[$6]) AND runtime_id IN ($7, $8) 401 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $9))`), 402 Args: []driver.Value{tenantID, model.ScenariosKey, scenario1, tenantID, model.ScenariosKey, scenario2, runtimeID, runtimeID2, tenantID}, 403 IsSelect: true, 404 ValidRowsProvider: func() []*sqlmock.Rows { 405 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 406 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 407 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 408 } 409 }, 410 InvalidRowsProvider: func() []*sqlmock.Rows { 411 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 412 }, 413 }, 414 }, 415 ExpectedModelEntities: []interface{}{runtimeCtxModel1, runtimeCtxModel2}, 416 ExpectedDBEntities: []interface{}{runtimeCtxEntity1, runtimeCtxEntity2}, 417 ConverterMockProvider: func() testdb.Mock { 418 return &automock.EntityConverter{} 419 }, 420 RepoConstructorFunc: runtimectx.NewRepository, 421 MethodArgs: []interface{}{tenantID, []string{scenario1, scenario2}, []string{runtimeID, runtimeID2}}, 422 MethodName: "ListByScenariosAndRuntimeIDs", 423 DisableConverterErrorTest: true, 424 } 425 426 suite.Run(t) 427 428 // Additional test - empty slice because test suite returns empty result given valid query 429 t.Run("returns empty slice given no scenarios", func(t *testing.T) { 430 // GIVEN 431 ctx := context.TODO() 432 repository := runtimectx.NewRepository(nil) 433 434 // WHEN 435 actual, err := repository.ListByScenariosAndRuntimeIDs(ctx, tenantID, []string{}, []string{}) 436 437 // THEN 438 assert.NoError(t, err) 439 assert.Nil(t, actual) 440 }) 441 } 442 443 func TestPgRepository_ListByScenarios(t *testing.T) { 444 scenario1 := "scenario-1" 445 scenario2 := "scenario-2" 446 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 447 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 448 runtimeCtxEntity1 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, runtimeID) 449 runtimeCtxEntity2 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, runtimeID2) 450 451 runtimeCtxModel1 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, runtimeID) 452 runtimeCtxModel2 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, runtimeID2) 453 454 suite := testdb.RepoListTestSuite{ 455 Name: "ListByScenarios Runtime Contexts", 456 SQLQueryDetails: []testdb.SQLQueryDetails{ 457 { 458 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts 459 WHERE id IN (SELECT "runtime_context_id" FROM public.labels 460 WHERE "runtime_context_id" IS NOT NULL 461 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $1)) 462 AND "key" = $2 AND "value" ?| array[$3] UNION SELECT "runtime_context_id" FROM public.labels WHERE "runtime_context_id" IS NOT NULL 463 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $4)) AND "key" = $5 464 AND "value" ?| array[$6]) 465 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $7))`), 466 Args: []driver.Value{tenantID, model.ScenariosKey, scenario1, tenantID, model.ScenariosKey, scenario2, tenantID}, 467 IsSelect: true, 468 ValidRowsProvider: func() []*sqlmock.Rows { 469 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 470 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 471 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 472 } 473 }, 474 InvalidRowsProvider: func() []*sqlmock.Rows { 475 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 476 }, 477 }, 478 }, 479 ExpectedModelEntities: []interface{}{runtimeCtxModel1, runtimeCtxModel2}, 480 ExpectedDBEntities: []interface{}{runtimeCtxEntity1, runtimeCtxEntity2}, 481 ConverterMockProvider: func() testdb.Mock { 482 return &automock.EntityConverter{} 483 }, 484 RepoConstructorFunc: runtimectx.NewRepository, 485 MethodArgs: []interface{}{tenantID, []string{scenario1, scenario2}}, 486 MethodName: "ListByScenarios", 487 DisableConverterErrorTest: true, 488 } 489 490 suite.Run(t) 491 492 // Additional test - empty slice because test suite returns empty result given valid query 493 t.Run("returns empty slice given no scenarios", func(t *testing.T) { 494 // GIVEN 495 ctx := context.TODO() 496 repository := runtimectx.NewRepository(nil) 497 498 // WHEN 499 actual, err := repository.ListByScenarios(ctx, tenantID, []string{}) 500 501 // THEN 502 assert.NoError(t, err) 503 assert.Nil(t, actual) 504 }) 505 } 506 507 func TestPgRepository_ListByIDs(t *testing.T) { 508 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 509 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 510 runtimeCtxEntity1 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, runtimeID) 511 runtimeCtxEntity2 := fixEntityRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, runtimeID2) 512 513 runtimeCtxModel1 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx1ID, runtimeID) 514 runtimeCtxModel2 := fixModelRuntimeCtxWithIDAndRuntimeID(runtimeCtx2ID, runtimeID2) 515 516 suite := testdb.RepoListTestSuite{ 517 Name: "ListByIDs Runtime Contexts", 518 SQLQueryDetails: []testdb.SQLQueryDetails{ 519 { 520 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE id IN ($1, $2) AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $3))`), 521 Args: []driver.Value{runtimeCtx1ID, runtimeCtx2ID, tenantID}, 522 IsSelect: true, 523 ValidRowsProvider: func() []*sqlmock.Rows { 524 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 525 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 526 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 527 } 528 }, 529 InvalidRowsProvider: func() []*sqlmock.Rows { 530 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 531 }, 532 }, 533 }, 534 ExpectedModelEntities: []interface{}{runtimeCtxModel1, runtimeCtxModel2}, 535 ExpectedDBEntities: []interface{}{runtimeCtxEntity1, runtimeCtxEntity2}, 536 ConverterMockProvider: func() testdb.Mock { 537 return &automock.EntityConverter{} 538 }, 539 RepoConstructorFunc: runtimectx.NewRepository, 540 MethodArgs: []interface{}{tenantID, []string{runtimeCtx1ID, runtimeCtx2ID}}, 541 MethodName: "ListByIDs", 542 DisableConverterErrorTest: true, 543 } 544 545 suite.Run(t) 546 547 // Additional test - empty slice because test suite returns empty result given valid query 548 t.Run("returns empty slice given no scenarios", func(t *testing.T) { 549 // GIVEN 550 ctx := context.TODO() 551 repository := runtimectx.NewRepository(nil) 552 553 // WHEN 554 actual, err := repository.ListByIDs(ctx, tenantID, []string{}) 555 556 // THEN 557 assert.NoError(t, err) 558 assert.Nil(t, actual) 559 }) 560 } 561 func TestPgRepository_ListAll(t *testing.T) { 562 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 563 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 564 runtimeCtxEntity1 := fixEntityRuntimeCtxWithID(runtimeCtx1ID) 565 runtimeCtxEntity2 := fixEntityRuntimeCtxWithID(runtimeCtx2ID) 566 567 runtimeCtxModel1 := fixModelRuntimeCtxWithID(runtimeCtx1ID) 568 runtimeCtxModel2 := fixModelRuntimeCtxWithID(runtimeCtx2ID) 569 570 suite := testdb.RepoListTestSuite{ 571 Name: "List Runtime Contexts", 572 SQLQueryDetails: []testdb.SQLQueryDetails{ 573 { 574 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $1))`), 575 Args: []driver.Value{tenantID}, 576 IsSelect: true, 577 ValidRowsProvider: func() []*sqlmock.Rows { 578 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 579 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 580 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 581 } 582 }, 583 InvalidRowsProvider: func() []*sqlmock.Rows { 584 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 585 }, 586 }, 587 }, 588 ConverterMockProvider: func() testdb.Mock { 589 return &automock.EntityConverter{} 590 }, 591 ExpectedDBEntities: []interface{}{runtimeCtxEntity1, runtimeCtxEntity2}, 592 ExpectedModelEntities: []interface{}{runtimeCtxModel1, runtimeCtxModel2}, 593 RepoConstructorFunc: runtimectx.NewRepository, 594 MethodArgs: []interface{}{tenantID}, 595 MethodName: "ListAll", 596 DisableConverterErrorTest: true, 597 } 598 599 suite.Run(t) 600 } 601 602 func TestPgRepository_ListAllForRuntime(t *testing.T) { 603 runtimeCtx1ID := "aec0e9c5-06da-4625-9f8a-bda17ab8c3b9" 604 runtimeCtx2ID := "ccdbef8f-b97a-490c-86e2-2bab2862a6e4" 605 runtimeCtxEntity1 := fixEntityRuntimeCtxWithID(runtimeCtx1ID) 606 runtimeCtxEntity2 := fixEntityRuntimeCtxWithID(runtimeCtx2ID) 607 608 runtimeCtxModel1 := fixModelRuntimeCtxWithID(runtimeCtx1ID) 609 runtimeCtxModel2 := fixModelRuntimeCtxWithID(runtimeCtx2ID) 610 611 suite := testdb.RepoListTestSuite{ 612 Name: "List Runtime Contexts", 613 SQLQueryDetails: []testdb.SQLQueryDetails{ 614 { 615 Query: regexp.QuoteMeta(`SELECT id, runtime_id, key, value FROM public.runtime_contexts WHERE runtime_id = $1 AND 616 (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $2))`), 617 Args: []driver.Value{runtimeID, tenantID}, 618 IsSelect: true, 619 ValidRowsProvider: func() []*sqlmock.Rows { 620 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns). 621 AddRow(runtimeCtxEntity1.ID, runtimeCtxEntity1.RuntimeID, runtimeCtxEntity1.Key, runtimeCtxEntity1.Value). 622 AddRow(runtimeCtxEntity2.ID, runtimeCtxEntity2.RuntimeID, runtimeCtxEntity2.Key, runtimeCtxEntity2.Value), 623 } 624 }, 625 InvalidRowsProvider: func() []*sqlmock.Rows { 626 return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)} 627 }, 628 }, 629 }, 630 ConverterMockProvider: func() testdb.Mock { 631 return &automock.EntityConverter{} 632 }, 633 ExpectedDBEntities: []interface{}{runtimeCtxEntity1, runtimeCtxEntity2}, 634 ExpectedModelEntities: []interface{}{runtimeCtxModel1, runtimeCtxModel2}, 635 RepoConstructorFunc: runtimectx.NewRepository, 636 MethodArgs: []interface{}{tenantID, runtimeID}, 637 MethodName: "ListAllForRuntime", 638 DisableConverterErrorTest: true, 639 } 640 641 suite.Run(t) 642 } 643 644 func TestPgRepository_Create(t *testing.T) { 645 var nilRuntimeCtxModel *model.RuntimeContext 646 runtimeCtxModel := fixModelRuntimeCtx() 647 runtimeCtxEntity := fixEntityRuntimeCtx() 648 649 suite := testdb.RepoCreateTestSuite{ 650 Name: "Create Runtime Context", 651 SQLQueryDetails: []testdb.SQLQueryDetails{ 652 { 653 Query: `^INSERT INTO public.runtime_contexts \(.+\) VALUES \(.+\)$`, 654 Args: []driver.Value{runtimeCtxModel.ID, runtimeCtxModel.RuntimeID, runtimeCtxModel.Key, runtimeCtxModel.Value}, 655 ValidResult: sqlmock.NewResult(-1, 1), 656 }, 657 { 658 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_runtime_contexts ( tenant_id, id, owner ) (SELECT parents.id AS tenant_id, ? as id, ? AS owner FROM parents)`), 659 Args: []driver.Value{tenantID, runtimeCtxModel.ID, true}, 660 ValidResult: sqlmock.NewResult(-1, 1), 661 }, 662 }, 663 ConverterMockProvider: func() testdb.Mock { 664 return &automock.EntityConverter{} 665 }, 666 RepoConstructorFunc: runtimectx.NewRepository, 667 ModelEntity: runtimeCtxModel, 668 DBEntity: runtimeCtxEntity, 669 NilModelEntity: nilRuntimeCtxModel, 670 TenantID: tenantID, 671 DisableConverterErrorTest: true, 672 IsTopLevelEntity: true, 673 } 674 675 suite.Run(t) 676 } 677 678 func TestPgRepository_Update(t *testing.T) { 679 var nilRuntimeCtxModel *model.RuntimeContext 680 runtimeCtxModel := fixModelRuntimeCtx() 681 runtimeCtxEntity := fixEntityRuntimeCtx() 682 683 suite := testdb.RepoUpdateTestSuite{ 684 Name: "Update Runtime Context", 685 SQLQueryDetails: []testdb.SQLQueryDetails{ 686 { 687 Query: regexp.QuoteMeta(`UPDATE public.runtime_contexts SET key = ?, value = ? WHERE id = ? AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = ? AND owner = true))`), 688 Args: []driver.Value{runtimeCtxModel.Key, runtimeCtxModel.Value, runtimeCtxModel.ID, tenantID}, 689 ValidResult: sqlmock.NewResult(-1, 1), 690 InvalidResult: sqlmock.NewResult(-1, 0), 691 }, 692 }, 693 ConverterMockProvider: func() testdb.Mock { 694 return &automock.EntityConverter{} 695 }, 696 RepoConstructorFunc: runtimectx.NewRepository, 697 ModelEntity: runtimeCtxModel, 698 DBEntity: runtimeCtxEntity, 699 NilModelEntity: nilRuntimeCtxModel, 700 TenantID: tenantID, 701 DisableConverterErrorTest: true, 702 } 703 704 suite.Run(t) 705 } 706 707 func TestPgRepository_Delete(t *testing.T) { 708 suite := testdb.RepoDeleteTestSuite{ 709 Name: "Runtime Context Delete", 710 SQLQueryDetails: []testdb.SQLQueryDetails{ 711 { 712 Query: regexp.QuoteMeta(`DELETE FROM public.runtime_contexts WHERE id = $1 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $2 AND owner = true))`), 713 Args: []driver.Value{runtimeCtxID, tenantID}, 714 ValidResult: sqlmock.NewResult(-1, 1), 715 InvalidResult: sqlmock.NewResult(-1, 2), 716 }, 717 }, 718 ConverterMockProvider: func() testdb.Mock { 719 return &automock.EntityConverter{} 720 }, 721 RepoConstructorFunc: runtimectx.NewRepository, 722 MethodArgs: []interface{}{tenantID, runtimeCtxID}, 723 } 724 725 suite.Run(t) 726 } 727 728 func TestPgRepository_Exist(t *testing.T) { 729 suite := testdb.RepoExistTestSuite{ 730 Name: "Runtime Context Exists", 731 SQLQueryDetails: []testdb.SQLQueryDetails{ 732 { 733 Query: regexp.QuoteMeta(`SELECT 1 FROM public.runtime_contexts WHERE id = $1 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $2))`), 734 Args: []driver.Value{runtimeCtxID, tenantID}, 735 IsSelect: true, 736 ValidRowsProvider: func() []*sqlmock.Rows { 737 return []*sqlmock.Rows{testdb.RowWhenObjectExist()} 738 }, 739 InvalidRowsProvider: func() []*sqlmock.Rows { 740 return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()} 741 }, 742 }, 743 }, 744 ConverterMockProvider: func() testdb.Mock { 745 return &automock.EntityConverter{} 746 }, 747 RepoConstructorFunc: runtimectx.NewRepository, 748 TargetID: runtimeCtxID, 749 TenantID: tenantID, 750 MethodName: "Exists", 751 MethodArgs: []interface{}{tenantID, runtimeCtxID}, 752 } 753 754 suite.Run(t) 755 } 756 757 func TestPgRepository_ExistsByRuntimeID(t *testing.T) { 758 suite := testdb.RepoExistTestSuite{ 759 Name: "Runtime Context Exists By Runtime ID", 760 SQLQueryDetails: []testdb.SQLQueryDetails{ 761 { 762 Query: regexp.QuoteMeta(`SELECT 1 FROM public.runtime_contexts WHERE runtime_id = $1 AND (id IN (SELECT id FROM tenant_runtime_contexts WHERE tenant_id = $2))`), 763 Args: []driver.Value{runtimeID, tenantID}, 764 IsSelect: true, 765 ValidRowsProvider: func() []*sqlmock.Rows { 766 return []*sqlmock.Rows{testdb.RowWhenObjectExist()} 767 }, 768 InvalidRowsProvider: func() []*sqlmock.Rows { 769 return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()} 770 }, 771 }, 772 }, 773 ConverterMockProvider: func() testdb.Mock { 774 return &automock.EntityConverter{} 775 }, 776 RepoConstructorFunc: runtimectx.NewRepository, 777 TargetID: runtimeCtxID, 778 TenantID: tenantID, 779 MethodName: "ExistsByRuntimeID", 780 MethodArgs: []interface{}{tenantID, runtimeID}, 781 } 782 783 suite.Run(t) 784 }