Skip to content

Commit

Permalink
Merge pull request #276 from ibi-group/companions-on-bus-notifications
Browse files Browse the repository at this point in the history
Companions on bus notifications
  • Loading branch information
binh-dam-ibigroup authored Dec 9, 2024
2 parents 65e1d30 + 93ab1f2 commit 13c2676
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -430,12 +431,19 @@ public boolean isOneTime() {
return !monday && !tuesday && !wednesday && !thursday && !friday && !saturday && !sunday;
}

/**
* @return true if the trip has a (confirmed) companion, false otherwise.
*/
public boolean hasConfirmedCompanion() {
return companion != null && companion.isConfirmed();
}

/**
* Gets users not previously involved (as primary traveler, companion, or observer) in a trip.
*/
public static TripUsers getAddedUsers(MonitoredTrip monitoredTrip, MonitoredTrip originalTrip) {
RelatedUser addedCompanion = null;
if (monitoredTrip.companion != null && monitoredTrip.companion.isConfirmed() && (
if (monitoredTrip.hasConfirmedCompanion() && (
originalTrip == null ||
originalTrip.companion == null ||
!originalTrip.companion.email.equals(monitoredTrip.companion.email)
Expand All @@ -459,6 +467,7 @@ public static TripUsers getAddedUsers(MonitoredTrip monitoredTrip, MonitoredTrip
List<RelatedUser> addedObservers = new ArrayList<>();
if (monitoredTrip.observers != null) {
List<RelatedUser> confirmedObservers = monitoredTrip.observers.stream()
.filter(Objects::nonNull)
.filter(RelatedUser::isConfirmed)
.collect(Collectors.toList());
if (originalTrip == null || originalTrip.observers == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ public class TripTrackingData {
public final TrackedJourney journey;
public final List<TrackingLocation> locations;

private TripTrackingData(MonitoredTrip trip, TrackedJourney journey, List<TrackingLocation> locations) {
public TripTrackingData(MonitoredTrip trip, TrackedJourney journey, List<TrackingLocation> locations) {
this.trip = trip;
this.journey = journey;
if (journey != null) {
this.journey.trip = trip;
}
this.locations = locations;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.opentripplanner.middleware.triptracker.interactions.busnotifiers;

import org.opentripplanner.middleware.models.TrackedJourney;
import org.opentripplanner.middleware.triptracker.TravelerPosition;

import java.time.Instant;
Expand Down Expand Up @@ -96,7 +97,8 @@ public UsRideGwinnettBusOpNotificationMessage(Instant currentTime, TravelerPosit
// 1 = Notify, 0 = Cancel.
this.msg_type = 1;
this.mobility_codes = getMobilityCode(travelerPosition.mobilityMode);
this.trusted_companion = false;
TrackedJourney journey = travelerPosition.trackedJourney;
this.trusted_companion = journey != null && journey.trip != null && journey.trip.hasConfirmedCompanion();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ void initializeFromItineraryAndQueryParamsShouldNotModifyModes() {
assertEquals(originalModes, trip.otp2QueryParams.modes);
}

@ParameterizedTest
@MethodSource("createHasCompanionCases")
void testHasCompanion(RelatedUser companion, boolean expected) {
MonitoredTrip ownTripWithCompanion = new MonitoredTrip();
ownTripWithCompanion.companion = companion;
ownTripWithCompanion.userId = "trip-user-id";

assertEquals(expected, ownTripWithCompanion.hasConfirmedCompanion());
}

private static Stream<Arguments> createHasCompanionCases() {
RelatedUser confirmedCompanion = new RelatedUser();
confirmedCompanion.email = "[email protected]";
confirmedCompanion.status = RelatedUser.RelatedUserStatus.CONFIRMED;

RelatedUser unconfirmedCompanion = new RelatedUser();
unconfirmedCompanion.email = "[email protected]";
unconfirmedCompanion.status = RelatedUser.RelatedUserStatus.INVALID;

return Stream.of(
Arguments.of(null, false),
Arguments.of(confirmedCompanion, true),
Arguments.of(unconfirmedCompanion, false)
);
}

@ParameterizedTest
@MethodSource("createGetAddedUsersCases")
void canGetAddedUsers(MonitoredTrip.TripUsers originalUsers, MonitoredTrip.TripUsers finalUsers, MonitoredTrip.TripUsers expected) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.opentripplanner.middleware.models.MobilityProfile;
import org.opentripplanner.middleware.models.MonitoredTrip;
import org.opentripplanner.middleware.models.OtpUser;
import org.opentripplanner.middleware.models.RelatedUser;
import org.opentripplanner.middleware.models.TrackedJourney;
import org.opentripplanner.middleware.otp.response.Itinerary;
import org.opentripplanner.middleware.otp.response.Leg;
Expand All @@ -33,6 +35,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opentripplanner.middleware.triptracker.TravelerLocator.ACCEPTABLE_AHEAD_OF_SCHEDULE_IN_MINUTES;
import static org.opentripplanner.middleware.triptracker.TravelerLocator.getBusDepartureTime;
Expand All @@ -46,7 +49,7 @@ class NotifyBusOperatorTest extends OtpMiddlewareTestEnvironment {

private static TrackedJourney trackedJourney;

private static final String routeId = "GwinnettCountyTransit:40";
private static final String ROUTE_ID = "GwinnettCountyTransit:40";

private static final Locale locale = Locale.US;

Expand All @@ -66,7 +69,7 @@ public static void setUp() throws IOException {
Itinerary.class
);
UsRideGwinnettNotifyBusOperator.IS_TEST = true;
UsRideGwinnettNotifyBusOperator.US_RIDE_GWINNETT_QUALIFYING_BUS_NOTIFIER_ROUTES = List.of(routeId);
UsRideGwinnettNotifyBusOperator.US_RIDE_GWINNETT_QUALIFYING_BUS_NOTIFIER_ROUTES = List.of(ROUTE_ID);
}

@AfterEach
Expand All @@ -86,7 +89,7 @@ void canNotifyBusOperatorForScheduledDeparture(Leg busLeg, Itinerary itinerary,
String tripInstruction = TravelerLocator.getInstruction(TripStatus.ON_SCHEDULE, travelerPosition, isStartOfTrip);
TripInstruction expectInstruction = new WaitForTransitInstruction(busLeg, busDepartureTime, locale);
TrackedJourney updated = Persistence.trackedJourneys.getById(trackedJourney.id);
assertTrue(updated.busNotificationMessages.containsKey(routeId));
assertTrue(updated.busNotificationMessages.containsKey(ROUTE_ID));
assertEquals(expectInstruction.build(), tripInstruction, message);
}

Expand All @@ -112,7 +115,7 @@ private static Stream<Arguments> creatNotifyBusOperatorForScheduledDepartureTrac
void shouldCancelBusNotificationForStartOfTrip(boolean expected, Leg expectedLeg, Coordinates currentPosition, String message) {
Leg first = firstLegBusTransit.legs.get(0);
TrackedJourney journey = new TrackedJourney();
journey.busNotificationMessages.put(routeId, "{\"msg_type\": 1}");
journey.busNotificationMessages.put(ROUTE_ID, "{\"msg_type\": 1}");
TravelerPosition travelerPosition = new TravelerPosition(expectedLeg, journey, first, currentPosition);
assertEquals(expected, ManageTripTracking.shouldCancelBusNotificationForStartOfTrip(travelerPosition), message);
}
Expand Down Expand Up @@ -161,9 +164,7 @@ void canCancelBusOperatorNotification() throws JsonProcessingException, Interrup
trackedJourney = createAndPersistTrackedJourney(getEndOfWalkLegCoordinates());
TravelerPosition travelerPosition = new TravelerPosition(trackedJourney, walkToBusTransition, createOtpUser());

busOperatorActions.handleSendNotificationAction(travelerPosition, travelerPosition.nextLeg);
TrackedJourney updated = Persistence.trackedJourneys.getById(trackedJourney.id);
assertTrue(updated.busNotificationMessages.containsKey(routeId));
TrackedJourney updated = sendAndCheckInitialBusOperatorNotification(travelerPosition);
assertEquals(1, getMessage(updated).msg_type);

busOperatorActions.handleCancelNotificationAction(travelerPosition, travelerPosition.nextLeg);
Expand All @@ -184,7 +185,7 @@ void canCancelBusOperatorNotification() throws JsonProcessingException, Interrup
}

private static UsRideGwinnettBusOpNotificationMessage getMessage(TrackedJourney updated) throws JsonProcessingException {
String messageBody = updated.busNotificationMessages.get(routeId);
String messageBody = updated.busNotificationMessages.get(ROUTE_ID);
return getNotificationMessage(messageBody);
}

Expand All @@ -193,18 +194,41 @@ void canNotifyBusOperatorOnlyOnce() throws InterruptedException, JsonProcessingE
trackedJourney = createAndPersistTrackedJourney(getEndOfWalkLegCoordinates());
TravelerPosition travelerPosition = new TravelerPosition(trackedJourney, walkToBusTransition, createOtpUser());

busOperatorActions.handleSendNotificationAction(travelerPosition, travelerPosition.nextLeg);
TrackedJourney updated = Persistence.trackedJourneys.getById(trackedJourney.id);
assertTrue(updated.busNotificationMessages.containsKey(routeId));
assertFalse(UsRideGwinnettNotifyBusOperator.hasNotSentNotificationForRoute(updated, routeId));
UsRideGwinnettBusOpNotificationMessage notifyMessage = getMessage(updated);
TrackedJourney updated = sendAndCheckInitialBusOperatorNotification(travelerPosition);

// A second request to notify the operator should not touch the previous request.
Thread.sleep(20);
busOperatorActions.handleSendNotificationAction(travelerPosition, travelerPosition.nextLeg);
TrackedJourney updated2 = Persistence.trackedJourneys.getById(trackedJourney.id);
assertFalse(UsRideGwinnettNotifyBusOperator.hasNotSentNotificationForRoute(updated2, routeId));
assertEquals(notifyMessage.timestamp, getMessage(updated2).timestamp);
assertFalse(UsRideGwinnettNotifyBusOperator.hasNotSentNotificationForRoute(updated2, ROUTE_ID));
assertEquals(getMessage(updated).timestamp, getMessage(updated2).timestamp);
}

private TrackedJourney sendAndCheckInitialBusOperatorNotification(TravelerPosition travelerPosition) throws JsonProcessingException {
Coordinates position = travelerPosition.currentPosition;
MonitoredTrip trip = new MonitoredTrip();
// Add a confirmed companion to this trip
trip.companion = new RelatedUser();
trip.companion.status = RelatedUser.RelatedUserStatus.CONFIRMED;

// Endpoints indirectly call the TripTrackingData constructor that sets the trip field in Trackedjourney,
// so we add that here to replicate those steps.
TripTrackingData tripData = new TripTrackingData(
trip,
trackedJourney,
List.of(new TrackingLocation(travelerPosition.currentTime, position.lat, position.lon))
);
assertNotNull(tripData.journey.trip);
assertNotNull(trackedJourney.trip);

busOperatorActions.handleSendNotificationAction(travelerPosition, travelerPosition.nextLeg);

TrackedJourney updated = Persistence.trackedJourneys.getById(trackedJourney.id);
assertTrue(updated.busNotificationMessages.containsKey(ROUTE_ID));
assertFalse(UsRideGwinnettNotifyBusOperator.hasNotSentNotificationForRoute(updated, ROUTE_ID));
assertTrue(getMessage(updated).trusted_companion);

return updated;
}

@ParameterizedTest
Expand Down

0 comments on commit 13c2676

Please sign in to comment.