diff --git a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/AbstractIT.java b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/AbstractIT.java index 616ab69dc..ec4743129 100644 --- a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/AbstractIT.java +++ b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/AbstractIT.java @@ -294,8 +294,8 @@ protected void stubProsecutionCases(final Hearing hearing) { hearing.getProsecutionCases().forEach(prosecutionCase -> stubGetProgressionProsecutionCases(prosecutionCase.getId())); } - protected void cleanDatabase(final String dbTableName) { + protected void cleanDatabase(final String dbTableName, final String... additionalTables) { final DatabaseCleaner databaseCleaner = new DatabaseCleaner(); - databaseCleaner.cleanViewStoreTables(CONTEXT_NAME, dbTableName); + databaseCleaner.cleanViewStoreTables(CONTEXT_NAME, dbTableName, additionalTables); } } diff --git a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/CourtListRestrictionIT.java b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/CourtListRestrictionIT.java index 00ea86154..34217a8d0 100644 --- a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/CourtListRestrictionIT.java +++ b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/it/CourtListRestrictionIT.java @@ -1,5 +1,6 @@ package uk.gov.moj.cpp.hearing.it; +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath; import static com.jayway.jsonpath.matchers.JsonPathMatchers.isJson; import static com.jayway.jsonpath.matchers.JsonPathMatchers.withJsonPath; import static java.util.Optional.of; @@ -11,6 +12,10 @@ import static org.hamcrest.Matchers.is; import static uk.gov.moj.cpp.hearing.it.PublishLatestCourtCentreHearingEventsIT.XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26; import static uk.gov.moj.cpp.hearing.steps.HearingEventStepDefinitions.OPEN_CASE_PROSECUTION_EVENT_DEFINITION_ID; +import static uk.gov.moj.cpp.hearing.utils.WebDavStub.awaitNewFile; +import static uk.gov.moj.cpp.hearing.utils.WebDavStub.awaitNewSentXmlForPubDisplay; +import static uk.gov.moj.cpp.hearing.utils.WebDavStub.countFilesAt; +import static uk.gov.moj.cpp.hearing.utils.WebDavStub.countSentXmlForPubDisplay; import static uk.gov.moj.cpp.hearing.utils.WebDavStub.getFileForPath; import static uk.gov.moj.cpp.hearing.utils.WebDavStub.getSentXmlForPubDisplay; @@ -35,9 +40,30 @@ public class CourtListRestrictionIT extends AbstractPublishLatestCourtCentreHear private ZonedDateTime eventTime; + /** + * Clean every table that can carry state across tests in this class. All five tests bind + * their hearings to the SAME static {@code caseId} (see + * {@link AbstractPublishLatestCourtCentreHearingIT}), so residual + * {@code is_court_list_restricted=true} on {@code ha_case} (the {@code ProsecutionCase} + * entity's table — see its {@code @Table} annotation) or {@code ha_defendant} from one + * test poisons the next. The {@code court_list_publish_status} row is also dropped so the + * FIRST publish in this class cannot inherit {@code EXPORT_SUCCESSFUL} from a prior test + * class's publish — without this, + * {@code verifyCourtListPublishStatusReturnedWhenQueryingFromAPI} returns on the stale + * status before the current publish has produced a file. + */ + private void cleanRestrictionTables() { + cleanDatabase("ha_hearing", + "ha_case", + "ha_defendant", + "ha_hearing_day", + "ha_hearing_event", + "court_list_publish_status"); + } + @BeforeEach public void setUpTest() { - cleanDatabase("ha_hearing"); + cleanRestrictionTables(); eventTime = new UtcClock().now().minusMinutes(5L); } @@ -54,7 +80,7 @@ public void setUpTest() { */ @AfterEach public void tearDownTest() { - cleanDatabase("ha_hearing"); + cleanRestrictionTables(); } @Test @@ -71,6 +97,10 @@ public void shouldRequestToPublishCourtListWithCaseRestriction() throws Exceptio withJsonPath("$.caseIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(true))))); + // Wait for the restriction projection to land before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails", hasSize(0))); + JsonObject publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); final PublishCourtListSteps publishCourtListSteps = new PublishCourtListSteps(); @@ -96,11 +126,20 @@ public void shouldRequestToPublishCourtListWithCaseRestriction() throws Exceptio withJsonPath("$.caseIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(false))))); + // Wait for the un-restriction projection to land before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails", hasSize(1))); + publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); + final int webPageCountBeforeSecondPublish = countFilesAt(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); + final int pubDisplayCountBeforeSecondPublish = countSentXmlForPubDisplay(); + courtCentreId = sendPublishCourtListCommand(publishCourtListJsonObject, courtCentreId); publishCourtListSteps.verifyCourtListPublishStatusReturnedWhenQueryingFromAPI(courtCentreId); + awaitNewFile(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26, webPageCountBeforeSecondPublish); + awaitNewSentXmlForPubDisplay(pubDisplayCountBeforeSecondPublish); filePayload = getFileForPath(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); filePayloadForPubDisplay = getSentXmlForPubDisplay(); @@ -127,6 +166,10 @@ public void shouldRequestToPublishCourtListWithDefendantRestrictionOnOff() throw withJsonPath("$.defendantIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(true))))); + // Wait for defendant restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails[0].defendants", hasSize(0))); + final JsonObject publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); final PublishCourtListSteps publishCourtListSteps = new PublishCourtListSteps(); @@ -155,8 +198,17 @@ public void shouldRequestToPublishCourtListWithDefendantRestrictionOnOff() throw withJsonPath("$.defendantIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(false))))); + // Wait for defendant un-restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails[0].defendants", hasSize(1))); + + final int webPageCountBeforeSecondPublish = countFilesAt(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); + final int pubDisplayCountBeforeSecondPublish = countSentXmlForPubDisplay(); + courtCentreId = sendPublishCourtListCommand(publishCourtListJsonObject, courtCentreId); publishCourtListSteps.verifyCourtListPublishStatusReturnedWhenQueryingFromAPI(courtCentreId); + awaitNewFile(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26, webPageCountBeforeSecondPublish); + awaitNewSentXmlForPubDisplay(pubDisplayCountBeforeSecondPublish); filePayload = getFileForPath(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); filePayloadForPubDisplay = getSentXmlForPubDisplay(); @@ -191,6 +243,10 @@ public void shouldRequestToPublishCourtListForApplicationRestrictionOnOff() thro withJsonPath("$.courtApplicationIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(true))))); + // Wait for application restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails", hasSize(0))); + JsonObject publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); final PublishCourtListSteps publishCourtListSteps = new PublishCourtListSteps(); @@ -216,11 +272,20 @@ public void shouldRequestToPublishCourtListForApplicationRestrictionOnOff() thro withJsonPath("$.courtApplicationIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(false))))); + // Wait for application un-restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails", hasSize(1))); + publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); + final int webPageCountBeforeSecondPublish = countFilesAt(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); + final int pubDisplayCountBeforeSecondPublish = countSentXmlForPubDisplay(); + courtCentreId = sendPublishCourtListCommand(publishCourtListJsonObject, courtCentreId); publishCourtListSteps.verifyCourtListPublishStatusReturnedWhenQueryingFromAPI(courtCentreId); + awaitNewFile(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26, webPageCountBeforeSecondPublish); + awaitNewSentXmlForPubDisplay(pubDisplayCountBeforeSecondPublish); filePayload = getFileForPath(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); filePayloadForPubDisplay = getSentXmlForPubDisplay(); @@ -249,6 +314,10 @@ public void shouldRequestToPublishCourtListForApplicationApplicantRestrictionOnO withJsonPath("$.courtApplicationApplicantIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(true))))); + // Wait for applicant restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + hasNoJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails[0].defendants[0].firstName")); + JsonObject publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); final PublishCourtListSteps publishCourtListSteps = new PublishCourtListSteps(); @@ -274,11 +343,20 @@ public void shouldRequestToPublishCourtListForApplicationApplicantRestrictionOnO withJsonPath("$.courtApplicationApplicantIds", hasSize(1)), withJsonPath("$.restrictCourtList", is(false))))); + // Wait for applicant un-restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails[0].defendants[0].firstName", org.hamcrest.CoreMatchers.notNullValue())); + publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); + final int webPageCountBeforeSecondPublish = countFilesAt(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); + final int pubDisplayCountBeforeSecondPublish = countSentXmlForPubDisplay(); + courtCentreId = sendPublishCourtListCommand(publishCourtListJsonObject, courtCentreId); publishCourtListSteps.verifyCourtListPublishStatusReturnedWhenQueryingFromAPI(courtCentreId); + awaitNewFile(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26, webPageCountBeforeSecondPublish); + awaitNewSentXmlForPubDisplay(pubDisplayCountBeforeSecondPublish); filePayload = getFileForPath(XHIBIT_GATEWAY_SEND_WEB_PAGE_TO_XHIBIT_FILE_NAME_26); filePayloadForPubDisplay = getSentXmlForPubDisplay(); @@ -308,6 +386,10 @@ public void shouldRequestToPublishCourtListWhenYoungDefendantIsRestrictedOnIniti caseId, randomUUID(), courtRoom2Id, randomUUID().toString(), OPEN_CASE_PROSECUTION_EVENT_DEFINITION_ID, eventTime, of(hearingTypeId), courtCentreId, eventTime.toLocalDate()); + // Wait for the young-defendant restriction to land in the projection before publishing + courtListRestrictionSteps.waitForRestrictionProjection(courtCentreId, eventTime.toLocalDate(), + withJsonPath("$.court.courtSites[0].courtRooms[0].cases.casesDetails[0].defendants", hasSize(0))); + final JsonObject publishCourtListJsonObject = buildPublishCourtListJsonString(courtCentreId, "26"); final PublishCourtListSteps publishCourtListSteps = new PublishCourtListSteps(); diff --git a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/steps/CourtListRestrictionSteps.java b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/steps/CourtListRestrictionSteps.java index 65423c2ed..cf1ddea89 100644 --- a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/steps/CourtListRestrictionSteps.java +++ b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/steps/CourtListRestrictionSteps.java @@ -3,11 +3,22 @@ import static com.google.common.collect.Lists.newArrayList; import static com.jayway.jsonpath.matchers.JsonPathMatchers.isJson; import static com.jayway.jsonpath.matchers.JsonPathMatchers.withJsonPath; +import static java.text.MessageFormat.format; import static java.util.UUID.fromString; import static java.util.UUID.randomUUID; +import static java.util.concurrent.TimeUnit.SECONDS; +import static javax.ws.rs.core.Response.Status.OK; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static uk.gov.justice.services.common.http.HeaderConstants.USER_ID; +import static uk.gov.justice.services.test.utils.core.http.BaseUriProvider.getBaseUri; +import static uk.gov.justice.services.test.utils.core.http.RequestParamsBuilder.requestParams; +import static uk.gov.justice.services.test.utils.core.http.RestPoller.poll; +import static uk.gov.justice.services.test.utils.core.matchers.ResponsePayloadMatcher.payload; +import static uk.gov.justice.services.test.utils.core.matchers.ResponseStatusMatcher.status; +import static uk.gov.moj.cpp.hearing.utils.WireMockStubUtils.setupAsAuthorizedAndSystemUser; import static uk.gov.justice.hearing.courts.CourtListRestricted.courtListRestricted; import static uk.gov.justice.services.test.utils.core.messaging.MetadataBuilderFactory.metadataWithRandomUUID; import static uk.gov.moj.cpp.hearing.it.UseCases.asDefault; @@ -32,6 +43,10 @@ import uk.gov.moj.cpp.hearing.test.CommandHelpers; import java.security.NoSuchAlgorithmException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import java.time.LocalDate; import java.time.ZonedDateTime; import java.util.Optional; @@ -42,8 +57,11 @@ import io.restassured.path.json.JsonPath; import com.fasterxml.jackson.databind.ObjectMapper; +import org.awaitility.Awaitility; import org.hamcrest.Matcher; import org.junit.jupiter.api.BeforeEach; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class CourtListRestrictionSteps extends AbstractIT { @@ -87,6 +105,103 @@ public JsonPath hearingEventsCourtListRestrictedReceived(final Matcher matche } } + /** + * Polls the publish-side query {@code hearing.latest-hearings-by-court-centres} until the + * restriction projection has reached the expected state. The publish flow internally consumes + * the same query — once it reflects the toggle, the next {@code publish-court-list} command is + * guaranteed to see the same state. + *

+ * Required because {@link #hearingEventsCourtListRestrictedReceived(Matcher)} only confirms the + * hearing event was emitted; the listener that projects it into the JPA entity runs in a + * separate transaction and may lag behind the publish command if not waited for. + *

+ * A hearing-visibility precondition ({@code courtRoomId notNullValue}) is prepended to the + * caller's matcher to prevent the poll from short-circuiting on the empty/not-yet-projected + * state — without this, lenient matchers such as {@code hasNoJsonPath(...)} or + * {@code withJsonPath(..., hasSize(0))} would match an empty {@code {}} response and return + * before the restriction event has actually been processed. + */ + public void waitForRestrictionProjection(final String courtCentreId, + final LocalDate hearingDate, + final Matcher expectedPayload) { + setupAsAuthorizedAndSystemUser(USER_ID_VALUE_AS_ADMIN); + final String queryPart = format(ENDPOINT_PROPERTIES.getProperty("hearing.latest-hearings-by-court-centres"), courtCentreId, hearingDate); + final String searchCourtListUrl = String.format("%s/%s", getBaseUri(), queryPart); + + poll(requestParams(searchCourtListUrl, "application/vnd.hearing.latest-hearings-by-court-centres+json") + .withHeader(USER_ID, getLoggedInSystemUserHeader())) + .timeout(60, SECONDS) + .pollInterval(1, SECONDS) + .until(status().is(OK), payload().isJson(allOf( + withJsonPath("$.court.courtSites[0].courtRooms[0].courtRoomId", notNullValue()), + expectedPayload))); + } + + /** + * Polls the view-store DB directly until the just-created hearing has BOTH + * {@code ha_hearing} AND {@code ha_hearing_day} rows for the given courtCentreId/date. + * MUST be called after {@code createHearingEvent*} and BEFORE any {@code hide*FromXhibit} + * call or any {@code sendPublishCourtListCommand}. + * + *

Two races this closes

+ * + *

1. The listener silent-drop race. + * Without this wait, the {@code public.listing.court-list-restricted} → ... → + * {@code hearing.event.court-list-restricted} chain can reach + * {@link uk.gov.moj.cpp.hearing.event.listener.CourtListRestrictionEventListener} before the + * hearing-creation projection has committed to {@code ha_hearing}. The listener does + * {@code hearingRepository.findOptionalBy(hearingId)} and, if the row is missing, silently + * returns — the message is consumed and never replayed, the restriction is lost, the + * subsequent publish reads the un-restricted hearing, and the assertion on the redacted XML + * fails. + * + *

2. The pub-display empty-XML race. + * Even when {@code ha_hearing} is populated, the publish's pub-display query + * ({@code findHearingsByDateAndCourtCentreList}) INNER-JOINs {@code ha_hearing.hearingDays} + * filtered by date. If {@code ha_hearing_day} hasn't been projected yet when the publish + * runs, the pub-display query returns thin/empty data and the publish writes an XML with + * empty fields (empty courtname, cppurn, defendant fields, no {@code currentstatus} block). + * The web-page publish (which goes via {@code ha_hearing_event}) is unaffected and writes + * correct XML, so the test sees a mismatch where the same publish call produces correct + * web-page XML but stub pub-display XML. + * + *

Polling JDBC directly is more robust than polling either REST endpoint because both + * publish-side queries are gated on the same two tables; once both are populated, both + * publishes will see fresh data. + */ + public void waitForHearingVisible(final String courtCentreId, final LocalDate hearingDate) { + Awaitility.await() + .atMost(60, SECONDS) + .pollInterval(500, java.util.concurrent.TimeUnit.MILLISECONDS) + .until(() -> hearingProjectedFor(courtCentreId, hearingDate)); + } + + private boolean hearingProjectedFor(final String courtCentreId, final LocalDate hearingDate) { + // Both publish paths need all three tables. Web-page goes via ha_hearing_event; + // pub-display additionally INNER-JOINs ha_hearing_day. + final String sql = String.format( + "SELECT count(1) FROM ha_hearing h " + + "INNER JOIN ha_hearing_day day ON day.hearing_id = h.id " + + "INNER JOIN ha_hearing_event ev ON ev.hearing_id = h.id " + + "WHERE h.court_centre_id = '%s' " + + "AND day.date = '%s' " + + "AND ev.event_date = '%s' " + + "AND ev.deleted = false", + courtCentreId, hearingDate, hearingDate); + try (final Connection connection = testJdbcConnectionProvider.getViewStoreConnection("hearing"); + final Statement statement = connection.createStatement(); + final ResultSet resultSet = statement.executeQuery(sql)) { + if (resultSet.next()) { + return resultSet.getInt(1) > 0; + } + } catch (final SQLException e) { + HEARING_VISIBILITY_LOGGER.warn("Failed to query view store for visibility check: {}", e.getMessage()); + } + return false; + } + + private static final Logger HEARING_VISIBILITY_LOGGER = LoggerFactory.getLogger(CourtListRestrictionSteps.class); + private void sendListingPublicEvent(final JsonObject restrictCourtListDataObject) { sendMessage( getPublicTopicInstance().createProducer(), @@ -99,11 +214,12 @@ public CommandHelpers.InitiateHearingCommandHelper createHearingEvent(final UUID final UUID eventDefinitionId, final ZonedDateTime eventTime, final Optional hearingTypeId, String courtCenter, LocalDate localDate) throws NoSuchAlgorithmException { final CommandHelpers.InitiateHearingCommandHelper hearing = h(UseCases.initiateHearingWithNsp(getRequestSpec(), initiateHearingTemplateWithParamNoReportingRestriction(fromString(courtCenter), fromString(courtRoomId), "CourtRoom 1", localDate, fromString(defenceCounselId), caseId, hearingTypeId))); logEvent(hearingEventId, getRequestSpec(), asDefault(), hearing.it(), eventDefinitionId, false, fromString(defenceCounselId), eventTime, null); + waitForHearingVisible(courtCenter, eventTime.toLocalDate()); return hearing; } public CommandHelpers.InitiateHearingCommandHelper createHearingEventWithYoungDefendant(final UUID caseId, final UUID hearingEventId, final String courtRoomId, final String defenceCounselId, - final UUID eventDefinitionId, final ZonedDateTime eventTime, final Optional hearingTypeId, final String courtCenter, final LocalDate localDate) throws NoSuchAlgorithmException { + final UUID eventDefinitionId, final ZonedDateTime eventTime, final Optional hearingTypeId, final String courtCenter, final LocalDate localDate) throws NoSuchAlgorithmException { try (final Utilities.EventListener eventListener = listenFor(HEARING_EVENTS_COURT_LIST_RESTRICTED, HEARING_EVENT) .withFilter(isJson(allOf( withJsonPath("$.defendantIds", hasSize(1)), @@ -112,6 +228,7 @@ public CommandHelpers.InitiateHearingCommandHelper createHearingEventWithYoungDe initiateHearingTemplateWithParamNoReportingRestrictionYoungDefendant(fromString(courtCenter), fromString(courtRoomId), "CourtRoom 1", localDate, fromString(defenceCounselId), caseId, hearingTypeId))); logEvent(hearingEventId, getRequestSpec(), asDefault(), hearing.it(), eventDefinitionId, false, fromString(defenceCounselId), eventTime, null); eventListener.waitFor(); + waitForHearingVisible(courtCenter, eventTime.toLocalDate()); return hearing; } } @@ -121,6 +238,7 @@ public CommandHelpers.InitiateHearingCommandHelper createHearingEventForApplicat final CommandHelpers.InitiateHearingCommandHelper hearing = h(initiateHearingForApplication(getRequestSpec(), initiateHearingTemplateForApplicationNoReportingRestriction(fromString(courtCenter), fromString(courtRoomId), "CourtRoom 1", localDate, fromString(defenceCounselId), caseId, hearingTypeId))); givenAUserHasLoggedInAsACourtClerk(randomUUID()); logEvent(hearingEventId, getRequestSpec(), asDefault(), hearing.it(), eventDefinitionId, false, fromString(defenceCounselId), eventTime, null); + waitForHearingVisible(courtCenter, eventTime.toLocalDate()); return hearing; } diff --git a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/utils/WebDavStub.java b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/utils/WebDavStub.java index 7c30374ed..8411194ea 100644 --- a/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/utils/WebDavStub.java +++ b/hearing-integration-test/src/test/java/uk/gov/moj/cpp/hearing/utils/WebDavStub.java @@ -7,11 +7,13 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; import static javax.ws.rs.core.Response.Status.OK; +import static org.awaitility.Durations.ONE_MINUTE; import java.util.List; import java.util.UUID; import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import org.awaitility.Awaitility; public class WebDavStub { @@ -35,4 +37,22 @@ public static String getFileForPath(final String filePath) { return loggedRequest.getBodyAsString(); } + + public static int countFilesAt(final String filePath) { + return findAll(putRequestedFor(urlPathMatching(filePath))).size(); + } + + public static int countSentXmlForPubDisplay() { + return countFilesAt(XHIBIT_GATEWAY_SEND_PUB_DISP_TO_XHIBIT_FILE_PATH_REG_EX); + } + + public static void awaitNewFile(final String filePath, final int previousCount) { + Awaitility.await() + .atMost(ONE_MINUTE) + .until(() -> countFilesAt(filePath) > previousCount); + } + + public static void awaitNewSentXmlForPubDisplay(final int previousCount) { + awaitNewFile(XHIBIT_GATEWAY_SEND_PUB_DISP_TO_XHIBIT_FILE_PATH_REG_EX, previousCount); + } }