Skip to content

Commit

Permalink
Better error message for badly linked events
Browse files Browse the repository at this point in the history
  • Loading branch information
amckenzie committed Oct 22, 2019
1 parent baf02eb commit f418183
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to
- Pre publish and publish timer beans now run in a separate thread.
- New JNDI boolean values of 'pre.publish.disable' and 'publish.disable' to disable
the running of PrePublisherTimerBean and PublisherTimerBean respectively
- Error message of event linking verification now gives more accurate error messages
based on whether the problem is in published_event or processed_event

## [2.2.1] - 2019-10-18
### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.sql.DataSource;

public class EventLinkageChecker {

@Inject
private EventLinkageErrorMessageGenerator eventLinkageErrorMessageGenerator;

public List<VerificationResult> verifyEventNumbersAreLinkedCorrectly(
final String tableName,
final LinkedEventNumberTable linkedEventNumberTable,
final DataSource dataSource) {

final String query = format("SELECT event_number, previous_event_number FROM %s ORDER BY event_number", tableName);
final String query = format("SELECT event_number, previous_event_number FROM %s ORDER BY event_number", linkedEventNumberTable.getTableName());

final List<VerificationResult> errors = new ArrayList<>();

Expand All @@ -36,13 +40,13 @@ public List<VerificationResult> verifyEventNumbersAreLinkedCorrectly(

if (previousEventNumber != lastEventNumber) {

final String message =
"Events incorrectly linked in %s table. " +
"Event with event number %d " +
"is linked to previous event number %d " +
"whereas it should be %d";
final String errorMessage = eventLinkageErrorMessageGenerator.generateErrorMessage(
previousEventNumber,
eventNumber,
lastEventNumber,
linkedEventNumberTable);

errors.add(error(format(message, tableName, eventNumber, previousEventNumber, lastEventNumber)));
errors.add(error(errorMessage));
}

lastEventNumber = eventNumber;
Expand All @@ -54,15 +58,15 @@ public List<VerificationResult> verifyEventNumbersAreLinkedCorrectly(
final String message = format(
"All %d events in the %s table are correctly linked",
count,
tableName);
linkedEventNumberTable.getTableName());

return singletonList(success(message));
}

return errors;

} catch (final SQLException e) {
throw new CatchupVerificationException(format("Failed to get event numbers from %s table", tableName), e);
throw new CatchupVerificationException(format("Failed to get event numbers from %s table", linkedEventNumberTable.getTableName()), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package uk.gov.justice.services.eventstore.management.validation.process;

import static java.lang.String.format;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PUBLISHED_EVENT;

public class EventLinkageErrorMessageGenerator {

public String generateErrorMessage(
final int previousEventNumber,
final int eventNumber,
final int lastEventNumber,
final LinkedEventNumberTable linkedEventNumberTable) {


final String message;
if (linkedEventNumberTable == PUBLISHED_EVENT) {
message = "Events incorrectly linked in %s table: " +
"Event with event number %d " +
"is linked to previous event number %d " +
"whereas it should be %d";

} else {
message = "Events missing from %s table: " +
"Event with event_number %d " +
"has a previous_event_number of %d, " +
"but the event in the previous row in the database " +
"has an event_number of %d";
}

return format(
message,
linkedEventNumberTable.getTableName(),
eventNumber,
previousEventNumber,
lastEventNumber);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package uk.gov.justice.services.eventstore.management.validation.process;

public enum LinkedEventNumberTable {

PUBLISHED_EVENT("published_event"),
PROCESSED_EVENT("processed_event");

private final String tableName;

LinkedEventNumberTable(final String tableName) {
this.tableName = tableName;
}

public String getTableName() {
return tableName;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package uk.gov.justice.services.eventstore.management.validation.process.verifiers;

import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PROCESSED_EVENT;

import uk.gov.justice.services.eventstore.management.validation.process.EventLinkageChecker;
import uk.gov.justice.services.eventstore.management.validation.process.VerificationResult;
import uk.gov.justice.services.eventstore.management.validation.process.Verifier;
Expand Down Expand Up @@ -28,7 +30,7 @@ public List<VerificationResult> verify() {
logger.info("Verifying all previous_event_numbers in processed_event point to an existing event...");

return eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(
"processed_event",
PROCESSED_EVENT,
viewStoreJdbcDataSourceProvider.getDataSource());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package uk.gov.justice.services.eventstore.management.validation.process.verifiers;

import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PUBLISHED_EVENT;

import uk.gov.justice.services.eventsourcing.source.core.EventStoreDataSourceProvider;
import uk.gov.justice.services.eventstore.management.validation.process.EventLinkageChecker;
import uk.gov.justice.services.eventstore.management.validation.process.VerificationResult;
Expand Down Expand Up @@ -28,7 +30,7 @@ public List<VerificationResult> verify() {
logger.info("Verifying all previous_event_numbers in processed_event point to an existing event...");

return eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(
"published_event",
PUBLISHED_EVENT,
eventStoreDataSourceProvider.getDefaultDataSource());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PROCESSED_EVENT;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PUBLISHED_EVENT;
import static uk.gov.justice.services.eventstore.management.validation.process.VerificationResult.VerificationResultType.ERROR;
import static uk.gov.justice.services.eventstore.management.validation.process.VerificationResult.VerificationResultType.SUCCESS;

Expand All @@ -19,20 +21,22 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class EventLinkageCheckerTest {

@Mock
private EventLinkageErrorMessageGenerator eventLinkageErrorMessageGenerator;

@InjectMocks
private EventLinkageChecker eventLinkageChecker;

@Test
public void shouldReturnSuccessIfAllEventsAreCorrectlyLinked() throws Exception {

final String tableName = "some_table";

final String sql = "SELECT event_number, previous_event_number FROM some_table ORDER BY event_number";
final String sql = "SELECT event_number, previous_event_number FROM published_event ORDER BY event_number";

final DataSource dataSource = mock(DataSource.class);
final Connection connection = mock(Connection.class);
Expand All @@ -48,20 +52,20 @@ public void shouldReturnSuccessIfAllEventsAreCorrectlyLinked() throws Exception
when(resultSet.getInt("event_number")).thenReturn(1, 2, 3);

final List<VerificationResult> publishedEventsResults = eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(
tableName,
PUBLISHED_EVENT,
dataSource);

assertThat(publishedEventsResults.size(), is(1));
assertThat(publishedEventsResults.get(0).getVerificationResultType(), is(SUCCESS));
assertThat(publishedEventsResults.get(0).getMessage(), is("All 3 events in the some_table table are correctly linked"));
assertThat(publishedEventsResults.get(0).getMessage(), is("All 3 events in the published_event table are correctly linked"));
}

@Test
public void shouldReturnErrorIfAnyEventsAreIncorrectlyLinked() throws Exception {

final String tableName = "some_table";
final String errorMessage = "error message";

final String sql = "SELECT event_number, previous_event_number FROM some_table ORDER BY event_number";
final String sql = "SELECT event_number, previous_event_number FROM published_event ORDER BY event_number";

final DataSource dataSource = mock(DataSource.class);
final Connection connection = mock(Connection.class);
Expand All @@ -76,21 +80,24 @@ public void shouldReturnErrorIfAnyEventsAreIncorrectlyLinked() throws Exception
when(resultSet.getInt("previous_event_number")).thenReturn(0, 1, 3);
when(resultSet.getInt("event_number")).thenReturn(1, 2, 4);

when(eventLinkageErrorMessageGenerator.generateErrorMessage(3, 4, 2, PUBLISHED_EVENT)).thenReturn(errorMessage);

final List<VerificationResult> publishedEventsResults = eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(
tableName,
PUBLISHED_EVENT,
dataSource);

assertThat(publishedEventsResults.size(), is(1));
assertThat(publishedEventsResults.get(0).getVerificationResultType(), is(ERROR));
assertThat(publishedEventsResults.get(0).getMessage(), is("Events incorrectly linked in some_table table. Event with event number 4 is linked to previous event number 3 whereas it should be 2"));
assertThat(publishedEventsResults.get(0).getMessage(), is(errorMessage));
}

@Test
public void shouldReturnAllErrors() throws Exception {

final String tableName = "some_table";
final String errorMessage_1 = "error message 1";
final String errorMessage_2 = "error message 2";

final String sql = "SELECT event_number, previous_event_number FROM some_table ORDER BY event_number";
final String sql = "SELECT event_number, previous_event_number FROM processed_event ORDER BY event_number";

final DataSource dataSource = mock(DataSource.class);
final Connection connection = mock(Connection.class);
Expand All @@ -105,24 +112,26 @@ public void shouldReturnAllErrors() throws Exception {
when(resultSet.getInt("previous_event_number")).thenReturn(0, 2, 4);
when(resultSet.getInt("event_number")).thenReturn(1, 3, 5);

when(eventLinkageErrorMessageGenerator.generateErrorMessage(2, 3, 1, PROCESSED_EVENT)).thenReturn(errorMessage_1);
when(eventLinkageErrorMessageGenerator.generateErrorMessage(4, 5, 3, PROCESSED_EVENT)).thenReturn(errorMessage_2);

final List<VerificationResult> publishedEventsResults = eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(
tableName,
PROCESSED_EVENT,
dataSource);

assertThat(publishedEventsResults.size(), is(2));
assertThat(publishedEventsResults.get(0).getVerificationResultType(), is(ERROR));
assertThat(publishedEventsResults.get(0).getMessage(), is("Events incorrectly linked in some_table table. Event with event number 3 is linked to previous event number 2 whereas it should be 1"));
assertThat(publishedEventsResults.get(0).getMessage(), is(errorMessage_1));
assertThat(publishedEventsResults.get(1).getVerificationResultType(), is(ERROR));
assertThat(publishedEventsResults.get(1).getMessage(), is("Events incorrectly linked in some_table table. Event with event number 5 is linked to previous event number 4 whereas it should be 3"));
assertThat(publishedEventsResults.get(1).getMessage(), is(errorMessage_2));
}

@Test
public void shouldThrowExceptionIfDataAccessFails() throws Exception {

final SQLException sqlException = new SQLException("Ooops");
final String tableName = "some_table";

final String sql = "SELECT event_number, previous_event_number FROM some_table ORDER BY event_number";
final String sql = "SELECT event_number, previous_event_number FROM published_event ORDER BY event_number";

final DataSource dataSource = mock(DataSource.class);
final Connection connection = mock(Connection.class);
Expand All @@ -136,12 +145,12 @@ public void shouldThrowExceptionIfDataAccessFails() throws Exception {

try {
eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(
tableName,
PUBLISHED_EVENT,
dataSource);
fail();
} catch (final CatchupVerificationException expected) {
assertThat(expected.getCause(), is(sqlException));
assertThat(expected.getMessage(), is("Failed to get event numbers from some_table table"));
assertThat(expected.getMessage(), is("Failed to get event numbers from published_event table"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package uk.gov.justice.services.eventstore.management.validation.process;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PROCESSED_EVENT;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PUBLISHED_EVENT;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class EventLinkageErrorMessageGeneratorTest {

@InjectMocks
private EventLinkageErrorMessageGenerator eventLinkageErrorMessageGenerator;

@Test
public void shouldGenerateTheCorrectErrorMessageForPublishedEvent() throws Exception {

final int previousEventNumber = 23;
final int currentEventNumber = 24;
final int lastEvenNumber = 13;

final String errorMessage = eventLinkageErrorMessageGenerator.generateErrorMessage(
previousEventNumber,
currentEventNumber,
lastEvenNumber,
PUBLISHED_EVENT);

assertThat(errorMessage, is("Events incorrectly linked in published_event table: " +
"Event with event number 24 is linked to previous event number 23 " +
"whereas it should be 13"));
}

@Test
public void shouldGenerateTheCorrectErrorMessageForProcessedEvent() throws Exception {

final int previousEventNumber = 41;
final int currentEventNumber = 42;
final int lastEvenNumber = 23;

final String errorMessage = eventLinkageErrorMessageGenerator.generateErrorMessage(
previousEventNumber,
currentEventNumber,
lastEvenNumber,
PROCESSED_EVENT);

assertThat(errorMessage, is("Events missing from processed_event table: " +
"Event with event_number 42 has a previous_event_number of 41, " +
"but the event in the previous row in the database has an event_number of 23"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PROCESSED_EVENT;

import uk.gov.justice.services.eventstore.management.validation.process.EventLinkageChecker;
import uk.gov.justice.services.eventstore.management.validation.process.VerificationResult;
Expand Down Expand Up @@ -44,7 +45,7 @@ public void shouldCheckTheLinkingOfEventNumbersInProcessedEvent() throws Excepti

when(viewStoreJdbcDataSourceProvider.getDataSource()).thenReturn(viewStoreDataSource);

when(eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly("processed_event", viewStoreDataSource)).thenReturn(results);
when(eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(PROCESSED_EVENT, viewStoreDataSource)).thenReturn(results);

assertThat(processedEventLinkVerifier.verify(), is(results));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static uk.gov.justice.services.eventstore.management.validation.process.LinkedEventNumberTable.PUBLISHED_EVENT;

import uk.gov.justice.services.eventsourcing.source.core.EventStoreDataSourceProvider;
import uk.gov.justice.services.eventstore.management.validation.process.EventLinkageChecker;
Expand Down Expand Up @@ -45,7 +46,7 @@ public void shouldCheckTheLinkingOfEventNumbersInPublishedEvent() throws Excepti

when(eventStoreDataSourceProvider.getDefaultDataSource()).thenReturn(eventStoreDataSource);

when(eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly("published_event", eventStoreDataSource)).thenReturn(results);
when(eventLinkageChecker.verifyEventNumbersAreLinkedCorrectly(PUBLISHED_EVENT, eventStoreDataSource)).thenReturn(results);

assertThat(publishedEventLinkVerifier.verify(), is(results));
}
Expand Down

0 comments on commit f418183

Please sign in to comment.