|
37 | 37 | import org.springframework.http.HttpStatus;
|
38 | 38 | import org.springframework.scheduling.TaskScheduler;
|
39 | 39 | import org.springframework.scheduling.Trigger;
|
| 40 | +import org.springframework.test.util.ReflectionTestUtils; |
40 | 41 | import org.springframework.vault.VaultException;
|
41 | 42 | import org.springframework.vault.core.RestOperationsCallback;
|
42 | 43 | import org.springframework.vault.core.VaultOperations;
|
@@ -479,6 +480,78 @@ void shouldNotRotateExpiringLease() {
|
479 | 480 | assertThat(((SecretLeaseCreatedEvent) events.get(1)).getSecrets()).containsOnlyKeys("foo");
|
480 | 481 | }
|
481 | 482 |
|
| 483 | + @SuppressWarnings("unchecked") |
| 484 | + @Test |
| 485 | + void secretShouldContinueOnRestartSecrets() { |
| 486 | + |
| 487 | + when(this.taskScheduler.schedule(any(Runnable.class), any(Trigger.class))).thenReturn(this.scheduledFuture); |
| 488 | + |
| 489 | + VaultResponse first = createSecrets(); |
| 490 | + VaultResponse second = createSecrets(); |
| 491 | + second.setData(Collections.singletonMap("foo", (Object) "bar")); |
| 492 | + |
| 493 | + when(this.vaultOperations.read(this.requestedSecret.getPath())).thenReturn(first, second); |
| 494 | + when(this.vaultOperations.doWithSession(any(RestOperationsCallback.class))) |
| 495 | + .thenReturn(Lease.of("after_restart", Duration.ofSeconds(1), true)); |
| 496 | + |
| 497 | + RequestedSecret secret = RequestedSecret.rotating("my-secret"); |
| 498 | + |
| 499 | + this.secretLeaseContainer.setExpiryThreshold(Duration.ofSeconds(1)); |
| 500 | + this.secretLeaseContainer.addRequestedSecret(secret); |
| 501 | + this.secretLeaseContainer.start(); |
| 502 | + |
| 503 | + ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); |
| 504 | + this.secretLeaseContainer.restartSecrets(); |
| 505 | + |
| 506 | + verify(this.taskScheduler, times(2)).schedule(captor.capture(), any(Trigger.class)); |
| 507 | + captor.getAllValues().get(0).run(); // old lease run |
| 508 | + captor.getAllValues().get(1).run(); // new lease run |
| 509 | + |
| 510 | + // one from restartSecrets, the second from the scheduler detecting expiry |
| 511 | + verify(this.leaseListenerAdapter, times(2)).onLeaseEvent(any(SecretLeaseRotatedEvent.class)); |
| 512 | + verify(this.leaseListenerAdapter, never()).onLeaseEvent(any(SecretLeaseExpiredEvent.class)); |
| 513 | + verify(this.leaseListenerAdapter, never()).onLeaseEvent(any(SecretLeaseErrorEvent.class)); |
| 514 | + } |
| 515 | + |
| 516 | + @SuppressWarnings("unchecked") |
| 517 | + @Test |
| 518 | + void concurrentRenewalAfterRestartSecretShouldContinueOnRestartSecrets() { |
| 519 | + |
| 520 | + when(this.taskScheduler.schedule(any(Runnable.class), any(Trigger.class))).thenReturn(this.scheduledFuture); |
| 521 | + |
| 522 | + VaultResponse first = createSecrets(); |
| 523 | + VaultResponse second = createSecrets(); |
| 524 | + second.setData(Collections.singletonMap("foo", (Object) "bar")); |
| 525 | + |
| 526 | + when(this.vaultOperations.read(this.requestedSecret.getPath())).thenReturn(first, second); |
| 527 | + when(this.vaultOperations.doWithSession(any(RestOperationsCallback.class))) |
| 528 | + .thenReturn(Lease.of("after_restart", Duration.ofSeconds(1), true)); |
| 529 | + |
| 530 | + RequestedSecret secret = RequestedSecret.rotating("my-secret"); |
| 531 | + |
| 532 | + this.secretLeaseContainer.setExpiryThreshold(Duration.ofSeconds(1)); |
| 533 | + this.secretLeaseContainer.addRequestedSecret(secret); |
| 534 | + this.secretLeaseContainer.start(); |
| 535 | + |
| 536 | + Map<RequestedSecret, SecretLeaseContainer.LeaseRenewalScheduler> renewals = (Map<RequestedSecret, SecretLeaseContainer.LeaseRenewalScheduler>) ReflectionTestUtils.getField(this.secretLeaseContainer, "renewals"); |
| 537 | + |
| 538 | + SecretLeaseContainer.LeaseRenewalScheduler scheduler = renewals.get(secret); |
| 539 | + Lease lease = scheduler.getLease(); |
| 540 | + ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); |
| 541 | + this.secretLeaseContainer.restartSecrets(); |
| 542 | + |
| 543 | + scheduler.associateLease(lease); |
| 544 | + |
| 545 | + verify(this.taskScheduler, times(2)).schedule(captor.capture(), any(Trigger.class)); |
| 546 | + captor.getAllValues().get(1).run(); // new lease run |
| 547 | + captor.getAllValues().get(0).run(); // old lease run |
| 548 | + |
| 549 | + // one from restartSecrets, the second from the scheduler detecting expiry |
| 550 | + verify(this.leaseListenerAdapter, times(2)).onLeaseEvent(any(SecretLeaseRotatedEvent.class)); |
| 551 | + verify(this.leaseListenerAdapter).onLeaseEvent(any(SecretLeaseExpiredEvent.class)); |
| 552 | + verify(this.leaseListenerAdapter, never()).onLeaseEvent(any(SecretLeaseErrorEvent.class)); |
| 553 | + } |
| 554 | + |
482 | 555 | @Test
|
483 | 556 | void scheduleRenewalShouldApplyExpiryThreshold() {
|
484 | 557 |
|
|
0 commit comments