|
11 | 11 | import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
|
12 | 12 | import com.google.common.collect.ImmutableMap;
|
13 | 13 | import org.junit.jupiter.api.Test;
|
| 14 | +import org.junit.jupiter.params.ParameterizedTest; |
| 15 | +import org.junit.jupiter.params.provider.CsvSource; |
14 | 16 | import org.mockito.Mockito;
|
15 | 17 | import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
16 | 18 | import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
|
22 | 24 | import software.amazon.awssdk.services.dynamodb.model.IndexStatus;
|
23 | 25 | import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
|
24 | 26 | import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
|
| 27 | +import software.amazon.awssdk.services.dynamodb.model.ScanRequest; |
| 28 | +import software.amazon.awssdk.services.dynamodb.model.ScanResponse; |
25 | 29 | import software.amazon.awssdk.services.dynamodb.model.TableDescription;
|
26 | 30 | import software.amazon.awssdk.services.dynamodb.model.TableStatus;
|
27 | 31 | import software.amazon.awssdk.services.dynamodb.model.UpdateContinuousBackupsRequest;
|
@@ -393,6 +397,153 @@ void listLeasesParallely_leaseWithFailingDeserialization_assertCorrectResponse()
|
393 | 397 | assertEquals("badLeaseKey", response.getValue().get(0));
|
394 | 398 | }
|
395 | 399 |
|
| 400 | + @Test |
| 401 | + public void listLeasesParallely_UseCachedTotalSegment() |
| 402 | + throws ProvisionedThroughputException, DependencyException, InvalidStateException { |
| 403 | + DynamoDbAsyncClient mockDdbClient = mock(DynamoDbAsyncClient.class); |
| 404 | + final long oneGBInBytes = 1073741824L; |
| 405 | + |
| 406 | + when(mockDdbClient.describeTable(any(DescribeTableRequest.class))) |
| 407 | + .thenReturn(CompletableFuture.completedFuture(DescribeTableResponse.builder() |
| 408 | + .table(TableDescription.builder() |
| 409 | + .tableName(TEST_LEASE_TABLE) |
| 410 | + .tableStatus(TableStatus.ACTIVE) |
| 411 | + .tableSizeBytes(oneGBInBytes) |
| 412 | + .build()) |
| 413 | + .build())); |
| 414 | + when(mockDdbClient.scan(any(ScanRequest.class))) |
| 415 | + .thenReturn(CompletableFuture.completedFuture( |
| 416 | + ScanResponse.builder().items(new ArrayList<>()).build())); |
| 417 | + |
| 418 | + final LeaseRefresher leaseRefresher = new DynamoDBLeaseRefresher( |
| 419 | + TEST_LEASE_TABLE, |
| 420 | + mockDdbClient, |
| 421 | + new DynamoDBLeaseSerializer(), |
| 422 | + true, |
| 423 | + NOOP_TABLE_CREATOR_CALLBACK, |
| 424 | + Duration.ofSeconds(10), |
| 425 | + new DdbTableConfig(), |
| 426 | + true, |
| 427 | + true, |
| 428 | + new ArrayList<>()); |
| 429 | + |
| 430 | + leaseRefresher.listLeasesParallely(Executors.newFixedThreadPool(2), 0); |
| 431 | + verify(mockDdbClient, times(5)).scan(any(ScanRequest.class)); |
| 432 | + |
| 433 | + // calling second to test cached value is used |
| 434 | + leaseRefresher.listLeasesParallely(Executors.newFixedThreadPool(2), 0); |
| 435 | + |
| 436 | + // verify if describe table is called once even when listLeasesParallely is called twice |
| 437 | + verify(mockDdbClient, times(1)).describeTable(any(DescribeTableRequest.class)); |
| 438 | + verify(mockDdbClient, times(10)).scan(any(ScanRequest.class)); |
| 439 | + } |
| 440 | + |
| 441 | + @Test |
| 442 | + public void listLeasesParallely_DescribeTableNotCalledWhenSegmentGreaterThanZero() |
| 443 | + throws ProvisionedThroughputException, DependencyException, InvalidStateException { |
| 444 | + DynamoDbAsyncClient mockDdbClient = mock(DynamoDbAsyncClient.class); |
| 445 | + |
| 446 | + when(mockDdbClient.describeTable(any(DescribeTableRequest.class))) |
| 447 | + .thenReturn(CompletableFuture.completedFuture(DescribeTableResponse.builder() |
| 448 | + .table(TableDescription.builder() |
| 449 | + .tableName(TEST_LEASE_TABLE) |
| 450 | + .tableStatus(TableStatus.ACTIVE) |
| 451 | + .tableSizeBytes(1000L) |
| 452 | + .build()) |
| 453 | + .build())); |
| 454 | + when(mockDdbClient.scan(any(ScanRequest.class))) |
| 455 | + .thenReturn(CompletableFuture.completedFuture( |
| 456 | + ScanResponse.builder().items(new ArrayList<>()).build())); |
| 457 | + |
| 458 | + final LeaseRefresher leaseRefresher = new DynamoDBLeaseRefresher( |
| 459 | + TEST_LEASE_TABLE, |
| 460 | + mockDdbClient, |
| 461 | + new DynamoDBLeaseSerializer(), |
| 462 | + true, |
| 463 | + NOOP_TABLE_CREATOR_CALLBACK, |
| 464 | + Duration.ofSeconds(10), |
| 465 | + new DdbTableConfig(), |
| 466 | + true, |
| 467 | + true, |
| 468 | + new ArrayList<>()); |
| 469 | + |
| 470 | + leaseRefresher.listLeasesParallely(Executors.newFixedThreadPool(2), 2); |
| 471 | + verify(mockDdbClient, times(0)).describeTable(any(DescribeTableRequest.class)); |
| 472 | + } |
| 473 | + |
| 474 | + @Test |
| 475 | + public void listLeasesParallely_TotalSegmentIsDefaultWhenDescribeTableThrowsException() |
| 476 | + throws ProvisionedThroughputException, DependencyException, InvalidStateException { |
| 477 | + DynamoDbAsyncClient mockDdbClient = mock(DynamoDbAsyncClient.class); |
| 478 | + |
| 479 | + when(mockDdbClient.describeTable(any(DescribeTableRequest.class))) |
| 480 | + .thenThrow(ResourceNotFoundException.builder() |
| 481 | + .message("Mock table does not exist scenario") |
| 482 | + .build()); |
| 483 | + |
| 484 | + when(mockDdbClient.scan(any(ScanRequest.class))) |
| 485 | + .thenReturn(CompletableFuture.completedFuture( |
| 486 | + ScanResponse.builder().items(new ArrayList<>()).build())); |
| 487 | + |
| 488 | + final LeaseRefresher leaseRefresher = new DynamoDBLeaseRefresher( |
| 489 | + TEST_LEASE_TABLE, |
| 490 | + mockDdbClient, |
| 491 | + new DynamoDBLeaseSerializer(), |
| 492 | + true, |
| 493 | + NOOP_TABLE_CREATOR_CALLBACK, |
| 494 | + Duration.ofSeconds(10), |
| 495 | + new DdbTableConfig(), |
| 496 | + true, |
| 497 | + true, |
| 498 | + new ArrayList<>()); |
| 499 | + |
| 500 | + leaseRefresher.listLeasesParallely(Executors.newFixedThreadPool(2), 0); |
| 501 | + verify(mockDdbClient, times(10)).scan(any(ScanRequest.class)); |
| 502 | + } |
| 503 | + |
| 504 | + @ParameterizedTest |
| 505 | + @CsvSource({ |
| 506 | + "0, 1", // 0 |
| 507 | + "1024, 1", // 1KB |
| 508 | + "104857600, 1", // 100MB |
| 509 | + "214748364, 1", // 0.2GB |
| 510 | + "322122547, 2", // 1.3GB |
| 511 | + "1073741824, 5", // 1GB |
| 512 | + "2147483648, 10", // 2GB |
| 513 | + "5368709120, 25", // 5GB |
| 514 | + }) |
| 515 | + public void listLeasesParallely_TotalSegmentForDifferentTableSize(long tableSizeBytes, int totalSegments) |
| 516 | + throws ProvisionedThroughputException, DependencyException, InvalidStateException { |
| 517 | + DynamoDbAsyncClient mockDdbClient = mock(DynamoDbAsyncClient.class); |
| 518 | + |
| 519 | + when(mockDdbClient.describeTable(any(DescribeTableRequest.class))) |
| 520 | + .thenReturn(CompletableFuture.completedFuture(DescribeTableResponse.builder() |
| 521 | + .table(TableDescription.builder() |
| 522 | + .tableName(TEST_LEASE_TABLE) |
| 523 | + .tableStatus(TableStatus.ACTIVE) |
| 524 | + .tableSizeBytes(tableSizeBytes) |
| 525 | + .build()) |
| 526 | + .build())); |
| 527 | + when(mockDdbClient.scan(any(ScanRequest.class))) |
| 528 | + .thenReturn(CompletableFuture.completedFuture( |
| 529 | + ScanResponse.builder().items(new ArrayList<>()).build())); |
| 530 | + |
| 531 | + final LeaseRefresher leaseRefresher = new DynamoDBLeaseRefresher( |
| 532 | + TEST_LEASE_TABLE, |
| 533 | + mockDdbClient, |
| 534 | + new DynamoDBLeaseSerializer(), |
| 535 | + true, |
| 536 | + NOOP_TABLE_CREATOR_CALLBACK, |
| 537 | + Duration.ofSeconds(10), |
| 538 | + new DdbTableConfig(), |
| 539 | + true, |
| 540 | + true, |
| 541 | + new ArrayList<>()); |
| 542 | + |
| 543 | + leaseRefresher.listLeasesParallely(Executors.newFixedThreadPool(2), 0); |
| 544 | + verify(mockDdbClient, times(totalSegments)).scan(any(ScanRequest.class)); |
| 545 | + } |
| 546 | + |
396 | 547 | @Test
|
397 | 548 | void initiateGracefulLeaseHandoff_sanity() throws Exception {
|
398 | 549 | DynamoDBLeaseRefresher leaseRefresher = createLeaseRefresher(new DdbTableConfig(), dynamoDbAsyncClient);
|
|
0 commit comments