-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider feed id in HSL fare service #5284
Consider feed id in HSL fare service #5284
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## dev-2.x #5284 +/- ##
=============================================
+ Coverage 66.37% 66.46% +0.08%
- Complexity 15184 15225 +41
=============================================
Files 1787 1786 -1
Lines 69263 69290 +27
Branches 7339 7318 -21
=============================================
+ Hits 45974 46054 +80
+ Misses 20804 20752 -52
+ Partials 2485 2484 -1
☔ View full report in Codecov by Sentry. |
src/ext/java/org/opentripplanner/ext/fares/impl/HSLFareServiceImpl.java
Outdated
Show resolved
Hide resolved
Co-authored-by: Leonard Ehrenfried <mail@leonard.io>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is still an issue that wrong fare is suggested in some cases. I tried searching for a trip from somewhere in Helsinki to Tampere and it suggested two HSL fares even though you would need a Tampere fare instead of the other HSL fare. You need HSL, tampere and digitraffic data to test it, maybe there is a simpler way to replicate the problem with unit tests.
…com/OpenTripPlanner into DT-5946-missing-ticket-disclaimer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@leonardehrenfried mentioned in the dev meeting that he would prefer to have the updated calculateFares code in the DefaultFareServiceImpl instead of duplicating most of the code to the HSLFareServiceImpl. Probably then we should also add some tests to the default service.
var legsByFeed = itinerary | ||
.getLegs() | ||
.stream() | ||
.filter(leg -> leg instanceof ScheduledTransitLeg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might need to consider FlexibleTransitLeg
here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was handled by moving the multifeed logic into the DefaultFareService
that already considers FlexibleTransitLeg
s
Indeed. It's going to be a maintenance nightmare if we copy and paste the code. There is a small number of tests for the Luckily there are lots and lots of tests for city specific calculators and also some integration tests so all in all I'm pretty confident of not breaking anything by accident. A long term goal for HSL could be to move to Fares V2 where the code isn't quite so bogged down with legacy issues. |
if (legWithoutRulesFound) { | ||
fare.addFare( | ||
fareType, | ||
Money.ofFractionalAmount(fares.get(0).currency(), Float.POSITIVE_INFINITY) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite dubious. You're adding an infinite fare when you have a leg without rules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it looks a bit funny but that seems to be how the fare is set for similar single feed cases in the performSearch method. I could of course change that to directly give the -0.01 that seems to be the current way to indicate that some legs do not have fares. Or do you maybe have some other ideas on how this should be handled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but we are not in the performSearch
method. The positive infinity is directly returned to the client.
If we want -1 cent then we need to return it here.
Also, we need lots and lots of tests that document what exactly the expected return values are since it's very confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll change that infinity to the -0.01. I added two test cases for the new multifeed logic. Is there some pre-existing functionality that I should add tests for in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is lots of functionality that we should test but knowledge about what the expectations are has been lost over time. The best we can do is to write tests when we add new features or find bugs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I added some tests cases for the new multifeed logic
.map(r -> r.fareId()) | ||
.toList(); | ||
|
||
assertEquals( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add assertions for the expected prices like is done here?
OpenTripPlanner/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java
Lines 75 to 100 in bf90bcf
@Test | |
void unknownLeg() { | |
var service = new DefaultFareService(); | |
service.addFareRules(FareType.regular, List.of(AIRPORT_TO_CITY_CENTER_SET)); | |
var itin = newItinerary(Place.forStop(AIRPORT_STOP), T11_00) | |
.bus(1, T11_00, T11_12, Place.forStop(CITY_CENTER_A_STOP)) | |
.bus(3, T11_20, T11_33, Place.forStop(SUBURB_STOP)) | |
.build(); | |
var fare = service.calculateFares(itin); | |
assertNotNull(fare); | |
var price = fare.getFare(FareType.regular); | |
assertEquals(Money.usDollars(-0.01f), price); | |
var components = fare.getComponents(FareType.regular); | |
assertEquals(1, components.size()); | |
var component = components.get(0); | |
assertEquals(AIRPORT_TO_CITY_CENTER_SET.getFareAttribute().getId(), component.fareId()); | |
assertEquals(Money.usDollars(10), component.price()); | |
var firstBusLeg = itin.firstTransitLeg().get(); | |
assertEquals(List.of(firstBusLeg), component.legs()); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added those
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is ok but rather than trying to fix the very flawed concept of the FareComponent
I would encourage HSL to migrate to the new API that replaces FareComponent
with FareProduct
.
https://docs.opentripplanner.org/api/dev-2.x/graphql-gtfs/types/FareProductUse
It also assigns the fares directly to the legs which makes displaying them in the UI easier.
src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java
Outdated
Show resolved
Hide resolved
src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java
Outdated
Show resolved
Hide resolved
src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java
Outdated
Show resolved
Hide resolved
src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java
Outdated
Show resolved
Hide resolved
src/ext/java/org/opentripplanner/ext/fares/impl/HSLFareServiceImpl.java
Outdated
Show resolved
Hide resolved
Could you also please merge |
Co-authored-by: Joel Lappalainen <lappalj8@gmail.com>
By master you mean dev-2.x right? |
Yes of course. |
if (legWithoutRulesFound || legsWithoutMatchingRulesFound) { | ||
fare.addFare( | ||
fareType, | ||
Money.ofFractionalAmount(fares.get(0).currency(), UNKNOWN_FARE_PRICE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I'm reconsidering this. If no fare could be found, should we simply skip this? Does your UI expect there to be a -1 cent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it specifically checks if the price is -1 cent and if it is, it warns the user of missing fares. Otherwise no warning is shown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright then.
My point about moving to the more expressive API still stands.
Summary
Previously, the HSL fare service did not consider which feed fare rules and attributes are from. This led to tickets from one feed to be sometimes applicable for legs originating from other feeds with no fare attributes or rules. This PR adds the feed consideration into the HSL fare service.
Unit tests
A unit test was added in HSLFareServiceTest. Known erratic ticket suggestions were also manually checked