diff --git a/src/main/java/com/conveyal/datatools/manager/jobs/AutoPublishJob.java b/src/main/java/com/conveyal/datatools/manager/jobs/AutoPublishJob.java index e8da846ea..eda22688f 100644 --- a/src/main/java/com/conveyal/datatools/manager/jobs/AutoPublishJob.java +++ b/src/main/java/com/conveyal/datatools/manager/jobs/AutoPublishJob.java @@ -43,6 +43,8 @@ protected void innerJobLogic() throws Exception { // Validate and check for blocking issues in the feed version to deploy. if (latestFeedVersion.hasExpired()) { status.fail("Could not publish this feed version because it has expired."); + } else if (latestFeedVersion.isFuture()) { + status.fail("Could not publish this feed version because it is in the future."); } else if (latestFeedVersion.hasBlockingIssuesForPublishing()) { status.fail("Could not publish this feed version because it contains blocking errors."); } else { diff --git a/src/main/java/com/conveyal/datatools/manager/models/FeedVersion.java b/src/main/java/com/conveyal/datatools/manager/models/FeedVersion.java index 6f8586bc8..7c62e20fa 100644 --- a/src/main/java/com/conveyal/datatools/manager/models/FeedVersion.java +++ b/src/main/java/com/conveyal/datatools/manager/models/FeedVersion.java @@ -551,6 +551,21 @@ public static boolean hasExpired(ValidationResult validationResult) { getNowAsLocalDate().isAfter(validationResult.lastCalendarDate); } + /** + * Whether the Has this feed expired? + * @return If the validation result last calendar date is null or has expired return true, else return false. + */ + @JsonIgnore + @BsonIgnore + public boolean isFuture() { + return isFuture(validationResult); + } + + public static boolean isFuture(ValidationResult validationResult) { + return validationResult.firstCalendarDate != null && + getNowAsLocalDate().isBefore(validationResult.firstCalendarDate); + } + private static LocalDate getNowAsLocalDate() { return dateOverrideForTesting == null ? LocalDate.now() : dateOverrideForTesting; } diff --git a/src/main/java/com/conveyal/datatools/manager/models/FeedVersionSummary.java b/src/main/java/com/conveyal/datatools/manager/models/FeedVersionSummary.java index 27d6096b6..0aa8bb9a3 100644 --- a/src/main/java/com/conveyal/datatools/manager/models/FeedVersionSummary.java +++ b/src/main/java/com/conveyal/datatools/manager/models/FeedVersionSummary.java @@ -232,6 +232,7 @@ private boolean isPublishBlocked() { !gtfsPlusValidation.issues.isEmpty() || !gtfsPlusValidation.published || FeedVersion.hasExpired(validationResult) || + FeedVersion.isFuture(validationResult) || hasBlockingIssuesForPublishing(); } diff --git a/src/test/java/com/conveyal/datatools/manager/controllers/api/FeedSourceControllerTest.java b/src/test/java/com/conveyal/datatools/manager/controllers/api/FeedSourceControllerTest.java index f8ad6b0ae..c3d0a16f4 100644 --- a/src/test/java/com/conveyal/datatools/manager/controllers/api/FeedSourceControllerTest.java +++ b/src/test/java/com/conveyal/datatools/manager/controllers/api/FeedSourceControllerTest.java @@ -13,7 +13,6 @@ import com.conveyal.datatools.manager.models.FeedSourceSummary; import com.conveyal.datatools.manager.models.FeedValidationResultSummary; import com.conveyal.datatools.manager.models.FeedVersion; -import com.conveyal.datatools.manager.models.FeedVersionSummary; import com.conveyal.datatools.manager.models.FetchFrequency; import com.conveyal.datatools.manager.models.Label; import com.conveyal.datatools.manager.models.Note; @@ -27,9 +26,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import java.io.IOException; import java.net.MalformedURLException; @@ -37,11 +33,9 @@ import java.time.LocalDate; import java.time.Month; import java.time.ZoneId; -import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.stream.Stream; import static com.conveyal.datatools.TestUtils.createFeedVersionFromGtfsZip; import static com.mongodb.client.model.Filters.eq; @@ -51,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -public class FeedSourceControllerTest extends DatatoolsTest { +class FeedSourceControllerTest extends DatatoolsTest { private static Project project = null; private static Project projectToBeDeleted = null; private static FeedSource feedSourceWithUrl = null; @@ -70,7 +64,7 @@ public class FeedSourceControllerTest extends DatatoolsTest { private static FeedVersion feedVersionFromPinnedDeployment = null; @BeforeAll - public static void setUp() throws IOException { + static void settingUp() throws IOException { DatatoolsTest.setUp(); Auth0Connection.setAuthDisabled(true); ProcessSingleFeedJob.ENABLE_ADDITIONAL_VALIDATION = false; @@ -206,7 +200,7 @@ private static void setUpFeedVersionFromPinnedDeployment() throws MalformedURLEx } @AfterAll - public static void tearDown() { + static void tearDown() { Auth0Connection.setAuthDisabled(Auth0Connection.getDefaultAuthDisabled()); if (project != null) { project.delete(); @@ -243,7 +237,7 @@ private static void tearDownDeployedFeedVersion() { * 3. Update the same feed source turning auth fetch back on and confirm it is scheduled once more. */ @Test - public void createFeedSourceWithUrlTest() { + void createFeedSourceWithUrlTest() { // create a feed source. SimpleHttpResponse createFeedSourceResponse = TestUtils.makeRequest("/api/manager/secure/feedsource", JsonUtil.toJson(feedSourceWithUrl), @@ -278,7 +272,7 @@ public void createFeedSourceWithUrlTest() { * Create a feed source without defining the feed source url. Confirm that the feed source is not scheduled. */ @Test - public void createFeedSourceWithNoUrlTest() { + void createFeedSourceWithNoUrlTest() { SimpleHttpResponse createFeedSourceResponse = TestUtils.makeRequest("/api/manager/secure/feedsource", JsonUtil.toJson(feedSourceWithNoUrl), HttpUtils.REQUEST_METHOD.POST @@ -292,7 +286,7 @@ public void createFeedSourceWithNoUrlTest() { * Create some labels, add them to the feed source make them admin only, and check that they don't appear if not an admin */ @Test - public void createFeedSourceWithLabels() { + void createFeedSourceWithLabels() { // Create labels SimpleHttpResponse createFirstLabelResponse = TestUtils.makeRequest("/api/manager/secure/label", JsonUtil.toJson(publicLabel), @@ -439,72 +433,6 @@ void canRetrieveDeployedFeedVersionFromPinnedDeployment() throws IOException { assertEquals(feedSourceWithPinnedDeploymentFeedVersion.publishedVersionId, firstSummary.publishedVersionId); } - @ParameterizedTest - @MethodSource("createPublishStates") - void canDeterminePublishState( - boolean isPublished, - boolean isPublishing, - boolean isPublishBlocked, - boolean isFeedLoading, - PublishState expectedPublishState - ) { - FeedSourceSummary feedSourceSummary = new FeedSourceSummary(); - FeedVersionSummary feedVersionSummary = new FeedVersionSummary(); - FeedVersion.setDateOverrideForTesting(LocalDate.now()); - - if (isPublished) { - feedVersionSummary.namespace = feedVersionSummary.feedSourcePublishedVersionId = "namespace"; - } - if (isPublishing) { - feedVersionSummary.sentToExternalPublisher = new Date(); - feedVersionSummary.processedByExternalPublisher = null; - } - if (isPublishBlocked) { - feedVersionSummary.gtfsPlusValidation = null; - } - if (!isPublished && !isPublishing && !isPublishBlocked && !isFeedLoading) { - // Ready to publish case. - FeedVersionSummary.setHasBlockingIssueForPublishingOverrideForTesting(false); - passPublishBlockedCheck(feedVersionSummary); - - feedVersionSummary.validationResult.errorCount = 1; - feedVersionSummary.id = "feed-version-id"; - feedSourceSummary.id = "feed-source-id"; - } - PublishState publishState = feedVersionSummary.getPublishState(); - assertEquals(expectedPublishState, publishState); - FeedVersionSummary.setHasBlockingIssueForPublishingOverrideForTesting(null); - } - - /** - * Set up a feed version summary to pass the publish blocked check. - */ - private static void passPublishBlockedCheck(FeedVersionSummary feedVersionSummary) { - feedVersionSummary.gtfsPlusValidation = new GtfsPlusValidation(); - feedVersionSummary.gtfsPlusValidation.issues = new ArrayList<>(); - feedVersionSummary.gtfsPlusValidation.published = true; - feedVersionSummary.validationResult = new ValidationResult(); - feedVersionSummary.validationResult.lastCalendarDate = LocalDate.now().plusDays(1); - FeedVersion.setDateOverrideForTesting(LocalDate.now()); - } - - private static Stream createPublishStates() { - return Stream.of( - Arguments.of( - true, false, false, false, PublishState.PUBLISHED - ), - Arguments.of( - false, true, false, false, PublishState.PUBLISHING - ), - Arguments.of( - false, false, true, false, PublishState.PUBLISH_BLOCKED - ), - Arguments.of( - false, false, false, false, PublishState.READY_TO_PUBLISH - ) - ); - } - private static Project createProject(String name, boolean autoFetchFeeds) { Project project = new Project(); project.name = name; diff --git a/src/test/java/com/conveyal/datatools/manager/jobs/AutoPublishJobTest.java b/src/test/java/com/conveyal/datatools/manager/jobs/AutoPublishJobTest.java index 16caf3caf..8b59d10f4 100644 --- a/src/test/java/com/conveyal/datatools/manager/jobs/AutoPublishJobTest.java +++ b/src/test/java/com/conveyal/datatools/manager/jobs/AutoPublishJobTest.java @@ -41,7 +41,7 @@ /** * Tests for the various {@link AutoPublishJob} cases. */ -public class AutoPublishJobTest extends UnitTest { +class AutoPublishJobTest extends UnitTest { private static final String TEST_COMPLETED_FOLDER = "test-completed"; private static final Auth0UserProfile user = Auth0UserProfile.createTestAdminUser(); private static Project project; @@ -52,7 +52,7 @@ public class AutoPublishJobTest extends UnitTest { * Prepare and start a testing-specific web server */ @BeforeAll - public static void setUp() throws IOException { + static void setUp() throws IOException { // start server if it isn't already running DatatoolsTest.setUp(); @@ -92,7 +92,7 @@ void afterEach() { } @AfterAll - public static void tearDown() { + static void tearDown() { Auth0Connection.setAuthDisabled(Auth0Connection.getDefaultAuthDisabled()); if (project != null) { project.delete(); @@ -140,6 +140,7 @@ void shouldProcessFeed(String resourceName, LocalDate nowDate, boolean isError, private static Stream createPublishFeedCases() { LocalDate feedValidDate = LocalDate.of(2019, 3, 1); + LocalDate feedBeforeValidDate = LocalDate.of(2010, 3, 1); return Stream.of( Arguments.of( "fake-agency-with-only-calendar-expire-in-2099-with-failed-referential-integrity", @@ -164,6 +165,12 @@ private static Stream createPublishFeedCases() { null, true, "Could not publish this feed version because it has expired." + ), + Arguments.of( + "bart_new_lite.zip", + feedBeforeValidDate, + true, + "Could not publish this feed version because it is in the future." ) ); } diff --git a/src/test/java/com/conveyal/datatools/manager/models/FeedVersionSummaryTest.java b/src/test/java/com/conveyal/datatools/manager/models/FeedVersionSummaryTest.java new file mode 100644 index 000000000..05dbc74b5 --- /dev/null +++ b/src/test/java/com/conveyal/datatools/manager/models/FeedVersionSummaryTest.java @@ -0,0 +1,112 @@ +package com.conveyal.datatools.manager.models; + +import com.conveyal.datatools.DatatoolsTest; +import com.conveyal.datatools.manager.gtfsplus.GtfsPlusValidation; +import com.conveyal.gtfs.validator.ValidationResult; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Date; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FeedVersionSummaryTest extends DatatoolsTest { + @BeforeAll + static void settingUp() throws IOException { + DatatoolsTest.setUp(); + } + + @AfterEach + void afterEach() { + FeedVersionSummary.setHasBlockingIssueForPublishingOverrideForTesting(null); + } + + @ParameterizedTest + @MethodSource("createPublishStates") + void canDeterminePublishState( + boolean isPublished, + boolean isPublishing, + boolean isPublishBlocked, + boolean isFeedLoading, + PublishState expectedPublishState + ) { + FeedSourceSummary feedSourceSummary = new FeedSourceSummary(); + FeedVersionSummary feedVersionSummary = new FeedVersionSummary(); + FeedVersion.setDateOverrideForTesting(LocalDate.now()); + + if (isPublished) { + feedVersionSummary.namespace = feedVersionSummary.feedSourcePublishedVersionId = "namespace"; + } + if (isPublishing) { + feedVersionSummary.sentToExternalPublisher = new Date(); + feedVersionSummary.processedByExternalPublisher = null; + } + if (isPublishBlocked) { + feedVersionSummary.gtfsPlusValidation = null; + } + if (!isPublished && !isPublishing && !isPublishBlocked && !isFeedLoading) { + // Ignore blocking issues. + FeedVersionSummary.setHasBlockingIssueForPublishingOverrideForTesting(false); + passPublishBlockedCheck(feedVersionSummary); + + feedVersionSummary.validationResult.errorCount = 1; + feedVersionSummary.id = "feed-version-id"; + feedSourceSummary.id = "feed-source-id"; + } + PublishState publishState = feedVersionSummary.getPublishState(); + assertEquals(expectedPublishState, publishState); + } + + /** + * Set up a feed version summary to pass the publish blocked check. + */ + private static void passPublishBlockedCheck(FeedVersionSummary feedVersionSummary) { + feedVersionSummary.gtfsPlusValidation = new GtfsPlusValidation(); + feedVersionSummary.gtfsPlusValidation.issues = new ArrayList<>(); + feedVersionSummary.gtfsPlusValidation.published = true; + feedVersionSummary.validationResult = new ValidationResult(); + feedVersionSummary.validationResult.lastCalendarDate = LocalDate.now().plusDays(1); + FeedVersion.setDateOverrideForTesting(LocalDate.now()); + } + + private static Stream createPublishStates() { + return Stream.of( + Arguments.of(true, false, false, false, PublishState.PUBLISHED), + Arguments.of(false, true, false, false, PublishState.PUBLISHING), + Arguments.of(false, false, true, false, PublishState.PUBLISH_BLOCKED), + Arguments.of(false, false, false, false, PublishState.READY_TO_PUBLISH) + ); + } + + /** + * Additional cases for future and expired feeds. + */ + @ParameterizedTest + @MethodSource("publishStateTimeCases") + void canGetPublishState(int daysOffsetFromToday, PublishState expectedState, String caseName) { + FeedVersionSummary feedVersionSummary = new FeedVersionSummary(); + passPublishBlockedCheck(feedVersionSummary); + LocalDate date = LocalDate.now().plusDays(daysOffsetFromToday); + feedVersionSummary.validationResult.firstCalendarDate = date; + feedVersionSummary.validationResult.lastCalendarDate = date.plusDays(3); + + // Ignore blocking issues. + FeedVersionSummary.setHasBlockingIssueForPublishingOverrideForTesting(false); + assertEquals(expectedState, feedVersionSummary.getPublishState(), caseName); + } + + private static Stream publishStateTimeCases() { + return Stream.of( + Arguments.of(1, PublishState.PUBLISH_BLOCKED, "future feed"), + Arguments.of(0, PublishState.READY_TO_PUBLISH, "present feed"), + Arguments.of(-5, PublishState.PUBLISH_BLOCKED, "expired feed") + ); + } +} diff --git a/src/test/java/com/conveyal/datatools/manager/models/FeedVersionTest.java b/src/test/java/com/conveyal/datatools/manager/models/FeedVersionTest.java index e0550c8eb..dd628160d 100644 --- a/src/test/java/com/conveyal/datatools/manager/models/FeedVersionTest.java +++ b/src/test/java/com/conveyal/datatools/manager/models/FeedVersionTest.java @@ -13,11 +13,15 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; import java.sql.Connection; import java.sql.SQLException; +import java.time.LocalDate; import java.util.Date; +import java.util.stream.Stream; import static com.conveyal.datatools.TestUtils.createFeedVersionFromGtfsZip; import static com.conveyal.datatools.manager.DataManager.GTFS_DATA_SOURCE; @@ -26,14 +30,16 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; -public class FeedVersionTest extends UnitTest { +class FeedVersionTest extends UnitTest { private static Project project; private static FeedSource feedSource; /** Initialize application for tests to run. */ @BeforeAll - public static void setUp() throws Exception { + static void setUp() throws Exception { // start server if it isn't already running DatatoolsTest.setUp(); Auth0Connection.setAuthDisabled(true); @@ -49,13 +55,52 @@ public static void setUp() throws Exception { } @AfterAll - public static void tearDown() { + static void tearDown() { Auth0Connection.setAuthDisabled(Auth0Connection.getDefaultAuthDisabled()); if (project != null) { project.delete(); } } + /** + * Future feed detection. + */ + @ParameterizedTest + @MethodSource("futureFeedCases") + void canDetermineFutureFeed(int daysOffsetFromToday, boolean isFuture, String caseName) { + FeedVersion feedVersion1 = new FeedVersion(feedSource); + feedVersion1.validationResult = new ValidationResult(); + LocalDate date = LocalDate.now().plusDays(daysOffsetFromToday); + feedVersion1.validationResult.firstCalendarDate = date; + feedVersion1.validationResult.lastCalendarDate = date.plusDays(3); + + assertEquals( + isFuture, + feedVersion1.isFuture(), + String.format("Feed starting '%s' is %s in the future.", caseName, isFuture ? "indeed" : "not") + ); + } + + private static Stream futureFeedCases() { + return Stream.of( + Arguments.of(0, false, "today"), + Arguments.of(-1, false, "yesterday"), + Arguments.of(-2, false, "the day before yesterday"), + Arguments.of(1, true, "tomorrow"), + Arguments.of(2, true, "the day after tomorrow") + ); + } + + /** + * Future feed detection. + */ + @Test + void canDetermineFutureFeedNullFirstCalendarDate() { + FeedVersion feedVersion1 = new FeedVersion(feedSource); + feedVersion1.validationResult = new ValidationResult(); + assertFalse(feedVersion1.isFuture(), "null firstCalendarDate is not future."); + } + /** * Make sure FeedVersionIDs are always unique, even if created at the same second. * See https://github.com/ibi-group/datatools-server/issues/251