From 88976cbc5b92ec402679001838706293dc45d938 Mon Sep 17 00:00:00 2001 From: gontarsky_04 Date: Mon, 19 Jan 2026 19:32:36 +0100 Subject: [PATCH 1/3] e2e tests - first attempt, not all working --- .../java/pl/agh/transit/StopController.java | 15 +- src/main/java/pl/agh/transit/StopService.java | 96 ++++---- .../java/pl/agh/transit/mcp/StopMcpTools.java | 11 +- .../transit/e2e/StopControllerE2ETest.java | 109 +++++++++ .../transit/e2e/TripControllerE2ETest.java | 213 ++++++++++++++++++ .../resources/application-test.properties | 29 +++ 6 files changed, 413 insertions(+), 60 deletions(-) create mode 100644 src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java create mode 100644 src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java create mode 100644 src/test/resources/application-test.properties diff --git a/src/main/java/pl/agh/transit/StopController.java b/src/main/java/pl/agh/transit/StopController.java index 783a131..23e7c26 100644 --- a/src/main/java/pl/agh/transit/StopController.java +++ b/src/main/java/pl/agh/transit/StopController.java @@ -43,12 +43,13 @@ public ResponseEntity> getNextDepartures( @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.TIME) LocalTime time ) { - //TODO: consider handling it in the service layer - - LocalDate travelDate = date != null ? date : LocalDate.now(); - LocalTime travelTime = time != null ? time : LocalTime.now(); - List departures = stopService.getNextDeparturesForStopAndRoute( - stopName, routeName, travelDate, travelTime, 5); + List departures; + if (date != null && time != null) { + departures = stopService.getNextDeparturesForStopAndRoute(stopName, routeName, date, time, 5); + } + else{ + departures = stopService.getNextDeparturesForStopAndRoute(stopName, routeName,5); + } return ResponseEntity.ok(departures); } -} +} \ No newline at end of file diff --git a/src/main/java/pl/agh/transit/StopService.java b/src/main/java/pl/agh/transit/StopService.java index d5d0178..4404ce3 100644 --- a/src/main/java/pl/agh/transit/StopService.java +++ b/src/main/java/pl/agh/transit/StopService.java @@ -15,18 +15,15 @@ import pl.agh.transit.gtfs_static.model.Trip; import pl.agh.transit.gtfs_static.model.Route; import pl.agh.transit.gtfs_static.repository.StaticTripRepository; -import pl.agh.transit.gtfs_static.repository.StopRepository; import pl.agh.transit.gtfs_static.repository.RouteRepository; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.HashMap; +import java.time.LocalTime; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -37,7 +34,6 @@ @AllArgsConstructor public class StopService { - private final StopRepository stopRepository; private final JdbcTemplate jdbcTemplate; private final ConnectionServiceHelper connectionServiceHelper; private final StaticTripRepository staticTripRepository; @@ -69,7 +65,7 @@ public PagedResponseDTO getAllStops(int page, int size, String sortBy) List stopDTOs = stops.stream() .map(this::convertToDTO) - .collect(Collectors.toList()); + .toList(); log.debug("Found {} stops on page {} of {}", stopDTOs.size(), page, totalPages); @@ -84,6 +80,49 @@ public PagedResponseDTO getAllStops(int page, int size, String sortBy) .build(); } + public List getNextDeparturesForStopAndRoute(String stopName, String routeName, int limit) { + LocalDate travelDate = LocalDate.now(); + LocalTime travelTime = LocalTime.now(); + + return getNextDeparturesForStopAndRoute(stopName, routeName, travelDate, travelTime, limit); + } + + /** + * Get next departures for a stop and route. + * Merges realtime and static data, filters by service calendar. + * Accepts names instead of IDs. + * Supplements results from next day if less than limit. + */ + public List getNextDeparturesForStopAndRoute( + String stopName, + String routeName, + LocalDate travelDate, + LocalTime travelTime, + int limit + ) { + log.debug("[0] Getting next {} departures for stop: {}, route: {}, date: {}, time: {}", + limit, stopName, routeName, travelDate, travelTime); + + List results = getNextDeparturesForDate(stopName, routeName, travelDate, travelTime, limit); + + // If insufficient results, fetch from next day + if (results.size() < limit) { + int remainingCount = limit - results.size(); + log.debug("[0c] Only {} results for initial date, fetching {} more from next day", results.size(), remainingCount); + + LocalDate nextDate = travelDate.plusDays(1); + List nextDayResults = getNextDeparturesForDate(stopName, routeName, nextDate, travelTime, remainingCount); + results = Stream.concat(results.stream(), nextDayResults.stream()) + .limit(limit) + .toList(); + + log.debug("[0d] Added {} results from next day, total: {}", nextDayResults.size(), results.size()); + } + + log.debug("[0e] Final results (including next day if needed): {}", results.size()); + return results; + } + /** * Sanitize sort column to prevent SQL injection */ @@ -125,43 +164,6 @@ private StopDTO convertToDTO(Stop stop) { .build(); } - /** - * Get next departures for a stop and route. - * Merges realtime and static data, filters by service calendar. - * Accepts names instead of IDs. - * Supplements results from next day if less than limit. - */ - public List getNextDeparturesForStopAndRoute( - String stopName, - String routeName, - LocalDate travelDate, - java.time.LocalTime travelTime, - int limit - ) { - log.debug("[0] Getting next {} departures for stop: {}, route: {}, date: {}, time: {}", - limit, stopName, routeName, travelDate, travelTime); - - List results = getNextDeparturesForDate(stopName, routeName, travelDate, travelTime, limit); - - // If insufficient results, fetch from next day - if (results.size() < limit) { - int remainingCount = limit - results.size(); - log.debug("[0c] Only {} results for initial date, fetching {} more from next day", results.size(), remainingCount); - - LocalDate nextDate = travelDate.plusDays(1); - List nextDayResults = getNextDeparturesForDate(stopName, routeName, nextDate, travelTime, remainingCount); - results = Stream.concat(results.stream(), nextDayResults.stream()) - .limit(limit) - .toList(); - - log.debug("[0d] Added {} results from next day, total: {}", nextDayResults.size(), results.size()); - } - - log.debug("[0e] Final results (including next day if needed): {}", results.size()); - return results; - } - - private List getNextDeparturesForDate( String stopName, String routeName, @@ -177,7 +179,7 @@ private List getNextDeparturesForDate( log.debug("[0a] Stop not found: {}", stopName); return List.of(); } - Stop stop = stops.get(0); + Stop stop = stops.getFirst(); String stopId = stop.getId(); Optional routeOptional = routeRepository.findByRouteShortName(routeName); @@ -283,16 +285,14 @@ private Stream findStopInRealtimeTrip( return stopTimeUpdates.stream() .filter(stopUpdate -> stopId.equals(stopUpdate.getStopId())) - .filter(stopUpdate -> isStopUpdateValid(stopUpdate, travelDateTime, travelDate, trip.getTripId(), stopId)) + .filter(stopUpdate -> isStopUpdateValid(stopUpdate, travelDateTime, travelDate)) .map(stopUpdate -> buildNextDepartureDTOFromUpdate(stopUpdate, stopName, routeName, trip.getTripId(), stopId)); } private boolean isStopUpdateValid( StopTimeUpdateDTO stopUpdate, LocalDateTime travelDateTime, - LocalDate travelDate, - String tripId, - String stopId + LocalDate travelDate ) { LocalDateTime departureTime = connectionServiceHelper.parseTimeWithDelay( stopUpdate.getDepartureTime(), diff --git a/src/main/java/pl/agh/transit/mcp/StopMcpTools.java b/src/main/java/pl/agh/transit/mcp/StopMcpTools.java index a59aace..b1947db 100644 --- a/src/main/java/pl/agh/transit/mcp/StopMcpTools.java +++ b/src/main/java/pl/agh/transit/mcp/StopMcpTools.java @@ -44,10 +44,11 @@ public List getNextDepartures( @ToolParam(description = "Date to check schedule for (YYYY-MM-DD). If omitted, defaults to today.", required = false) LocalDate date, @ToolParam(description = "Time to check schedule for (HH:mm). If omitted, defaults to right now.", required = false) LocalTime time ) { - //TODO: consider handling it in the service layer - LocalDate travelDate = (date != null) ? date : LocalDate.now(); - LocalTime travelTime = time != null ? time : LocalTime.now(); - - return stopService.getNextDeparturesForStopAndRoute(stopName, routeName, travelDate, travelTime, 5); + if (date != null && time != null) { + return stopService.getNextDeparturesForStopAndRoute(stopName, routeName, date, time, 5); + } + else{ + return stopService.getNextDeparturesForStopAndRoute(stopName, routeName,5); + } } } \ No newline at end of file diff --git a/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java b/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java new file mode 100644 index 0000000..8be6985 --- /dev/null +++ b/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java @@ -0,0 +1,109 @@ +package pl.agh.transit.e2e; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import pl.agh.transit.dto.PagedResponseDTO; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +@DisplayName("E2E Tests - Stop Controller") +class StopControllerE2ETest { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + private String baseUrl() { + return "http://localhost:" + port; + } + + @Nested + @DisplayName("GET /stops") + class GetStopsEndpoint { + + @Test + @DisplayName("powinien zwrócić listę przystanków z domyślną paginacją") + void shouldReturnStopsWithDefaultPagination() { + + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/stops", + PagedResponseDTO.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getPageNumber()).isEqualTo(0); + assertThat(response.getBody().getPageSize()).isEqualTo(10); + } + + @Test + @DisplayName("powinien obsługiwać parametry paginacji") + void shouldHandlePaginationParameters() { + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/stops?page=1&size=5", + PagedResponseDTO.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getPageNumber()).isEqualTo(1); + assertThat(response.getBody().getPageSize()).isEqualTo(5); + } + + @Test + @DisplayName("powinien ograniczyć maksymalny rozmiar strony do 100") + void shouldLimitMaxPageSize() { + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/stops?size=500", + PagedResponseDTO.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getPageSize()).isLessThanOrEqualTo(100); + } + } + + @Nested + @DisplayName("GET /stops/routes") + class GetNextDeparturesEndpoint { + + @Test + @DisplayName("powinien zwrócić następne odjazdy dla przystanku i linii") + void shouldReturnNextDepartures() { + + String stopName = "Rondo Grunwaldzkie"; + String routeName = "52"; + + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/stops/routes?stopName=" + stopName + "&routeName=" + routeName, + String.class + ); + + assertThat(response.getStatusCode()).isIn(HttpStatus.OK, HttpStatus.NOT_FOUND); + } + + @Test + @DisplayName("powinien obsługiwać brakujące wymagane parametry") + void shouldHandleMissingRequiredParameters() { + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/stops/routes", + String.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + } + } +} \ No newline at end of file diff --git a/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java b/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java new file mode 100644 index 0000000..312f93f --- /dev/null +++ b/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java @@ -0,0 +1,213 @@ +package pl.agh.transit.e2e; + +import com.google.transit.realtime.GtfsRealtime; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; +import pl.agh.transit.TripRepository; +import pl.agh.transit.dto.StopTimeUpdateDTO; +import pl.agh.transit.dto.TransportTypeDTO; +import pl.agh.transit.dto.TripUpdateDTO; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@DisplayName("E2E Tests - Trip Controller") +class TripControllerE2ETest { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + @Autowired + private TripRepository tripRepository; + + private String baseUrl() { + return "http://localhost:" + port; + } + + private void setupTestData() { + GtfsRealtime.FeedMessage feed = GtfsRealtime.FeedMessage.newBuilder() + .setHeader(GtfsRealtime.FeedHeader.newBuilder() + .setGtfsRealtimeVersion("2.0") + .setTimestamp(System.currentTimeMillis() / 1000) + .build()) + .addEntity(GtfsRealtime.FeedEntity.newBuilder() + .setId("entity1") + .setTripUpdate(GtfsRealtime.TripUpdate.newBuilder() + .setTrip(GtfsRealtime.TripDescriptor.newBuilder() + .setTripId("trip_001") + .setRouteId("route_52") + .build()) + .addStopTimeUpdate(GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder() + .setStopSequence(1) + .setStopId("stop_rondo_grunwaldzkie") + .build()) + .addStopTimeUpdate(GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder() + .setStopSequence(2) + .setStopId("stop_rondo_mogilskie") + .build()) + .build()) + .build()) + .build(); + + tripRepository.updateAllTrips(feed); + } + + @Nested + @DisplayName("GET /trips") + class GetTripsEndpoint { + + @Test + @DisplayName("powinien zwrócić listę wszystkich aktualizacji kursów") + void shouldReturnAllTrips() { + setupTestData(); + + ResponseEntity> response = restTemplate.exchange( + baseUrl() + "/trips", + HttpMethod.GET, + null, + new ParameterizedTypeReference<>() {} + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody()).isNotEmpty(); + assertThat(response.getBody().get(0).getTripId()).isEqualTo("trip_001"); + } + + @Test + @DisplayName("powinien zwrócić pustą listę gdy brak danych") + void shouldReturnEmptyListWhenNoData() { + + ResponseEntity> response = restTemplate.exchange( + baseUrl() + "/trips", + HttpMethod.GET, + null, + new ParameterizedTypeReference<>() {} + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody()).isEmpty(); + } + } + + @Nested + @DisplayName("GET /random-stop-time") + class GetRandomStopTimeEndpoint { + + @Test + @DisplayName("powinien zwrócić losowy czas przystanku gdy dane istnieją") + void shouldReturnRandomStopTimeWhenDataExists() { + setupTestData(); + + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/random-stop-time", + StopTimeUpdateDTO.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getStopId()).isNotBlank(); + } + + @Test + @DisplayName("powinien zwrócić błąd 500 gdy brak danych") + void shouldReturnErrorWhenNoData() { + + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/random-stop-time", + String.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Nested + @DisplayName("GET /fastest-direct-connection") + class GetFastestDirectConnectionEndpoint { + + @Test + @DisplayName("powinien obsługiwać zapytanie o połączenie bezpośrednie") + void shouldHandleDirectConnectionQuery() { + String from = "Rondo Grunwaldzkie"; + String to = "Rondo Mogilskie"; + + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/fastest-direct-connection?from=" + from + "&to=" + to, + TransportTypeDTO.class + ); + + assertThat(response.getStatusCode()).isIn( + HttpStatus.OK, + HttpStatus.NOT_FOUND, + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + + @Test + @DisplayName("powinien zwrócić błąd przy brakujących parametrach") + void shouldReturnErrorForMissingParams() { + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/fastest-direct-connection?from=Rondo", + String.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + } + } + + @Nested + @DisplayName("GET /fastest-direct-connections") + class GetFastestDirectConnectionsEndpoint { + + @Test + @DisplayName("powinien obsługiwać zapytanie o wiele połączeń") + void shouldHandleMultipleConnectionsQuery() { + String from = "Rondo Grunwaldzkie"; + String to = "Rondo Mogilskie"; + + ResponseEntity> response = restTemplate.exchange( + baseUrl() + "/fastest-direct-connections?from=" + from + "&to=" + to + "&count=3", + HttpMethod.GET, + null, + new ParameterizedTypeReference<>() {} + ); + + assertThat(response.getStatusCode()).isIn(HttpStatus.OK, HttpStatus.NOT_FOUND); + } + + @Test + @DisplayName("powinien obsługiwać opcjonalne parametry daty i czasu") + void shouldHandleOptionalDateTimeParams() { + String from = "Rondo Grunwaldzkie"; + String to = "Rondo Mogilskie"; + String date = "2026-01-19"; + String time = "08:00"; + + ResponseEntity response = restTemplate.getForEntity( + baseUrl() + "/fastest-direct-connections?from=" + from + + "&to=" + to + "&travelDate=" + date + "&travelTime=" + time, + String.class + ); + + assertThat(response.getStatusCode()).isIn( + HttpStatus.OK, + HttpStatus.NOT_FOUND, + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + } +} diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties new file mode 100644 index 0000000..33da538 --- /dev/null +++ b/src/test/resources/application-test.properties @@ -0,0 +1,29 @@ +spring.application.name=Transit Location API - Test + +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +spring.h2.console.enabled=false + +spring.sql.init.mode=always +spring.sql.init.platform=h2 + +gtfs.tripUpdatesUrl=https://gtfs.ztp.krakow.pl/TripUpdates.pb +gtfs.staticDataUrl=https://gtfs.ztp.krakow.pl/GTFS_KRK.zip +gtfs.dataDir=/data +gtfs.localFile=data/trip-updates.pb + +gtfs.file.agency=agency.txt +gtfs.file.stops=stops.txt +gtfs.file.calendar=calendar.txt +gtfs.file.routes=routes.txt +gtfs.file.shapes=shapes.txt +gtfs.file.calendarDates=calendar_dates.txt +gtfs.file.trips=trips.txt +gtfs.file.stopTimes=stop_times.txt +gtfs.file.feedInfo=feed_info.txt + +logging.level.root=WARN +logging.level.pl.agh.transit=INFO \ No newline at end of file From 03bed3542342f462d13e15626256b767cea12f09 Mon Sep 17 00:00:00 2001 From: gontarsky_04 Date: Tue, 20 Jan 2026 00:30:48 +0100 Subject: [PATCH 2/3] e2e tests - second attepmt, working tests, need refactor --- .../pl/agh/transit/TripUpdateScheduler.java | 2 + ...irectConnectionServiceIntegrationTest.java | 27 ++++++----- .../transit/DirectConnectionServiceTest.java | 5 ++- .../TripControllerIntegrationTest.java | 6 ++- .../transit/e2e/StopControllerE2ETest.java | 2 + .../transit/e2e/TripControllerE2ETest.java | 45 ++++++++++++------- .../resources/application-test.properties | 3 ++ 7 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/main/java/pl/agh/transit/TripUpdateScheduler.java b/src/main/java/pl/agh/transit/TripUpdateScheduler.java index a49ebf1..931894e 100644 --- a/src/main/java/pl/agh/transit/TripUpdateScheduler.java +++ b/src/main/java/pl/agh/transit/TripUpdateScheduler.java @@ -3,6 +3,7 @@ import jakarta.annotation.PostConstruct; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import pl.agh.transit.gtfs_static.GtfsStaticService; @@ -11,6 +12,7 @@ @Component @AllArgsConstructor @Slf4j +@ConditionalOnProperty(name = "gtfs.scheduler.enabled", havingValue = "true", matchIfMissing = true) public class TripUpdateScheduler { private final TripDataFetcher fetcher; diff --git a/src/test/java/pl/agh/transit/DirectConnectionServiceIntegrationTest.java b/src/test/java/pl/agh/transit/DirectConnectionServiceIntegrationTest.java index 40c281b..d290c35 100644 --- a/src/test/java/pl/agh/transit/DirectConnectionServiceIntegrationTest.java +++ b/src/test/java/pl/agh/transit/DirectConnectionServiceIntegrationTest.java @@ -18,6 +18,8 @@ import java.time.LocalTime; import java.util.List; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import static org.assertj.core.api.Assertions.assertThat; import pl.agh.transit.gtfs_static.repository.RouteRepository; import pl.agh.transit.gtfs_static.repository.StaticTripRepository; @@ -26,6 +28,8 @@ @SpringBootTest @Transactional +@ActiveProfiles("test") +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) @DisplayName("DirectConnectionService Integration Tests") class DirectConnectionServiceIntegrationTest { @@ -47,6 +51,7 @@ class DirectConnectionServiceIntegrationTest { @Autowired private CalendarRepository calendarRepository; + private static final LocalTime TEST_TIME = LocalTime.of(22, 0); @BeforeEach void setUp() { @@ -152,7 +157,7 @@ private void setupTestData() { @DisplayName("Should find fastest direct connection from static data") void findFastestDirectConnection_staticData_returnsFastestRoute() { List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), TEST_TIME, 1); assertThat(result).hasSize(1); assertThat(result.get(0).getRouteName()).isEqualTo("1A"); @@ -162,7 +167,7 @@ void findFastestDirectConnection_staticData_returnsFastestRoute() { @DisplayName("Should return empty when no direct connection exists") void findFastestDirectConnection_noDirectConnections_returnsEmpty() { List result = directConnectionService - .findFastestDirectConnections("Main Station", "Final Stop", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "Final Stop", LocalDate.now(), TEST_TIME, 1); assertThat(result).isEmpty(); } @@ -171,7 +176,7 @@ void findFastestDirectConnection_noDirectConnections_returnsEmpty() { @DisplayName("Should return empty when source stop does not exist") void findFastestDirectConnections_sourceStopNotFound_returnsEmpty() { List result = directConnectionService - .findFastestDirectConnections("Unknown Station", "City Center", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Unknown Station", "City Center", LocalDate.now(), TEST_TIME, 1); assertThat(result).isEmpty(); } @@ -180,7 +185,7 @@ void findFastestDirectConnections_sourceStopNotFound_returnsEmpty() { @DisplayName("Should return empty when destination stop does not exist") void findFastestDirectConnections_destinationStopNotFound_returnsEmpty() { List result = directConnectionService - .findFastestDirectConnections("Main Station", "Unknown Station", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "Unknown Station", LocalDate.now(), TEST_TIME, 1); assertThat(result).isEmpty(); } @@ -189,7 +194,7 @@ void findFastestDirectConnections_destinationStopNotFound_returnsEmpty() { @DisplayName("Should return empty when both stops are the same") void findFastestDirectConnections_sameSourceAndDestination_returnsEmpty() { List result = directConnectionService - .findFastestDirectConnections("Main Station", "Main Station", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "Main Station", LocalDate.now(), TEST_TIME, 1); assertThat(result).isEmpty(); } @@ -200,7 +205,7 @@ void findFastestDirectConnections_travelDateOutsideCalendar_returnsEmpty() { LocalDate futureDate = LocalDate.now().plusYears(1); List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", futureDate, LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", futureDate, TEST_TIME, 1); assertThat(result).isEmpty(); } @@ -211,7 +216,7 @@ void findFastestDirectConnection_validTravelDate_returnsConnections() { LocalDate validDate = LocalDate.now(); List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", validDate, LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", validDate, TEST_TIME, 1); assertThat(result).hasSize(1); assertThat(result.get(0).getRouteName()).isEqualTo("1A"); @@ -225,7 +230,7 @@ void findFastestDirectConnections_comparesDepartureTimes_returnsEarliestDepartur // Should select trip 1 because it departs earliest List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), TEST_TIME, 1); assertThat(result).hasSize(1); assertThat(result.get(0).getRouteName()).isEqualTo("1A"); @@ -278,7 +283,7 @@ void findFastestDirectConnections_inactiveServicesIgnored_returnsActiveRoute() { stopTimeRepository.save(stopTime3To); List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), TEST_TIME, 1); // Should select route 1A (active, earliest departure), not 3C (inactive) assertThat(result).hasSize(1); @@ -297,7 +302,7 @@ void findFastestDirectConnections_multipleStopsSameName_handlesCorrectly() { stopRepository.save(duplicateStop); List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), TEST_TIME, 1); // Should find connection even with multiple stops with same name assertThat(result).hasSize(1); @@ -308,7 +313,7 @@ void findFastestDirectConnections_multipleStopsSameName_handlesCorrectly() { @DisplayName("Should return valid arrival time for connection") void findFastestDirectConnections_returnsNonNullArrivalTime() { List result = directConnectionService - .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), LocalTime.now(), 1); + .findFastestDirectConnections("Main Station", "City Center", LocalDate.now(), TEST_TIME, 1); assertThat(result).hasSize(1); assertThat(result.get(0).getArrivalTime()).isNotNull(); diff --git a/src/test/java/pl/agh/transit/DirectConnectionServiceTest.java b/src/test/java/pl/agh/transit/DirectConnectionServiceTest.java index 436dc7d..b0c189d 100644 --- a/src/test/java/pl/agh/transit/DirectConnectionServiceTest.java +++ b/src/test/java/pl/agh/transit/DirectConnectionServiceTest.java @@ -20,8 +20,11 @@ import java.time.LocalTime; import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; + import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/src/test/java/pl/agh/transit/TripControllerIntegrationTest.java b/src/test/java/pl/agh/transit/TripControllerIntegrationTest.java index 4155b1e..c8d3fa8 100644 --- a/src/test/java/pl/agh/transit/TripControllerIntegrationTest.java +++ b/src/test/java/pl/agh/transit/TripControllerIntegrationTest.java @@ -6,13 +6,17 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc +@ActiveProfiles("test") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class TripControllerIntegrationTest { diff --git a/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java b/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java index 8be6985..37c251d 100644 --- a/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java +++ b/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java @@ -9,12 +9,14 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; import pl.agh.transit.dto.PagedResponseDTO; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @ActiveProfiles("test") @DisplayName("E2E Tests - Stop Controller") class StopControllerE2ETest { diff --git a/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java b/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java index 312f93f..3499f0a 100644 --- a/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java +++ b/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java @@ -1,7 +1,10 @@ package pl.agh.transit.e2e; import com.google.transit.realtime.GtfsRealtime; -import org.junit.jupiter.api.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; @@ -11,6 +14,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import pl.agh.transit.TripRepository; import pl.agh.transit.dto.StopTimeUpdateDTO; import pl.agh.transit.dto.TransportTypeDTO; @@ -19,7 +23,8 @@ import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +@ActiveProfiles("test") @DisplayName("E2E Tests - Trip Controller") class TripControllerE2ETest { @@ -87,19 +92,22 @@ void shouldReturnAllTrips() { } @Test - @DisplayName("powinien zwrócić pustą listę gdy brak danych") - void shouldReturnEmptyListWhenNoData() { + @DisplayName("powinien zwrócić błąd 500 gdy brak danych") + void shouldReturnErrorWhenNoData() { + GtfsRealtime.FeedMessage emptyFeed = GtfsRealtime.FeedMessage.newBuilder() + .setHeader(GtfsRealtime.FeedHeader.newBuilder() + .setGtfsRealtimeVersion("2.0") + .setTimestamp(System.currentTimeMillis() / 1000) + .build()) + .build(); + tripRepository.updateAllTrips(emptyFeed); - ResponseEntity> response = restTemplate.exchange( + ResponseEntity response = restTemplate.getForEntity( baseUrl() + "/trips", - HttpMethod.GET, - null, - new ParameterizedTypeReference<>() {} + String.class ); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isNotNull(); - assertThat(response.getBody()).isEmpty(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); } } @@ -125,6 +133,13 @@ void shouldReturnRandomStopTimeWhenDataExists() { @Test @DisplayName("powinien zwrócić błąd 500 gdy brak danych") void shouldReturnErrorWhenNoData() { + GtfsRealtime.FeedMessage emptyFeed = GtfsRealtime.FeedMessage.newBuilder() + .setHeader(GtfsRealtime.FeedHeader.newBuilder() + .setGtfsRealtimeVersion("2.0") + .setTimestamp(System.currentTimeMillis() / 1000) + .build()) + .build(); + tripRepository.updateAllTrips(emptyFeed); ResponseEntity response = restTemplate.getForEntity( baseUrl() + "/random-stop-time", @@ -151,8 +166,8 @@ void shouldHandleDirectConnectionQuery() { ); assertThat(response.getStatusCode()).isIn( - HttpStatus.OK, - HttpStatus.NOT_FOUND, + HttpStatus.OK, + HttpStatus.NOT_FOUND, HttpStatus.INTERNAL_SERVER_ERROR ); } @@ -198,13 +213,13 @@ void shouldHandleOptionalDateTimeParams() { String time = "08:00"; ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/fastest-direct-connections?from=" + from + + baseUrl() + "/fastest-direct-connections?from=" + from + "&to=" + to + "&travelDate=" + date + "&travelTime=" + time, String.class ); assertThat(response.getStatusCode()).isIn( - HttpStatus.OK, + HttpStatus.OK, HttpStatus.NOT_FOUND, HttpStatus.INTERNAL_SERVER_ERROR ); diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties index 33da538..17dd28c 100644 --- a/src/test/resources/application-test.properties +++ b/src/test/resources/application-test.properties @@ -10,6 +10,9 @@ spring.h2.console.enabled=false spring.sql.init.mode=always spring.sql.init.platform=h2 +# Disable GTFS scheduler during tests +gtfs.scheduler.enabled=false + gtfs.tripUpdatesUrl=https://gtfs.ztp.krakow.pl/TripUpdates.pb gtfs.staticDataUrl=https://gtfs.ztp.krakow.pl/GTFS_KRK.zip gtfs.dataDir=/data From 767d8bf6d2d54c0217970a760c606de44900be15 Mon Sep 17 00:00:00 2001 From: gontarsky_04 Date: Fri, 23 Jan 2026 00:45:58 +0100 Subject: [PATCH 3/3] E2E tests refactored, actual coverage 81% lines --- .../pl/agh/transit/e2e/AbstractE2ETest.java | 28 +++++++ .../transit/e2e/StopControllerE2ETest.java | 48 +++++------ .../transit/e2e/TripControllerE2ETest.java | 79 +++++++------------ 3 files changed, 77 insertions(+), 78 deletions(-) create mode 100644 src/test/java/pl/agh/transit/e2e/AbstractE2ETest.java diff --git a/src/test/java/pl/agh/transit/e2e/AbstractE2ETest.java b/src/test/java/pl/agh/transit/e2e/AbstractE2ETest.java new file mode 100644 index 0000000..48b49cd --- /dev/null +++ b/src/test/java/pl/agh/transit/e2e/AbstractE2ETest.java @@ -0,0 +1,28 @@ +package pl.agh.transit.e2e; + +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +public abstract class AbstractE2ETest { + @LocalServerPort + protected int port; + + @Autowired + protected TestRestTemplate restTemplate; + + @BeforeEach + void setUpBaseUrl() { + restTemplate.getRestTemplate().setUriTemplateHandler( + new DefaultUriBuilderFactory("http://localhost:" + port) + ); + } +} diff --git a/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java b/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java index 37c251d..d5761ab 100644 --- a/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java +++ b/src/test/java/pl/agh/transit/e2e/StopControllerE2ETest.java @@ -3,33 +3,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; import pl.agh.transit.dto.PagedResponseDTO; import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) -@ActiveProfiles("test") @DisplayName("E2E Tests - Stop Controller") -class StopControllerE2ETest { - - @LocalServerPort - private int port; - - @Autowired - private TestRestTemplate restTemplate; - - private String baseUrl() { - return "http://localhost:" + port; - } +class StopControllerE2ETest extends AbstractE2ETest{ @Nested @DisplayName("GET /stops") @@ -40,12 +21,12 @@ class GetStopsEndpoint { void shouldReturnStopsWithDefaultPagination() { ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/stops", + "/stops", PagedResponseDTO.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()).isNotNull(); assertThat(response.getBody().getPageNumber()).isEqualTo(0); assertThat(response.getBody().getPageSize()).isEqualTo(10); } @@ -54,12 +35,12 @@ void shouldReturnStopsWithDefaultPagination() { @DisplayName("powinien obsługiwać parametry paginacji") void shouldHandlePaginationParameters() { ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/stops?page=1&size=5", + "/stops?page=1&size=5", PagedResponseDTO.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()).isNotNull(); assertThat(response.getBody().getPageNumber()).isEqualTo(1); assertThat(response.getBody().getPageSize()).isEqualTo(5); } @@ -68,14 +49,25 @@ void shouldHandlePaginationParameters() { @DisplayName("powinien ograniczyć maksymalny rozmiar strony do 100") void shouldLimitMaxPageSize() { ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/stops?size=500", + "/stops?size=500", PagedResponseDTO.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()).isNotNull(); assertThat(response.getBody().getPageSize()).isLessThanOrEqualTo(100); } + + @Test + @DisplayName("powinien zwrócić błąd 500 dla ujemnego rozmiaru strony") + void shouldReturnBadRequestForNegativePageSize() { + ResponseEntity respose = restTemplate.getForEntity( + "/stops?size=-1", + String.class + ); + + assertThat(respose.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + } } @Nested @@ -90,7 +82,7 @@ void shouldReturnNextDepartures() { String routeName = "52"; ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/stops/routes?stopName=" + stopName + "&routeName=" + routeName, + "/stops/routes?stopName=" + stopName + "&routeName=" + routeName, String.class ); @@ -101,7 +93,7 @@ void shouldReturnNextDepartures() { @DisplayName("powinien obsługiwać brakujące wymagane parametry") void shouldHandleMissingRequiredParameters() { ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/stops/routes", + "/stops/routes", String.class ); diff --git a/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java b/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java index 3499f0a..25e2cbd 100644 --- a/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java +++ b/src/test/java/pl/agh/transit/e2e/TripControllerE2ETest.java @@ -6,15 +6,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; import pl.agh.transit.TripRepository; import pl.agh.transit.dto.StopTimeUpdateDTO; import pl.agh.transit.dto.TransportTypeDTO; @@ -22,26 +17,13 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) -@ActiveProfiles("test") @DisplayName("E2E Tests - Trip Controller") -class TripControllerE2ETest { - - @LocalServerPort - private int port; - - @Autowired - private TestRestTemplate restTemplate; +class TripControllerE2ETest extends AbstractE2ETest { @Autowired private TripRepository tripRepository; - private String baseUrl() { - return "http://localhost:" + port; - } - - private void setupTestData() { + private void givenSingleTripWithTwoStops() { GtfsRealtime.FeedMessage feed = GtfsRealtime.FeedMessage.newBuilder() .setHeader(GtfsRealtime.FeedHeader.newBuilder() .setGtfsRealtimeVersion("2.0") @@ -54,10 +36,6 @@ private void setupTestData() { .setTripId("trip_001") .setRouteId("route_52") .build()) - .addStopTimeUpdate(GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder() - .setStopSequence(1) - .setStopId("stop_rondo_grunwaldzkie") - .build()) .addStopTimeUpdate(GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder() .setStopSequence(2) .setStopId("stop_rondo_mogilskie") @@ -69,6 +47,13 @@ private void setupTestData() { tripRepository.updateAllTrips(feed); } + private GtfsRealtime.TripUpdate.StopTimeUpdate stop(int seq, String id) { + return GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder() + .setStopSequence(seq) + .setStopId(id) + .build(); + } + @Nested @DisplayName("GET /trips") class GetTripsEndpoint { @@ -76,19 +61,22 @@ class GetTripsEndpoint { @Test @DisplayName("powinien zwrócić listę wszystkich aktualizacji kursów") void shouldReturnAllTrips() { - setupTestData(); + givenSingleTripWithTwoStops(); ResponseEntity> response = restTemplate.exchange( - baseUrl() + "/trips", + "/trips", HttpMethod.GET, null, new ParameterizedTypeReference<>() {} ); + TripUpdateDTO trip = response.getBody().get(0); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).isNotNull(); - assertThat(response.getBody()).isNotEmpty(); - assertThat(response.getBody().get(0).getTripId()).isEqualTo("trip_001"); + assertThat(response.getBody()).hasSize(1); + + assertThat(trip.getTripId()).isEqualTo("trip_001"); + assertThat(trip.getStopTimeUpdates()).hasSize(1); } @Test @@ -103,7 +91,7 @@ void shouldReturnErrorWhenNoData() { tripRepository.updateAllTrips(emptyFeed); ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/trips", + "/trips", String.class ); @@ -118,10 +106,10 @@ class GetRandomStopTimeEndpoint { @Test @DisplayName("powinien zwrócić losowy czas przystanku gdy dane istnieją") void shouldReturnRandomStopTimeWhenDataExists() { - setupTestData(); + givenSingleTripWithTwoStops(); ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/random-stop-time", + "/random-stop-time", StopTimeUpdateDTO.class ); @@ -132,17 +120,9 @@ void shouldReturnRandomStopTimeWhenDataExists() { @Test @DisplayName("powinien zwrócić błąd 500 gdy brak danych") - void shouldReturnErrorWhenNoData() { - GtfsRealtime.FeedMessage emptyFeed = GtfsRealtime.FeedMessage.newBuilder() - .setHeader(GtfsRealtime.FeedHeader.newBuilder() - .setGtfsRealtimeVersion("2.0") - .setTimestamp(System.currentTimeMillis() / 1000) - .build()) - .build(); - tripRepository.updateAllTrips(emptyFeed); - + void shouldReturnNoContentWhenNoTrips() { ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/random-stop-time", + "/random-stop-time", String.class ); @@ -155,13 +135,12 @@ void shouldReturnErrorWhenNoData() { class GetFastestDirectConnectionEndpoint { @Test - @DisplayName("powinien obsługiwać zapytanie o połączenie bezpośrednie") - void shouldHandleDirectConnectionQuery() { + @DisplayName("powinien zwrócić odpowiedź lub brak połączenia dla poprawnych parametrów") + void shouldHandleCorrectQuery() { String from = "Rondo Grunwaldzkie"; String to = "Rondo Mogilskie"; - ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/fastest-direct-connection?from=" + from + "&to=" + to, + "/fastest-direct-connection?from=" + from + "&to=" + to, TransportTypeDTO.class ); @@ -173,10 +152,10 @@ void shouldHandleDirectConnectionQuery() { } @Test - @DisplayName("powinien zwrócić błąd przy brakujących parametrach") - void shouldReturnErrorForMissingParams() { + @DisplayName("powinien zwrócić błąd 400 przy brakujących parametrach") + void shouldReturnBadRequestForMissingParams() { ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/fastest-direct-connection?from=Rondo", + "/fastest-direct-connection?from=Rondo", String.class ); @@ -195,7 +174,7 @@ void shouldHandleMultipleConnectionsQuery() { String to = "Rondo Mogilskie"; ResponseEntity> response = restTemplate.exchange( - baseUrl() + "/fastest-direct-connections?from=" + from + "&to=" + to + "&count=3", + "/fastest-direct-connections?from=" + from + "&to=" + to + "&count=3", HttpMethod.GET, null, new ParameterizedTypeReference<>() {} @@ -213,7 +192,7 @@ void shouldHandleOptionalDateTimeParams() { String time = "08:00"; ResponseEntity response = restTemplate.getForEntity( - baseUrl() + "/fastest-direct-connections?from=" + from + + "/fastest-direct-connections?from=" + from + "&to=" + to + "&travelDate=" + date + "&travelTime=" + time, String.class );