-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
65ceab1
commit a44b7ad
Showing
6 changed files
with
333 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
143 changes: 143 additions & 0 deletions
143
...foundry/multiapps/controller/core/application/health/ApplicationHealthCalculatorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package org.cloudfoundry.multiapps.controller.core.application.health; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import org.cloudfoundry.multiapps.common.SLException; | ||
import org.cloudfoundry.multiapps.controller.client.util.ResilientOperationExecutor; | ||
import org.cloudfoundry.multiapps.controller.core.application.health.database.DatabaseWaitingLocksAnalyzer; | ||
import org.cloudfoundry.multiapps.controller.core.application.health.model.ApplicationHealthResult; | ||
import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; | ||
import org.cloudfoundry.multiapps.controller.persistence.services.DatabaseHealthService; | ||
import org.cloudfoundry.multiapps.controller.persistence.services.DatabaseMonitoringService; | ||
import org.cloudfoundry.multiapps.controller.persistence.services.ObjectStoreFileStorage; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.Mock; | ||
import org.mockito.Mockito; | ||
import org.mockito.MockitoAnnotations; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
|
||
class ApplicationHealthCalculatorTest { | ||
|
||
@Mock | ||
private ObjectStoreFileStorage objectStoreFileStorage; | ||
@Mock | ||
private ApplicationConfiguration applicationConfiguration; | ||
@Mock | ||
private DatabaseHealthService databaseHealthService; | ||
@Mock | ||
private DatabaseMonitoringService databaseMonitoringService; | ||
@Mock | ||
private DatabaseWaitingLocksAnalyzer databaseWaitingLocksAnalyzer; | ||
|
||
private ApplicationHealthCalculator applicationHealthCalculator; | ||
|
||
@BeforeEach | ||
void setUp() throws Exception { | ||
MockitoAnnotations.openMocks(this) | ||
.close(); | ||
Mockito.when(applicationConfiguration.isHealthCheckEnabled()) | ||
.thenReturn(true); | ||
applicationHealthCalculator = new ApplicationHealthCalculatorMock(objectStoreFileStorage, | ||
applicationConfiguration, | ||
databaseHealthService, | ||
databaseMonitoringService, | ||
databaseWaitingLocksAnalyzer); | ||
} | ||
|
||
@Test | ||
void testUpdateWithFailingObjectStore() { | ||
Mockito.doThrow(new SLException("Object store not working")) | ||
.when(objectStoreFileStorage) | ||
.testConnection(); | ||
applicationHealthCalculator.updateHealthStatus(); | ||
ResponseEntity<ApplicationHealthResult> applicationHealthResultResponseEntity = applicationHealthCalculator.calculateApplicationHealth(); | ||
assertEquals(HttpStatus.SERVICE_UNAVAILABLE, applicationHealthResultResponseEntity.getStatusCode()); | ||
assertEquals(ApplicationHealthResult.Status.DOWN, applicationHealthResultResponseEntity.getBody() | ||
.getStatus()); | ||
assertFalse(applicationHealthResultResponseEntity.getBody() | ||
.hasIncreasedLocks()); | ||
} | ||
|
||
@Test | ||
void testUpdateWithFailingDatabase() { | ||
Mockito.doThrow(new SLException("Database not working")) | ||
.when(databaseHealthService) | ||
.testDatabaseConnection(); | ||
applicationHealthCalculator.updateHealthStatus(); | ||
ResponseEntity<ApplicationHealthResult> applicationHealthResultResponseEntity = applicationHealthCalculator.calculateApplicationHealth(); | ||
assertEquals(HttpStatus.SERVICE_UNAVAILABLE, applicationHealthResultResponseEntity.getStatusCode()); | ||
assertEquals(ApplicationHealthResult.Status.DOWN, applicationHealthResultResponseEntity.getBody() | ||
.getStatus()); | ||
assertFalse(applicationHealthResultResponseEntity.getBody() | ||
.hasIncreasedLocks()); | ||
} | ||
|
||
@Test | ||
void testSuccessfulHealthCheck() { | ||
applicationHealthCalculator.updateHealthStatus(); | ||
ResponseEntity<ApplicationHealthResult> applicationHealthResultResponseEntity = applicationHealthCalculator.calculateApplicationHealth(); | ||
assertEquals(HttpStatus.OK, applicationHealthResultResponseEntity.getStatusCode()); | ||
assertEquals(ApplicationHealthResult.Status.UP, applicationHealthResultResponseEntity.getBody() | ||
.getStatus()); | ||
assertFalse(applicationHealthResultResponseEntity.getBody() | ||
.hasIncreasedLocks()); | ||
} | ||
|
||
@Test | ||
void testUpdateWithIncreasedDatabaseLocks() { | ||
Mockito.when(databaseWaitingLocksAnalyzer.hasIncreasedDbLocks()) | ||
.thenReturn(true); | ||
applicationHealthCalculator.updateHealthStatus(); | ||
ResponseEntity<ApplicationHealthResult> applicationHealthResultResponseEntity = applicationHealthCalculator.calculateApplicationHealth(); | ||
assertEquals(HttpStatus.OK, applicationHealthResultResponseEntity.getStatusCode()); | ||
assertEquals(ApplicationHealthResult.Status.DOWN, applicationHealthResultResponseEntity.getBody() | ||
.getStatus()); | ||
assertTrue(applicationHealthResultResponseEntity.getBody() | ||
.hasIncreasedLocks()); | ||
} | ||
|
||
@Test | ||
void testSuccessfulUpdateWithMissingObjectStore() { | ||
applicationHealthCalculator = new ApplicationHealthCalculatorMock(null, | ||
applicationConfiguration, | ||
databaseHealthService, | ||
databaseMonitoringService, | ||
databaseWaitingLocksAnalyzer); | ||
applicationHealthCalculator.updateHealthStatus(); | ||
ResponseEntity<ApplicationHealthResult> applicationHealthResultResponseEntity = applicationHealthCalculator.calculateApplicationHealth(); | ||
assertEquals(HttpStatus.OK, applicationHealthResultResponseEntity.getStatusCode()); | ||
assertEquals(ApplicationHealthResult.Status.UP, applicationHealthResultResponseEntity.getBody() | ||
.getStatus()); | ||
assertFalse(applicationHealthResultResponseEntity.getBody() | ||
.hasIncreasedLocks()); | ||
} | ||
|
||
private static class ApplicationHealthCalculatorMock extends ApplicationHealthCalculator { | ||
public ApplicationHealthCalculatorMock(ObjectStoreFileStorage objectStoreFileStorage, | ||
ApplicationConfiguration applicationConfiguration, | ||
DatabaseHealthService databaseHealthService, | ||
DatabaseMonitoringService databaseMonitoringService, | ||
DatabaseWaitingLocksAnalyzer databaseWaitingLocksAnalyzer) { | ||
super(objectStoreFileStorage, | ||
applicationConfiguration, | ||
databaseHealthService, | ||
databaseMonitoringService, | ||
databaseWaitingLocksAnalyzer); | ||
} | ||
|
||
@Override | ||
protected ResilientOperationExecutor getResilienceExecutor() { | ||
return new ResilientOperationExecutor().withRetryCount(0) | ||
.withWaitTimeBetweenRetriesInMillis(0); | ||
} | ||
|
||
@Override | ||
protected void scheduleRegularHealthUpdate() { | ||
// Do nothing | ||
} | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
...ltiapps/controller/core/application/health/database/DatabaseWaitingLocksAnalyzerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package org.cloudfoundry.multiapps.controller.core.application.health.database; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.ArgumentMatchers.anyString; | ||
|
||
import java.util.stream.Stream; | ||
|
||
import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; | ||
import org.cloudfoundry.multiapps.controller.persistence.services.DatabaseMonitoringService; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
import org.mockito.Mock; | ||
import org.mockito.Mockito; | ||
import org.mockito.MockitoAnnotations; | ||
|
||
class DatabaseWaitingLocksAnalyzerTest { | ||
|
||
@Mock | ||
private DatabaseMonitoringService databaseMonitoringService; | ||
@Mock | ||
private ApplicationConfiguration applicationConfiguration; | ||
|
||
private DatabaseWaitingLocksAnalyzer databaseWaitingLocksAnalyzer; | ||
|
||
@BeforeEach | ||
void setUp() throws Exception { | ||
MockitoAnnotations.openMocks(this) | ||
.close(); | ||
databaseWaitingLocksAnalyzer = new DatabaseWaitingLocksAnalyzerMock(databaseMonitoringService, applicationConfiguration); | ||
} | ||
|
||
// @formatter:off | ||
static Stream<Arguments> testIncreasedLocks() { | ||
return Stream.of(Arguments.of(new long[] { 1, 2, 3, 4, 5, 6, 6, 6, 7, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 5, 14, 16, 4, 3, 2, 1 }, false), // has values under the minimal threshold | ||
Arguments.of(new long[] { 6, 7, 12, 12, 12, 12, 12, 12, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 41, 35, 30 }, false), // most of the values are decreasing, assuming that they will continue to decrease | ||
Arguments.of(new long[] { 24, 24, 26, 29, 30, 30, 30, 31, 30, 14, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 11, 12, 13, 14, 14, 15, 16, 17, 18, 20 }, false), // the sum of the last on third of the sequence is smaller compared to the sum of the first one third | ||
Arguments.of(new long[] { 24, 24, 26, 29, 30, 30, 30, 31, 30, 14, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 24, 29, 31, 32, 14, 19, 36, 38, 40, 45 }, true), // the index of increase is bigger than the threshold and the sum of the last sequence is bigger than the sum of the first sequence | ||
Arguments.of(new long[] { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }, true) // flat sequence | ||
); | ||
} | ||
// @formatter:on | ||
|
||
@ParameterizedTest | ||
@MethodSource | ||
void testIncreasedLocks(long[] lockSamples, boolean hasIncreasedLocksExpectation) { | ||
mockDatabaseWaitingLocksAnalyzer(lockSamples); | ||
refreshLocksSamples(lockSamples); | ||
assertEquals(hasIncreasedLocksExpectation, databaseWaitingLocksAnalyzer.hasIncreasedDbLocks()); | ||
} | ||
|
||
private void mockDatabaseWaitingLocksAnalyzer(long[] lockSamples) { | ||
Mockito.when(databaseMonitoringService.getProcessesWaitingForLocks(anyString())) | ||
.thenAnswer(invocation -> { | ||
int callIndex = Mockito.mockingDetails(databaseMonitoringService) | ||
.getInvocations() | ||
.size() | ||
- 1; | ||
return lockSamples[callIndex]; | ||
}); | ||
} | ||
|
||
private void refreshLocksSamples(long[] lockSamples) { | ||
for (int i = 0; i < lockSamples.length; i++) { | ||
databaseWaitingLocksAnalyzer.refreshLockInfo(); | ||
} | ||
} | ||
|
||
private static class DatabaseWaitingLocksAnalyzerMock extends DatabaseWaitingLocksAnalyzer { | ||
|
||
public DatabaseWaitingLocksAnalyzerMock(DatabaseMonitoringService databaseMonitoringService, | ||
ApplicationConfiguration applicationConfiguration) { | ||
super(databaseMonitoringService, applicationConfiguration); | ||
} | ||
|
||
@Override | ||
protected void scheduleRegularLocksRefresh() { | ||
// Do nothing | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...org/cloudfoundry/multiapps/controller/persistence/services/DatabaseHealthServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.cloudfoundry.multiapps.controller.persistence.services; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.ArgumentMatchers.anyString; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import jakarta.persistence.EntityManager; | ||
import jakarta.persistence.EntityManagerFactory; | ||
import jakarta.persistence.Query; | ||
|
||
class DatabaseHealthServiceTest { | ||
|
||
private EntityManagerFactory entityManagerFactory; | ||
private EntityManager entityManager; | ||
private Query query; | ||
private DatabaseHealthService databaseHealthService; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
entityManagerFactory = mock(EntityManagerFactory.class); | ||
entityManager = mock(EntityManager.class); | ||
query = mock(Query.class); | ||
databaseHealthService = new DatabaseHealthService(entityManagerFactory); | ||
|
||
when(entityManagerFactory.createEntityManager()).thenReturn(entityManager); | ||
when(entityManager.createNativeQuery(anyString())).thenReturn(query); | ||
when(query.getSingleResult()).thenReturn(10); | ||
} | ||
|
||
@Test | ||
void testDatabaseConnection() { | ||
databaseHealthService.testDatabaseConnection(); | ||
|
||
verify(entityManager).close(); | ||
assertEquals(10, query.getSingleResult()); | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
...cloudfoundry/multiapps/controller/persistence/services/DatabaseMonitoringServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package org.cloudfoundry.multiapps.controller.persistence.services; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.ArgumentMatchers.anyString; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import jakarta.persistence.EntityManager; | ||
import jakarta.persistence.EntityManagerFactory; | ||
import jakarta.persistence.Query; | ||
|
||
class DatabaseMonitoringServiceTest { | ||
|
||
private EntityManagerFactory entityManagerFactory; | ||
private EntityManager entityManager; | ||
private Query query; | ||
private DatabaseMonitoringService databaseMonitoringService; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
entityManagerFactory = mock(EntityManagerFactory.class); | ||
entityManager = mock(EntityManager.class); | ||
query = mock(Query.class); | ||
databaseMonitoringService = new DatabaseMonitoringService(entityManagerFactory); | ||
|
||
when(entityManagerFactory.createEntityManager()).thenReturn(entityManager); | ||
when(entityManager.createNativeQuery(anyString())).thenReturn(query); | ||
when(query.getSingleResult()).thenReturn(10L); | ||
} | ||
|
||
@Test | ||
void testGetProcessesWaitingForLocks() { | ||
long result = databaseMonitoringService.getProcessesWaitingForLocks("testApp"); | ||
|
||
assertEquals(10L, result); | ||
verify(entityManager).close(); | ||
} | ||
|
||
} |