Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,28 @@ void constructor_doesNotCancelInitialTask() {

verify(initialTask, never()).cancelTask();
}

@Test
@DisplayName("Given a ReloadableTask, when first constructed, then runTask is called on the initial task")
void constructor_callsRunTaskOnInitialTask() {
CancelableCoreTask initialTask = mock(CancelableCoreTask.class);
BiFunction<YamlDocument, Route, CancelableCoreTask> callback = (doc, r) -> initialTask;

new ReloadableTask<>(yamlDocument, route, callback, false);

verify(initialTask).runTask(false);
}

@Test
@DisplayName("Given async=true, when first constructed, then initial runTask receives false due to field initialization order")
void constructor_callsRunTaskWithFalse_whenAsyncIsTrueDueToFieldInitOrder() {
CancelableCoreTask initialTask = mock(CancelableCoreTask.class);
BiFunction<YamlDocument, Route, CancelableCoreTask> callback = (doc, r) -> initialTask;

new ReloadableTask<>(yamlDocument, route, callback, true);

// During construction, super() calls reloadContent() before 'async' is assigned.
// The async field is still at its default value (false) at that point.
verify(initialTask).runTask(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,50 @@ void executeTransaction_doesNotThrow_whenAutoCommitResetAndCloseBothFail() throw
assertDoesNotThrow(transaction::executeTransaction);
}

@Test
@DisplayName("Given a successful execution, when commit throws, then transaction state is ROLLED_BACK and rollback is called")
void executeTransaction_rollsBack_whenCommitFails() throws SQLException {
PreparedStatement ps = mock(PreparedStatement.class);
doThrow(new SQLException("commit failed")).when(connection).commit();

var transaction = new FailSafeTransaction(connection, List.of(ps));
assertDoesNotThrow(transaction::executeTransaction);

verify(ps).executeUpdate();
verify(connection).rollback();
assertEquals(TransactionState.ROLLED_BACK, transaction.getTransactionState());
assertTrue(transaction.getFailureCause().isPresent());
}

@Test
@DisplayName("Given a statement failure, when getting failure cause, then cause message wraps the original exception")
void executeTransaction_storesFailureCause_withOriginalExceptionDetails() throws SQLException {
PreparedStatement ps = mock(PreparedStatement.class);
doThrow(new SQLException("specific error detail")).when(ps).executeUpdate();

var transaction = new FailSafeTransaction(connection, List.of(ps));
transaction.executeTransaction();

assertTrue(transaction.getFailureCause().isPresent());
assertNotNull(transaction.getFailureCause().get().getCause());
assertEquals("specific error detail", transaction.getFailureCause().get().getCause().getMessage());
}

@Test
@DisplayName("Given a successful execution with autocommit-reset failure, when checking state, then state remains COMMITTED")
void executeTransaction_remainsCommitted_whenAutoCommitResetFails() throws SQLException {
PreparedStatement ps = mock(PreparedStatement.class);
doNothing().when(connection).setAutoCommit(false);
doThrow(new SQLException("autocommit fail")).when(connection).setAutoCommit(true);

var transaction = new FailSafeTransaction(connection, List.of(ps));
transaction.executeTransaction();

verify(connection).commit();
assertEquals(TransactionState.COMMITTED, transaction.getTransactionState());
assertFalse(transaction.getFailureCause().isPresent());
}

@Test
@DisplayName("Given no statements, when executing transaction, then commit succeeds and no rollback occurs")
void executeTransaction_commitsSuccessfully_whenNoStatementsAdded() throws SQLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ void getCheckedLocales_returnsEmptySet_whenConstructedWithEmptyLocales() {
assertTrue(ex.getCheckedLocales().isEmpty());
}

@Test
@DisplayName("Given an empty locale set, when calling getMessage, then message contains Optional.empty for locales")
void getMessage_containsOptionalEmpty_whenConstructedWithEmptyLocales() {
Route route = Route.from("messages", "empty");
NoLocalizationContainsMessageException ex = new NoLocalizationContainsMessageException(route, Set.of());

String message = ex.getMessage();
assertNotNull(message);
assertTrue(message.contains(route.toString()));
assertTrue(message.contains("Optional.empty"));
}

@Test
@DisplayName("Given multiple locales, when calling getMessage, then message contains comma-separated locale names")
void getMessage_containsCommaSeparatedLocaleNames_whenConstructedWithMultipleLocales() {
Route route = Route.from("messages", "multi");
NoLocalizationContainsMessageException ex = new NoLocalizationContainsMessageException(route, Set.of(Locale.ENGLISH, Locale.FRENCH));

String message = ex.getMessage();
assertNotNull(message);
assertTrue(message.contains(Locale.ENGLISH.getDisplayName()));
assertTrue(message.contains(Locale.FRENCH.getDisplayName()));
}

@Test
@DisplayName("Given a NoLocalizationContainsMessageException, when checking type, then it is a RuntimeException")
void noLocalizationContainsMessageException_isRuntimeException_always() {
Expand Down
Loading