Skip to content
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

Merged

Conversation

nurmAV
Copy link
Contributor

@nurmAV nurmAV commented Aug 10, 2023

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

@nurmAV nurmAV requested a review from a team as a code owner August 10, 2023 10:31
@codecov
Copy link

codecov bot commented Aug 10, 2023

Codecov Report

Patch coverage: 93.44% and project coverage change: +0.08% 🎉

Comparison is base (7136d18) 66.37% compared to head (a9caa84) 66.46%.
Report is 41 commits behind head on dev-2.x.

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     
Files Changed Coverage Δ
...tripplanner/ext/fares/impl/HSLFareServiceImpl.java 68.26% <81.81%> (+4.43%) ⬆️
...tripplanner/ext/fares/impl/DefaultFareService.java 91.57% <96.00%> (-1.04%) ⬇️

... and 29 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Co-authored-by: Leonard Ehrenfried <mail@leonard.io>
Copy link
Member

@optionsome optionsome left a 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.

@t2gran t2gran added this to the 2.4 (next release) milestone Aug 15, 2023
Copy link
Member

@optionsome optionsome left a 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)
Copy link
Member

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.

Copy link
Contributor Author

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 FlexibleTransitLegs

@leonardehrenfried
Copy link
Member

@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.

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 DefaultFareService but there are also a lot of hidden assumptions which we can document as we find them.

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)
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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(
Copy link
Member

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?

@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());
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added those

@t2gran t2gran modified the milestones: 2.4, 2.5 (next release) Sep 13, 2023
Copy link
Member

@leonardehrenfried leonardehrenfried left a 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.

@leonardehrenfried
Copy link
Member

leonardehrenfried commented Sep 14, 2023

Could you also please merge master dev-2.x so I can get an accurate view of the coverage change?

Co-authored-by: Joel Lappalainen <lappalj8@gmail.com>
@optionsome
Copy link
Member

Could you also please merge master so I can get an accurate view of the coverage change?

By master you mean dev-2.x right?

@leonardehrenfried
Copy link
Member

Yes of course.

if (legWithoutRulesFound || legsWithoutMatchingRulesFound) {
fare.addFare(
fareType,
Money.ofFractionalAmount(fares.get(0).currency(), UNKNOWN_FARE_PRICE)
Copy link
Member

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?

Copy link
Contributor Author

@nurmAV nurmAV Sep 14, 2023

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.

Copy link
Member

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.

@optionsome optionsome merged commit 260c581 into opentripplanner:dev-2.x Sep 14, 2023
@optionsome optionsome deleted the DT-5946-missing-ticket-disclaimer branch September 14, 2023 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants