github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/update_test.go (about) 1 package repo_test 2 3 import ( 4 "context" 5 "fmt" 6 "regexp" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/DATA-DOG/go-sqlmock" 12 "github.com/kyma-incubator/compass/components/director/internal/repo" 13 "github.com/kyma-incubator/compass/components/director/internal/repo/testdb" 14 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 15 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 16 "github.com/kyma-incubator/compass/components/director/pkg/resource" 17 "github.com/lib/pq" 18 "github.com/stretchr/testify/assert" 19 "github.com/stretchr/testify/require" 20 ) 21 22 func TestUpdaterGlobal(t *testing.T) { 23 t.Run("Global Update", func(t *testing.T) { 24 sut := repo.NewUpdaterGlobal(UserType, "users", []string{"first_name", "last_name", "age"}, []string{"id"}) 25 givenUser := User{ 26 ID: "given_id", 27 FirstName: "given_first_name", 28 LastName: "given_last_name", 29 Age: 55, 30 } 31 32 t.Run("success", func(t *testing.T) { 33 // GIVEN 34 db, mock := testdb.MockDatabase(t) 35 ctx := persistence.SaveToContext(context.TODO(), db) 36 defer mock.AssertExpectations(t) 37 38 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ? WHERE id = ?")). 39 WithArgs("given_first_name", "given_last_name", 55, "given_id").WillReturnResult(sqlmock.NewResult(0, 1)) 40 // WHEN 41 err := sut.UpdateSingleGlobal(ctx, givenUser) 42 // THEN 43 require.NoError(t, err) 44 }) 45 46 t.Run("success when no id column", func(t *testing.T) { 47 // GIVEN 48 sut := repo.NewUpdaterGlobal(UserType, "users", []string{"first_name", "last_name", "age"}, []string{}) 49 db, mock := testdb.MockDatabase(t) 50 ctx := persistence.SaveToContext(context.TODO(), db) 51 defer mock.AssertExpectations(t) 52 53 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ?")). 54 WithArgs("given_first_name", "given_last_name", 55).WillReturnResult(sqlmock.NewResult(0, 1)) 55 // WHEN 56 err := sut.UpdateSingleGlobal(ctx, givenUser) 57 // THEN 58 require.NoError(t, err) 59 }) 60 61 t.Run("returns error when operation on db failed", func(t *testing.T) { 62 // GIVEN 63 db, mock := testdb.MockDatabase(t) 64 ctx := persistence.SaveToContext(context.TODO(), db) 65 defer mock.AssertExpectations(t) 66 mock.ExpectExec("UPDATE users .*"). 67 WillReturnError(someError()) 68 // WHEN 69 err := sut.UpdateSingleGlobal(ctx, givenUser) 70 // THEN 71 require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 72 }) 73 74 t.Run("returns non unique error", func(t *testing.T) { 75 // GIVEN 76 db, mock := testdb.MockDatabase(t) 77 ctx := persistence.SaveToContext(context.TODO(), db) 78 defer mock.AssertExpectations(t) 79 mock.ExpectExec("UPDATE users .*"). 80 WillReturnError(&pq.Error{Code: persistence.UniqueViolation}) 81 // WHEN 82 err := sut.UpdateSingleGlobal(ctx, givenUser) 83 // THEN 84 require.True(t, apperrors.IsNotUniqueError(err)) 85 }) 86 87 t.Run("returns error if modified more than one row", func(t *testing.T) { 88 // GIVEN 89 db, mock := testdb.MockDatabase(t) 90 ctx := persistence.SaveToContext(context.TODO(), db) 91 defer mock.AssertExpectations(t) 92 93 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ? WHERE id = ?")). 94 WithArgs("given_first_name", "given_last_name", 55, "given_id").WillReturnResult(sqlmock.NewResult(0, 157)) 95 // WHEN 96 err := sut.UpdateSingleGlobal(ctx, givenUser) 97 // THEN 98 require.Error(t, err) 99 assert.Contains(t, err.Error(), "should update single row, but updated 157 rows") 100 }) 101 102 t.Run("returns error if does not modified any row", func(t *testing.T) { 103 // GIVEN 104 db, mock := testdb.MockDatabase(t) 105 ctx := persistence.SaveToContext(context.TODO(), db) 106 defer mock.AssertExpectations(t) 107 108 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ? WHERE id = ?")). 109 WithArgs("given_first_name", "given_last_name", 55, "given_id").WillReturnResult(sqlmock.NewResult(0, 0)) 110 // WHEN 111 err := sut.UpdateSingleGlobal(ctx, givenUser) 112 // THEN 113 require.Error(t, err) 114 assert.Contains(t, err.Error(), "should update single row, but updated 0 rows") 115 }) 116 117 t.Run("returns error if missing persistence context", func(t *testing.T) { 118 // WHEN 119 err := sut.UpdateSingleGlobal(context.TODO(), User{}) 120 // THEN 121 require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error()) 122 }) 123 124 t.Run("returns error if entity is nil", func(t *testing.T) { 125 // WHEN 126 err := sut.UpdateSingleGlobal(context.TODO(), nil) 127 // THEN 128 require.EqualError(t, err, apperrors.NewInternalError("item cannot be nil").Error()) 129 }) 130 }) 131 132 t.Run("Update with embedded tenant", func(t *testing.T) { 133 tests := []struct { 134 Name string 135 AdditionalCondition string 136 Method func(updater repo.UpdaterGlobal) func(ctx context.Context, dbEntity interface{}) error 137 }{ 138 { 139 Name: "UpdateSingleGlobal", 140 Method: func(updater repo.UpdaterGlobal) func(ctx context.Context, dbEntity interface{}) error { 141 return updater.UpdateSingleGlobal 142 }, 143 }, 144 { 145 Name: "UpdateSingleWithVersionGlobal", 146 AdditionalCondition: ", version = version+1", 147 Method: func(updater repo.UpdaterGlobal) func(ctx context.Context, dbEntity interface{}) error { 148 return updater.UpdateSingleWithVersionGlobal 149 }, 150 }, 151 } 152 153 for _, test := range tests { 154 t.Run(test.Name, func(t *testing.T) { 155 sut := repo.NewUpdaterWithEmbeddedTenant(UserType, "users", []string{"first_name", "last_name", "age"}, "tenant_id", []string{"id"}) 156 givenUser := User{ 157 ID: "given_id", 158 Tenant: "given_tenant", 159 FirstName: "given_first_name", 160 LastName: "given_last_name", 161 Age: 55, 162 } 163 164 t.Run("success", func(t *testing.T) { 165 // GIVEN 166 db, mock := testdb.MockDatabase(t) 167 ctx := persistence.SaveToContext(context.TODO(), db) 168 defer mock.AssertExpectations(t) 169 170 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ?"+test.AdditionalCondition+" WHERE id = ? AND tenant_id = ?")). 171 WithArgs("given_first_name", "given_last_name", 55, "given_id", "given_tenant").WillReturnResult(sqlmock.NewResult(0, 1)) 172 // WHEN 173 err := test.Method(sut)(ctx, givenUser) 174 // THEN 175 require.NoError(t, err) 176 }) 177 178 t.Run("success when no id column", func(t *testing.T) { 179 // GIVEN 180 sut := repo.NewUpdaterWithEmbeddedTenant(UserType, "users", []string{"first_name", "last_name", "age"}, "tenant_id", []string{}) 181 db, mock := testdb.MockDatabase(t) 182 ctx := persistence.SaveToContext(context.TODO(), db) 183 defer mock.AssertExpectations(t) 184 185 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ?"+test.AdditionalCondition+" WHERE tenant_id = ?")). 186 WithArgs("given_first_name", "given_last_name", 55, "given_tenant").WillReturnResult(sqlmock.NewResult(0, 1)) 187 // WHEN 188 err := test.Method(sut)(ctx, givenUser) 189 // THEN 190 require.NoError(t, err) 191 }) 192 193 t.Run("returns error when operation on db failed", func(t *testing.T) { 194 // GIVEN 195 db, mock := testdb.MockDatabase(t) 196 ctx := persistence.SaveToContext(context.TODO(), db) 197 defer mock.AssertExpectations(t) 198 mock.ExpectExec("UPDATE users .*"). 199 WillReturnError(someError()) 200 // WHEN 201 err := test.Method(sut)(ctx, givenUser) 202 // THEN 203 require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 204 }) 205 206 t.Run("context properly canceled", func(t *testing.T) { 207 db, mock := testdb.MockDatabase(t) 208 defer mock.AssertExpectations(t) 209 210 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond) 211 defer cancel() 212 213 ctx = persistence.SaveToContext(ctx, db) 214 215 err := test.Method(sut)(ctx, givenUser) 216 217 require.EqualError(t, err, "Internal Server Error: Maximum processing timeout reached") 218 }) 219 220 t.Run("returns non unique error", func(t *testing.T) { 221 // GIVEN 222 db, mock := testdb.MockDatabase(t) 223 ctx := persistence.SaveToContext(context.TODO(), db) 224 defer mock.AssertExpectations(t) 225 mock.ExpectExec("UPDATE users .*"). 226 WillReturnError(&pq.Error{Code: persistence.UniqueViolation}) 227 // WHEN 228 err := test.Method(sut)(ctx, givenUser) 229 // THEN 230 require.True(t, apperrors.IsNotUniqueError(err)) 231 }) 232 233 t.Run("returns error if modified more than one row", func(t *testing.T) { 234 // GIVEN 235 db, mock := testdb.MockDatabase(t) 236 ctx := persistence.SaveToContext(context.TODO(), db) 237 defer mock.AssertExpectations(t) 238 239 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ?"+test.AdditionalCondition+" WHERE id = ? AND tenant_id = ?")). 240 WithArgs("given_first_name", "given_last_name", 55, "given_id", "given_tenant").WillReturnResult(sqlmock.NewResult(0, 157)) 241 // WHEN 242 err := test.Method(sut)(ctx, givenUser) 243 // THEN 244 require.Error(t, err) 245 require.Contains(t, err.Error(), "should update single row, but updated 157 rows") 246 }) 247 248 t.Run("returns error if does not modified any row", func(t *testing.T) { 249 // GIVEN 250 db, mock := testdb.MockDatabase(t) 251 ctx := persistence.SaveToContext(context.TODO(), db) 252 defer mock.AssertExpectations(t) 253 254 mock.ExpectExec(regexp.QuoteMeta("UPDATE users SET first_name = ?, last_name = ?, age = ?"+test.AdditionalCondition+" WHERE id = ? AND tenant_id = ?")). 255 WithArgs("given_first_name", "given_last_name", 55, "given_id", "given_tenant").WillReturnResult(sqlmock.NewResult(0, 0)) 256 // WHEN 257 err := test.Method(sut)(ctx, givenUser) 258 // THEN 259 require.Error(t, err) 260 if !strings.Contains(err.Error(), apperrors.ShouldBeOwnerMsg) && !strings.Contains(err.Error(), apperrors.ConcurrentUpdateMsg) { 261 t.Errorf("unexpected error: %s", err) 262 } 263 }) 264 265 t.Run("returns error if missing persistence context", func(t *testing.T) { 266 // WHEN 267 err := test.Method(sut)(context.TODO(), User{}) 268 // THEN 269 require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error()) 270 }) 271 272 t.Run("returns error if entity is nil", func(t *testing.T) { 273 // WHEN 274 err := test.Method(sut)(context.TODO(), nil) 275 // THEN 276 require.EqualError(t, err, apperrors.NewInternalError("item cannot be nil").Error()) 277 }) 278 }) 279 } 280 }) 281 } 282 283 func TestUpdater(t *testing.T) { 284 tests := []struct { 285 Name string 286 AdditionalCondition string 287 AttachAdditionalQueries func(mock testdb.DBMock, m2mTable, tenant string) 288 Method func(updater repo.Updater) func(ctx context.Context, resourceType resource.Type, tenant string, dbEntity interface{}) error 289 }{ 290 { 291 Name: "UpdateSingle", 292 AttachAdditionalQueries: func(mock testdb.DBMock, m2mTable, tenant string) {}, 293 Method: func(updater repo.Updater) func(ctx context.Context, resourceType resource.Type, tenant string, dbEntity interface{}) error { 294 return updater.UpdateSingle 295 }, 296 }, 297 { 298 Name: "UpdateSingleWithVersion", 299 AttachAdditionalQueries: func(mock testdb.DBMock, m2mTable, tenant string) { 300 mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT 1 FROM %s WHERE id = $1 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithOwnerCheckFmt, m2mTable, "$2")))). 301 WithArgs(appID, tenant).WillReturnRows(testdb.RowWhenObjectExist()) 302 }, 303 AdditionalCondition: ", version = version+1", 304 Method: func(updater repo.Updater) func(ctx context.Context, resourceType resource.Type, tenant string, dbEntity interface{}) error { 305 return updater.UpdateSingleWithVersion 306 }, 307 }, 308 } 309 310 for _, test := range tests { 311 t.Run(test.Name, func(t *testing.T) { 312 updater := repo.NewUpdater(appTableName, []string{"name", "description"}, []string{"id"}) 313 resourceType := resource.Application 314 m2mTable, ok := resourceType.TenantAccessTable() 315 require.True(t, ok) 316 317 t.Run("success", func(t *testing.T) { 318 // GIVEN 319 db, mock := testdb.MockDatabase(t) 320 ctx := persistence.SaveToContext(context.TODO(), db) 321 defer mock.AssertExpectations(t) 322 323 test.AttachAdditionalQueries(mock, m2mTable, tenantID) 324 325 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ?%s WHERE id = ? AND (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true))", appTableName, test.AdditionalCondition, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 326 WithArgs(appName, appDescription, appID, tenantID).WillReturnResult(sqlmock.NewResult(0, 1)) 327 // WHEN 328 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 329 // THEN 330 require.NoError(t, err) 331 }) 332 333 t.Run("success when no id column", func(t *testing.T) { 334 updater := repo.NewUpdater(appTableName, []string{"name", "description"}, []string{}) 335 // GIVEN 336 db, mock := testdb.MockDatabase(t) 337 ctx := persistence.SaveToContext(context.TODO(), db) 338 defer mock.AssertExpectations(t) 339 340 test.AttachAdditionalQueries(mock, m2mTable, tenantID) 341 342 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ?%s WHERE (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true)", appTableName, test.AdditionalCondition, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 343 WithArgs(appName, appDescription, tenantID).WillReturnResult(sqlmock.NewResult(0, 1)) 344 // WHEN 345 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 346 // THEN 347 require.NoError(t, err) 348 }) 349 350 t.Run("returns error when operation on db failed", func(t *testing.T) { 351 // GIVEN 352 db, mock := testdb.MockDatabase(t) 353 ctx := persistence.SaveToContext(context.TODO(), db) 354 defer mock.AssertExpectations(t) 355 356 test.AttachAdditionalQueries(mock, m2mTable, tenantID) 357 358 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ?%s WHERE id = ? AND (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true)", appTableName, test.AdditionalCondition, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 359 WithArgs(appName, appDescription, appID, tenantID).WillReturnError(someError()) 360 // WHEN 361 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 362 // THEN 363 require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 364 }) 365 366 t.Run("context properly canceled", func(t *testing.T) { 367 db, mock := testdb.MockDatabase(t) 368 defer mock.AssertExpectations(t) 369 370 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond) 371 defer cancel() 372 373 ctx = persistence.SaveToContext(ctx, db) 374 375 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 376 377 require.EqualError(t, err, "Internal Server Error: Maximum processing timeout reached") 378 }) 379 380 t.Run("returns non unique error", func(t *testing.T) { 381 // GIVEN 382 db, mock := testdb.MockDatabase(t) 383 ctx := persistence.SaveToContext(context.TODO(), db) 384 defer mock.AssertExpectations(t) 385 386 test.AttachAdditionalQueries(mock, m2mTable, tenantID) 387 388 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ?%s WHERE id = ? AND (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true)", appTableName, test.AdditionalCondition, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 389 WithArgs(appName, appDescription, appID, tenantID).WillReturnError(&pq.Error{Code: persistence.UniqueViolation}) 390 // WHEN 391 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 392 // THEN 393 require.True(t, apperrors.IsNotUniqueError(err)) 394 }) 395 396 t.Run("returns error if modified more than one row", func(t *testing.T) { 397 // GIVEN 398 db, mock := testdb.MockDatabase(t) 399 ctx := persistence.SaveToContext(context.TODO(), db) 400 defer mock.AssertExpectations(t) 401 402 test.AttachAdditionalQueries(mock, m2mTable, tenantID) 403 404 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ?%s WHERE id = ? AND (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true)", appTableName, test.AdditionalCondition, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 405 WithArgs(appName, appDescription, appID, tenantID).WillReturnResult(sqlmock.NewResult(0, 157)) 406 // WHEN 407 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 408 // THEN 409 require.Error(t, err) 410 require.Contains(t, err.Error(), "should update single row, but updated 157 rows") 411 }) 412 413 t.Run("returns error if does not modified any row", func(t *testing.T) { 414 // GIVEN 415 db, mock := testdb.MockDatabase(t) 416 ctx := persistence.SaveToContext(context.TODO(), db) 417 defer mock.AssertExpectations(t) 418 419 test.AttachAdditionalQueries(mock, m2mTable, tenantID) 420 421 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ?%s WHERE id = ? AND (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true)", appTableName, test.AdditionalCondition, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 422 WithArgs(appName, appDescription, appID, tenantID).WillReturnResult(sqlmock.NewResult(0, 0)) 423 // WHEN 424 err := test.Method(updater)(ctx, resourceType, tenantID, fixApp) 425 // THEN 426 require.Error(t, err) 427 if !strings.Contains(err.Error(), apperrors.ShouldBeOwnerMsg) && !strings.Contains(err.Error(), apperrors.ConcurrentUpdateMsg) { 428 t.Errorf("unexpected error: %s", err) 429 } 430 }) 431 432 t.Run("returns error if entity does not have tenant access table", func(t *testing.T) { 433 db, mock := testdb.MockDatabase(t) 434 ctx := persistence.SaveToContext(context.TODO(), db) 435 defer mock.AssertExpectations(t) 436 // WHEN 437 err := test.Method(updater)(ctx, resource.Type("unknown"), tenantID, fixApp) 438 // THEN 439 assert.Contains(t, err.Error(), "entity unknown does not have access table") 440 }) 441 442 t.Run("returns error if missing persistence context", func(t *testing.T) { 443 // WHEN 444 err := test.Method(updater)(context.TODO(), resourceType, tenantID, fixApp) 445 // THEN 446 require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error()) 447 }) 448 449 t.Run("returns error if entity is nil", func(t *testing.T) { 450 // WHEN 451 err := test.Method(updater)(context.TODO(), resourceType, tenantID, nil) 452 // THEN 453 require.EqualError(t, err, apperrors.NewInternalError("item cannot be nil").Error()) 454 }) 455 }) 456 } 457 458 t.Run("success for BundleInstanceAuth", func(t *testing.T) { 459 updater := repo.NewUpdater(biaTableName, []string{"name", "description"}, []string{"id"}) 460 resourceType := resource.BundleInstanceAuth 461 m2mTable, ok := resourceType.TenantAccessTable() 462 require.True(t, ok) 463 // GIVEN 464 db, mock := testdb.MockDatabase(t) 465 ctx := persistence.SaveToContext(context.TODO(), db) 466 defer mock.AssertExpectations(t) 467 468 mock.ExpectExec(regexp.QuoteMeta(fmt.Sprintf("UPDATE %s SET name = ?, description = ? WHERE id = ? AND (id IN (SELECT %s FROM %s WHERE %s = ? AND %s = true) OR owner_id = ?)", biaTableName, repo.M2MResourceIDColumn, m2mTable, repo.M2MTenantIDColumn, repo.M2MOwnerColumn))). 469 WithArgs(biaName, biaDescription, biaID, tenantID, tenantID).WillReturnResult(sqlmock.NewResult(0, 1)) 470 // WHEN 471 err := updater.UpdateSingle(ctx, resourceType, tenantID, fixBIA) 472 // THEN 473 require.NoError(t, err) 474 }) 475 476 t.Run("UpdateSingleWithVersion", func(t *testing.T) { 477 updater := repo.NewUpdater(appTableName, []string{"name", "description"}, []string{"id"}) 478 resourceType := resource.Application 479 m2mTable, ok := resourceType.TenantAccessTable() 480 require.True(t, ok) 481 482 t.Run("tenant does not have owner access should return error", func(t *testing.T) { 483 // GIVEN 484 db, mock := testdb.MockDatabase(t) 485 ctx := persistence.SaveToContext(context.TODO(), db) 486 defer mock.AssertExpectations(t) 487 488 mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT 1 FROM %s WHERE id = $1 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithOwnerCheckFmt, m2mTable, "$2")))). 489 WithArgs(appID, tenantID).WillReturnRows(testdb.RowWhenObjectDoesNotExist()) 490 491 // WHEN 492 err := updater.UpdateSingleWithVersion(ctx, resourceType, tenantID, fixApp) 493 // THEN 494 require.Error(t, err) 495 require.Contains(t, err.Error(), "entity does not exist or caller tenant does not have owner access") 496 }) 497 498 t.Run("entity is not identifiable should return error", func(t *testing.T) { 499 // GIVEN 500 db, mock := testdb.MockDatabase(t) 501 ctx := persistence.SaveToContext(context.TODO(), db) 502 defer mock.AssertExpectations(t) 503 504 // WHEN 505 err := updater.UpdateSingleWithVersion(ctx, resourceType, tenantID, struct{}{}) 506 // THEN 507 require.Error(t, err) 508 require.Contains(t, err.Error(), "id cannot be empty, check if the entity implements Identifiable") 509 }) 510 }) 511 }