diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000..80f6347 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,12 @@ +name: CI/CD + +on: + - pull_request + - push + +jobs: + build: + uses: HSLdevcom/transitdata-shared-workflows/.github/workflows/ci-cd-java.yml@1.0.0 + secrets: + DOCKER_USERNAME: ${{ secrets.TRANSITDATA_DOCKERHUB_USER }} + DOCKER_PASSWORD: ${{ secrets.TRANSITDATA_DOCKERHUB_TOKEN }} diff --git a/.github/workflows/test-and-build.yml b/.github/workflows/test-and-build.yml deleted file mode 100644 index d08acc8..0000000 --- a/.github/workflows/test-and-build.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Test and create Docker image - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '11' - cache: 'maven' - - name: Run Spotless Apply - run: mvn spotless:apply - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Build with Maven - run: mvn --file pom.xml clean install - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload .jar file - uses: actions/upload-artifact@v4 - with: - name: transitdata-metro-ats-parser-jar-with-dependencies.jar - path: target/transitdata-metro-ats-parser-jar-with-dependencies.jar - build-develop-docker-image: - needs: test - runs-on: ubuntu-latest - # Run only on develop branch - if: github.ref == 'refs/heads/develop' - steps: - - uses: actions/checkout@v3 - - name: Download .jar file - uses: actions/download-artifact@v4 - with: - name: transitdata-metro-ats-parser-jar-with-dependencies.jar - path: target - - name: Build and publish develop Docker image - uses: elgohr/Publish-Docker-Github-Action@v5 - with: - name: hsldevcom/transitdata-metro-ats-parser - username: ${{ secrets.TRANSITDATA_DOCKERHUB_USER }} - password: ${{ secrets.TRANSITDATA_DOCKERHUB_TOKEN }} - tags: develop - build-release-docker-image: - needs: test - runs-on: ubuntu-latest - # Run only for tagged commits - if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') - steps: - - uses: actions/checkout@v3 - - name: Download .jar file - uses: actions/download-artifact@v4 - with: - name: transitdata-metro-ats-parser-jar-with-dependencies.jar - path: target - - name: Build and publish release Docker image - uses: elgohr/Publish-Docker-Github-Action@v5 - with: - name: hsldevcom/transitdata-metro-ats-parser - username: ${{ secrets.TRANSITDATA_DOCKERHUB_USER }} - password: ${{ secrets.TRANSITDATA_DOCKERHUB_TOKEN }} - tag_semver: true - build-aks-dev-docker-image: - needs: test - runs-on: ubuntu-latest - # Run only on aks-dev branch - if: github.ref == 'refs/heads/aks-dev' - steps: - - uses: actions/checkout@v2 - - name: Download .jar file - uses: actions/download-artifact@v4 - with: - name: transitdata-metro-ats-parser-jar-with-dependencies.jar - path: target - - name: Build and publish aks-dev Docker image - uses: elgohr/Publish-Docker-Github-Action@master - with: - name: hsldevcom/transitdata-metro-ats-parser - username: ${{ secrets.TRANSITDATA_DOCKERHUB_USER }} - password: ${{ secrets.TRANSITDATA_DOCKERHUB_TOKEN }} - tags: aks-dev \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index a4aa406..d55d935 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,7 @@ -FROM eclipse-temurin:11-alpine -#Install curl for health check -RUN apk add --no-cache curl +FROM hsldevcom/infodevops-docker-base-images:1.0.0-java-25 ADD target/transitdata-metro-ats-parser-jar-with-dependencies.jar /usr/app/transitdata-metro-ats-parser.jar COPY start-application.sh / RUN chmod +x /start-application.sh -CMD ["/start-application.sh"] \ No newline at end of file +CMD ["/start-application.sh"] diff --git a/pom.xml b/pom.xml index 782a860..032d2ab 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,8 @@ UTF-8 - 11 - 11 + 25 + 25 2.0.7 2.43.0 1.17.0 @@ -88,8 +88,8 @@ maven-compiler-plugin 3.11.0 - 11 - 11 + 25 + 25 diff --git a/src/main/java/fi/hsl/transitdata/metroats/MetroEstimatesFactory.java b/src/main/java/fi/hsl/transitdata/metroats/MetroEstimatesFactory.java index 594bf4f..4d9244f 100644 --- a/src/main/java/fi/hsl/transitdata/metroats/MetroEstimatesFactory.java +++ b/src/main/java/fi/hsl/transitdata/metroats/MetroEstimatesFactory.java @@ -368,9 +368,34 @@ private Optional> getMetroJourneyData(final String metroKey) } } + /** + * Checks if the metro prediction is considered fairly reliable. + * + * We have learned that the Metro Mipro ATS API sends unreliable predictions for a vehicle journey for a few + * minutes before the departure from the first station. Those faulty predictions tend to predict an early departure + * from the first station. That almost never happens as the drivers will wait until the vehicle journey is planned + * to start. + * + * This method filters out predictions where the first station's departureTimeMeasured is missing (or invalid). + * + * @param estimate the MetroEstimate to validate + * @return true if the predictions can be considered fairly reliable or no predictions were given, + * false if the predictions cannot be considered fairly reliable + */ + private static boolean arePredictionsFairlyReliable(MetroEstimate estimate) { + return estimate.routeRows == null || estimate.routeRows.isEmpty() + || estimate.routeRows.get(0).departureTimeMeasured != null; + } + public static Optional parsePayload(final byte[] payload) { try { MetroEstimate metroEstimate = mapper.readValue(payload, MetroEstimate.class); + if (!arePredictionsFairlyReliable(metroEstimate)) { + log.debug( + "Dropped untrustworthy Mipro ATS predictions that were given before departure from first station. Payload: {}", + new String(payload)); + return Optional.empty(); + } return Optional.of(metroEstimate); } catch (Exception e) { log.warn("Failed to parse payload {}.", new String(payload), e); diff --git a/src/test/java/fi.hsl.transitdata.metroats/MetroEstimatesFactoryTest.java b/src/test/java/fi.hsl.transitdata.metroats/MetroEstimatesFactoryTest.java index ecd05d8..d2f6df7 100644 --- a/src/test/java/fi.hsl.transitdata.metroats/MetroEstimatesFactoryTest.java +++ b/src/test/java/fi.hsl.transitdata.metroats/MetroEstimatesFactoryTest.java @@ -1,15 +1,14 @@ package fi.hsl.transitdata.metroats; +import static org.junit.Assert.*; + import fi.hsl.common.files.FileUtils; import fi.hsl.transitdata.metroats.models.MetroEstimate; import fi.hsl.transitdata.metroats.models.MetroStopEstimate; -import org.junit.Test; - import java.io.InputStream; import java.net.URL; import java.util.Optional; - -import static org.junit.Assert.*; +import org.junit.Test; public class MetroEstimatesFactoryTest { @@ -32,4 +31,40 @@ public void testDateTimeConversion() throws Exception { assertEquals("2019-07-09T05:06:13.941Z", metroStopEstimate.departureTimeForecast); assertEquals("2019-07-09T05:06:32.578Z", metroStopEstimate.departureTimeMeasured); } + + @Test + public void testParsePayloadWithNoMeasuredDepartureTimeForFirstStation() throws Exception { + // The API surprisingly uses "null" instead of null in JSON. + String json = """ + { + "routeName": "M1", + "beginTime": "2023-01-01T12:01:02.345Z", + "routeRows": [ + { + "station": "KIV", + "departureTimeMeasured": "null" + } + ] + }"""; + Optional result = MetroEstimatesFactory.parsePayload(json.getBytes()); + assertFalse("Should filter out messages without a measured departure time for first station", + result.isPresent()); + } + + @Test + public void testParsePayloadWithMeasuredDepartureTimeForFirstStation() throws Exception { + String json = """ + { + "routeName": "M1", + "beginTime": "2023-01-01T12:01:02.345Z", + "routeRows": [ + { + "station": "KIV", + "departureTimeMeasured": "2023-01-01T12:01:05.678Z" + } + ] + }"""; + Optional result = MetroEstimatesFactory.parsePayload(json.getBytes()); + assertTrue("Should accept messages with a measured departure time for first station", result.isPresent()); + } }