From cda980432dd8eeb208d9eaab7ddaf33db398fb04 Mon Sep 17 00:00:00 2001 From: Paul Kim Date: Fri, 3 Jan 2025 13:14:25 -0500 Subject: [PATCH] Migrate to update_type (#863) * Migrate to update_type * clean up typespecs * PR feedback * Add back excluded prediction types * remove accidentally added typespec --- config/runtime.exs | 2 - lib/content/message/predictions.ex | 3 +- lib/fake/httpoison.ex | 12 +- lib/predictions/prediction.ex | 11 +- lib/predictions/predictions.ex | 162 ++++++----- lib/signs/utilities/messages.ex | 6 +- lib/signs/utilities/predictions.ex | 24 +- test/content/messages/predictions_test.exs | 4 +- test/predictions/predictions_test.exs | 312 ++------------------- test/signs/realtime_test.exs | 25 +- 10 files changed, 147 insertions(+), 414 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 4d1fc5b5b..77c7f3792 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -29,8 +29,6 @@ if config_env() != :test do scu_ip_map: System.get_env("SCU_IP_MAP", "null") |> Jason.decode!(), chelsea_bridge_url: System.get_env("CHELSEA_BRIDGE_URL"), chelsea_bridge_auth: System.get_env("CHELSEA_BRIDGE_AUTH"), - filter_uncertain_predictions?: - System.get_env("FILTER_UNCERTAIN_PREDICTIONS", "false") == "true", number_of_http_updaters: System.get_env("NUMBER_OF_HTTP_UPDATERS", "4") |> String.to_integer(), message_log_zip_url: System.get_env("MESSAGE_LOG_ZIP_URL"), diff --git a/lib/content/message/predictions.ex b/lib/content/message/predictions.ex index a632ed2ce..52341ffad 100644 --- a/lib/content/message/predictions.ex +++ b/lib/content/message/predictions.ex @@ -35,7 +35,6 @@ defmodule Content.Message.Predictions do end min = round(sec / 60) - reverse_prediction? = Signs.Utilities.Predictions.reverse_prediction?(prediction, terminal?) {minutes, approximate?} = cond do @@ -43,7 +42,7 @@ defmodule Content.Message.Predictions do !terminal? and sec <= 30 -> {:arriving, false} !terminal? and sec <= 60 -> {:approaching, false} min > 60 -> {60, true} - reverse_prediction? and min > 20 -> {div(min, 10) * 10, true} + prediction.type == :reverse and min > 20 -> {div(min, 10) * 10, true} true -> {max(min, 1), false} end diff --git a/lib/fake/httpoison.ex b/lib/fake/httpoison.ex index b16bad2cc..ba893acc3 100644 --- a/lib/fake/httpoison.ex +++ b/lib/fake/httpoison.ex @@ -70,8 +70,7 @@ defmodule Fake.HTTPoison do "stop_time_update" => [ %{ "arrival" => %{ - "time" => 1_491_570_120, - "uncertainty" => nil + "time" => 1_491_570_120 }, "departure" => nil, "schedule_relationship" => "SCHEDULED", @@ -80,8 +79,7 @@ defmodule Fake.HTTPoison do }, %{ "arrival" => %{ - "time" => 1_491_570_180, - "uncertainty" => nil + "time" => 1_491_570_180 }, "departure" => nil, "schedule_relationship" => "SCHEDULED", @@ -243,8 +241,7 @@ defmodule Fake.HTTPoison do "stop_time_update" => [ %{ "arrival" => %{ - "time" => 1_491_570_180, - "uncertainty" => 60 + "time" => 1_491_570_180 }, "departure" => nil, "stop_id" => "stop_to_update", @@ -299,8 +296,7 @@ defmodule Fake.HTTPoison do %{ "arrival" => %{ "delay" => nil, - "time" => 1_491_570_080, - "uncertainty" => nil + "time" => 1_491_570_080 }, "departure" => nil, "schedule_relationship" => "SCHEDULED", diff --git a/lib/predictions/prediction.ex b/lib/predictions/prediction.ex index ee9fe08f3..49e7389db 100644 --- a/lib/predictions/prediction.ex +++ b/lib/predictions/prediction.ex @@ -1,9 +1,7 @@ defmodule Predictions.Prediction do defstruct stop_id: nil, seconds_until_arrival: nil, - arrival_certainty: nil, seconds_until_departure: nil, - departure_certainty: nil, seconds_until_passthrough: nil, direction_id: nil, schedule_relationship: nil, @@ -13,16 +11,16 @@ defmodule Predictions.Prediction do stopped_at_predicted_stop?: false, boarding_status: nil, revenue_trip?: true, - vehicle_id: nil + vehicle_id: nil, + type: nil @type trip_id :: String.t() + @type prediction_type :: :mid_trip | :terminal | :reverse | nil @type t :: %__MODULE__{ stop_id: String.t(), seconds_until_arrival: non_neg_integer() | nil, - arrival_certainty: non_neg_integer() | nil, seconds_until_departure: non_neg_integer() | nil, - departure_certainty: non_neg_integer() | nil, seconds_until_passthrough: non_neg_integer() | nil, direction_id: 0 | 1, schedule_relationship: :scheduled | :skipped | nil, @@ -32,6 +30,7 @@ defmodule Predictions.Prediction do stopped_at_predicted_stop?: boolean(), boarding_status: String.t() | nil, revenue_trip?: boolean(), - vehicle_id: String.t() | nil + vehicle_id: String.t() | nil, + type: prediction_type() } end diff --git a/lib/predictions/predictions.ex b/lib/predictions/predictions.ex index c0560d15d..ca3f7ae98 100644 --- a/lib/predictions/predictions.ex +++ b/lib/predictions/predictions.ex @@ -2,30 +2,18 @@ defmodule Predictions.Predictions do alias Predictions.Prediction require Logger + @excluded_prediction_types [] + @spec get_all(map(), DateTime.t()) :: {%{ - optional({String.t(), integer()}) => [Predictions.Prediction.t()] + optional({String.t(), integer()}) => [Prediction.t()] }, MapSet.t(String.t())} def get_all(feed_message, current_time) do predictions = feed_message["entity"] |> Stream.map(& &1["trip_update"]) - |> Stream.filter( - &(relevant_rail_route?(&1["trip"]["route_id"]) and - &1["trip"]["schedule_relationship"] != "CANCELED") - ) - |> Stream.flat_map(&transform_stop_time_updates/1) - |> Stream.filter(fn {update, _, _, _, _, _, _} -> - (update["arrival"] && update["arrival"]["uncertainty"]) || - (update["departure"] && update["departure"]["uncertainty"]) || - update["passthrough_time"] - end) - |> Stream.map(&prediction_from_update(&1, current_time)) - |> Enum.reject( - &((is_nil(&1.seconds_until_arrival) and is_nil(&1.seconds_until_departure) and - is_nil(&1.seconds_until_passthrough)) or - has_departed?(&1)) - ) + |> Stream.filter(&valid_trip_update?/1) + |> Stream.flat_map(&trip_update_to_predictions(&1, current_time)) vehicles_running_revenue_trips = predictions @@ -38,77 +26,90 @@ defmodule Predictions.Predictions do end), vehicles_running_revenue_trips} end - @spec transform_stop_time_updates(map()) :: [ - {map(), String.t(), String.t(), integer(), String.t(), boolean(), String.t() | nil} - ] - defp transform_stop_time_updates(trip_update) do - last_stop_id = - Enum.max_by(trip_update["stop_time_update"], fn update -> - if update["arrival"], do: update["arrival"]["time"], else: 0 - end) - |> Map.get("stop_id") - - vehicle_id = get_in(trip_update, ["vehicle", "id"]) - - Enum.map( - trip_update["stop_time_update"], - &{&1, last_stop_id, trip_update["trip"]["route_id"], trip_update["trip"]["direction_id"], - trip_update["trip"]["trip_id"], trip_update["trip"]["revenue"], vehicle_id} - ) + defp valid_trip_update?(trip_update) do + relevant_rail_route?(trip_update["trip"]["route_id"]) and + trip_update["trip"]["schedule_relationship"] != "CANCELED" + end + + @spec trip_update_to_predictions(map(), DateTime.t()) :: [Prediction.t()] + defp trip_update_to_predictions(trip_update, current_time) do + vehicle_id = trip_update["vehicle"]["id"] + + for stop_time_update <- trip_update["stop_time_update"], + is_valid_prediction?(stop_time_update), + prediction = + build_prediction( + stop_time_update, + get_destination_stop_id(trip_update), + vehicle_id, + Engine.Locations.for_vehicle(vehicle_id), + trip_update["trip"]["route_id"], + trip_update["trip"]["direction_id"], + trip_update["trip"]["trip_id"], + trip_update["trip"]["revenue"], + get_prediction_type(trip_update["update_type"]), + DateTime.to_unix(current_time) + ), + not has_departed?(prediction), + not is_excluded_prediction_type?(prediction), + do: prediction end - @spec prediction_from_update( - {map(), String.t(), String.t(), integer(), Predictions.Prediction.trip_id(), boolean(), - String.t() | nil}, - DateTime.t() + @spec build_prediction( + map(), + String.t(), + String.t(), + Locations.Location.t(), + String.t(), + integer(), + Predictions.Prediction.trip_id(), + boolean(), + atom(), + integer() ) :: Prediction.t() - defp prediction_from_update( - {stop_time_update, last_stop_id, route_id, direction_id, trip_id, revenue_trip?, - vehicle_id}, - current_time + defp build_prediction( + stop_time_update, + destination_stop_id, + vehicle_id, + vehicle_location, + route_id, + direction_id, + trip_id, + revenue_trip?, + prediction_type, + current_time_seconds ) do - current_time_seconds = DateTime.to_unix(current_time) - schedule_relationship = translate_schedule_relationship(stop_time_update["schedule_relationship"]) seconds_until_arrival = - if stop_time_update["arrival"] && - sufficient_certainty?(stop_time_update["arrival"], route_id), - do: stop_time_update["arrival"]["time"] - current_time_seconds, - else: nil + stop_time_update["arrival"] && stop_time_update["arrival"]["time"] - current_time_seconds seconds_until_departure = - if stop_time_update["departure"] && - sufficient_certainty?(stop_time_update["departure"], route_id), - do: stop_time_update["departure"]["time"] - current_time_seconds, - else: nil + stop_time_update["departure"] && + stop_time_update["departure"]["time"] - current_time_seconds seconds_until_passthrough = - if stop_time_update["passthrough_time"], - do: stop_time_update["passthrough_time"] - current_time_seconds, - else: nil - - vehicle_location = Engine.Locations.for_vehicle(vehicle_id) + stop_time_update["passthrough_time"] && + stop_time_update["passthrough_time"] - current_time_seconds %Prediction{ stop_id: stop_time_update["stop_id"], direction_id: direction_id, seconds_until_arrival: max(0, seconds_until_arrival), - arrival_certainty: stop_time_update["arrival"]["uncertainty"], seconds_until_departure: seconds_until_departure, - departure_certainty: stop_time_update["departure"]["uncertainty"], seconds_until_passthrough: max(0, seconds_until_passthrough), schedule_relationship: schedule_relationship, route_id: route_id, trip_id: trip_id, - destination_stop_id: last_stop_id, + destination_stop_id: destination_stop_id, stopped_at_predicted_stop?: not is_nil(vehicle_location) and vehicle_location.status == :stopped_at and stop_time_update["stop_id"] == vehicle_location.stop_id, boarding_status: stop_time_update["boarding_status"], revenue_trip?: revenue_trip?, - vehicle_id: vehicle_id + vehicle_id: vehicle_id, + type: prediction_type } end @@ -142,23 +143,40 @@ defmodule Predictions.Predictions do :scheduled end - @spec sufficient_certainty?(map(), String.t()) :: boolean() - defp sufficient_certainty?(_stop_time_event, route_id) - when route_id in ["Mattapan", "Green-B", "Green-C", "Green-D", "Green-E"] do - true + defp get_destination_stop_id(trip_update) do + Enum.max_by(trip_update["stop_time_update"], fn update -> + if update["arrival"], do: update["arrival"]["time"], else: 0 + end) + |> Map.get("stop_id") end - defp sufficient_certainty?(stop_time_event, _route_id) do - if Application.get_env(:realtime_signs, :filter_uncertain_predictions?) do - is_nil(stop_time_event["uncertainty"]) or stop_time_event["uncertainty"] <= 300 - else - true + @spec get_prediction_type(String.t()) :: Prediction.prediction_type() + defp get_prediction_type(update_type) do + case update_type do + "mid_trip" -> :mid_trip + "at_terminal" -> :terminal + "reverse_trip" -> :reverse + _ -> nil end end - @spec has_departed?(Predictions.Prediction.t()) :: boolean() + defp is_valid_prediction?(stop_time_update) do + not (is_nil(stop_time_update["arrival"]) and is_nil(stop_time_update["departure"]) and + is_nil(stop_time_update["passthrough_time"])) + end + + @spec is_excluded_prediction_type?(Prediction.t()) :: boolean() + defp is_excluded_prediction_type?(prediction) + when prediction.route_id in ["Mattapan", "Green-B", "Green-C", "Green-D", "Green-E"], + do: false + + defp is_excluded_prediction_type?(prediction) do + prediction.type in @excluded_prediction_types + end + + @spec has_departed?(Prediction.t()) :: boolean() defp has_departed?(prediction) do - prediction.seconds_until_departure && prediction.seconds_until_departure < 0 && + not is_nil(prediction.seconds_until_departure) and prediction.seconds_until_departure < 0 and not prediction.stopped_at_predicted_stop? end end diff --git a/lib/signs/utilities/messages.ex b/lib/signs/utilities/messages.ex index 915c696e5..cf7850dbb 100644 --- a/lib/signs/utilities/messages.ex +++ b/lib/signs/utilities/messages.ex @@ -197,12 +197,12 @@ defmodule Signs.Utilities.Messages do end, prediction.seconds_until_departure, prediction.seconds_until_arrival} end) |> then(fn predictions -> if(sign_config == :headway, do: [], else: predictions) end) - |> filter_early_am_predictions(config, current_time, scheduled) + |> filter_early_am_predictions(current_time, scheduled) |> filter_large_red_line_gaps() |> get_unique_destination_predictions(Signs.Utilities.SourceConfig.single_route(config)) end - defp filter_early_am_predictions(predictions, config, current_time, scheduled) do + defp filter_early_am_predictions(predictions, current_time, scheduled) do cond do !in_early_am?(current_time, scheduled) -> predictions @@ -216,7 +216,7 @@ defmodule Signs.Utilities.Messages do # except for Prudential or Symphony EB Enum.reject( predictions, - &(Signs.Utilities.Predictions.reverse_prediction?(&1, config.terminal?) and + &(&1.type == :reverse and &1.stop_id not in ["70240", "70242"]) ) end diff --git a/lib/signs/utilities/predictions.ex b/lib/signs/utilities/predictions.ex index 23bbc8d1a..478dde888 100644 --- a/lib/signs/utilities/predictions.ex +++ b/lib/signs/utilities/predictions.ex @@ -9,7 +9,6 @@ defmodule Signs.Utilities.Predictions do require Content.Utilities alias Signs.Utilities.SourceConfig - @reverse_prediction_certainty 360 @max_prediction_sec 60 * 60 @reverse_prediction_cutoff_sec 20 * 60 @@ -53,18 +52,6 @@ defmodule Signs.Utilities.Predictions do end end - @spec reverse_prediction?(Predictions.Prediction.t(), boolean()) :: boolean() - def reverse_prediction?(%Predictions.Prediction{} = prediction, terminal?) do - certainty = - if terminal? || !prediction.seconds_until_arrival do - prediction.departure_certainty - else - prediction.arrival_certainty - end - - certainty == @reverse_prediction_certainty - end - @spec get_passthrough_train_audio(Signs.Realtime.predictions()) :: [Content.Audio.t()] def get_passthrough_train_audio({top_predictions, bottom_predictions}) do prediction_passthrough_audios(top_predictions) ++ @@ -100,10 +87,10 @@ defmodule Signs.Utilities.Predictions do |> Enum.take(1) end - defp approximate_time?(sec, certainty) do + defp approximate_time?(sec, prediction_type) do sec && (sec > @max_prediction_sec || - (sec > @reverse_prediction_cutoff_sec && certainty == @reverse_prediction_certainty)) + (sec > @reverse_prediction_cutoff_sec && prediction_type == :reverse)) end @spec stopped_train?(Predictions.Prediction.t()) :: boolean() @@ -111,14 +98,13 @@ defmodule Signs.Utilities.Predictions do boarding_status: boarding_status, seconds_until_arrival: seconds_until_arrival, seconds_until_departure: seconds_until_departure, - arrival_certainty: arrival_certainty, - departure_certainty: departure_certainty + type: type }) do # Note: This performs a similar (but not identical) calculation to the one in the Message # code for determining whether a prediction will show an approximate time. Ideally they # should both call the same logic. - approximate_arrival? = approximate_time?(seconds_until_arrival, arrival_certainty) - approximate_departure? = approximate_time?(seconds_until_departure, departure_certainty) + approximate_arrival? = approximate_time?(seconds_until_arrival, type) + approximate_departure? = approximate_time?(seconds_until_departure, type) boarding_status && String.starts_with?(boarding_status, "Stopped") && boarding_status != "Stopped at station" && !approximate_arrival? && !approximate_departure? diff --git a/test/content/messages/predictions_test.exs b/test/content/messages/predictions_test.exs index f4daee5a4..88d5495bc 100644 --- a/test/content/messages/predictions_test.exs +++ b/test/content/messages/predictions_test.exs @@ -72,10 +72,10 @@ defmodule Content.Message.PredictionsTest do test "shows approximate minutes for longer turnaround predictions" do prediction = %Predictions.Prediction{ seconds_until_arrival: 25 * 60, - arrival_certainty: 360, direction_id: 0, route_id: "Mattapan", - destination_stop_id: "70275" + destination_stop_id: "70275", + type: :reverse } msg = Content.Message.Predictions.new(prediction, false, nil) diff --git a/test/predictions/predictions_test.exs b/test/predictions/predictions_test.exs index 63eb514ee..5e7418e04 100644 --- a/test/predictions/predictions_test.exs +++ b/test/predictions/predictions_test.exs @@ -19,8 +19,7 @@ defmodule Predictions.PredictionsTest do %{ "arrival" => nil, "departure" => %{ - "time" => 1_491_570_120, - "uncertainty" => 60 + "time" => 1_491_570_120 }, "stop_id" => "70263", "stop_sequence" => 1, @@ -28,8 +27,7 @@ defmodule Predictions.PredictionsTest do }, %{ "arrival" => %{ - "time" => 1_491_570_180, - "uncertainty" => 60 + "time" => 1_491_570_180 }, "departure" => nil, "stop_id" => "70261", @@ -50,7 +48,8 @@ defmodule Predictions.PredictionsTest do "id" => "G-10040", "label" => "3260", "license_plate" => nil - } + }, + "update_type" => "mid_trip" }, "vehicle" => nil } @@ -69,21 +68,20 @@ defmodule Predictions.PredictionsTest do %Predictions.Prediction{ stop_id: "70261", seconds_until_arrival: 180, - arrival_certainty: 60, direction_id: 0, schedule_relationship: :scheduled, route_id: "Mattapan", destination_stop_id: "70261", trip_id: "32568935", revenue_trip?: true, - vehicle_id: "G-10040" + vehicle_id: "G-10040", + type: :mid_trip } ], {"70263", 0} => [ %Predictions.Prediction{ stop_id: "70263", seconds_until_departure: 120, - departure_certainty: 60, direction_id: 0, schedule_relationship: :scheduled, route_id: "Mattapan", @@ -91,7 +89,8 @@ defmodule Predictions.PredictionsTest do boarding_status: "Stopped 1 stop away", trip_id: "32568935", revenue_trip?: true, - vehicle_id: "G-10040" + vehicle_id: "G-10040", + type: :mid_trip } ] } @@ -112,8 +111,7 @@ defmodule Predictions.PredictionsTest do %{ "arrival" => %{ "delay" => nil, - "time" => 1_491_570_120, - "uncertainty" => 60 + "time" => 1_491_570_120 }, "departure" => nil, "stop_id" => "70263", @@ -124,8 +122,7 @@ defmodule Predictions.PredictionsTest do %{ "arrival" => %{ "delay" => nil, - "time" => 1_491_570_180, - "uncertainty" => 60 + "time" => 1_491_570_180 }, "departure" => nil, "stop_id" => "70261", @@ -156,7 +153,8 @@ defmodule Predictions.PredictionsTest do "id" => "G-10040", "label" => "3260", "license_plate" => nil - } + }, + "update_type" => "mid_trip" }, "vehicle" => nil }, @@ -170,8 +168,7 @@ defmodule Predictions.PredictionsTest do %{ "arrival" => %{ "delay" => nil, - "time" => 1_491_570_200, - "uncertainty" => 60 + "time" => 1_491_570_200 }, "departure" => nil, "stop_id" => "70038", @@ -182,8 +179,7 @@ defmodule Predictions.PredictionsTest do %{ "arrival" => %{ "delay" => nil, - "time" => 1_491_570_400, - "uncertainty" => 60 + "time" => 1_491_570_400 }, "departure" => nil, "stop_id" => "70060", @@ -206,7 +202,8 @@ defmodule Predictions.PredictionsTest do "id" => "vehicle_2", "label" => "3261", "license_plate" => nil - } + }, + "update_type" => "mid_trip" }, "vehicle" => nil }, @@ -248,56 +245,56 @@ defmodule Predictions.PredictionsTest do %Predictions.Prediction{ stop_id: "70261", seconds_until_arrival: 180, - arrival_certainty: 60, schedule_relationship: :scheduled, direction_id: 0, route_id: "Mattapan", destination_stop_id: "70261", trip_id: "32568935", revenue_trip?: true, - vehicle_id: "G-10040" + vehicle_id: "G-10040", + type: :mid_trip } ], {"70263", 0} => [ %Predictions.Prediction{ stop_id: "70263", seconds_until_arrival: 120, - arrival_certainty: 60, direction_id: 0, schedule_relationship: :scheduled, route_id: "Mattapan", destination_stop_id: "70261", trip_id: "32568935", revenue_trip?: true, - vehicle_id: "G-10040" + vehicle_id: "G-10040", + type: :mid_trip } ], {"70038", 1} => [ %Predictions.Prediction{ stop_id: "70038", seconds_until_arrival: 200, - arrival_certainty: 60, direction_id: 1, schedule_relationship: :scheduled, route_id: "Blue", destination_stop_id: "70060", trip_id: "trip_2", revenue_trip?: true, - vehicle_id: "vehicle_2" + vehicle_id: "vehicle_2", + type: :mid_trip } ], {"70060", 1} => [ %Predictions.Prediction{ stop_id: "70060", seconds_until_arrival: 400, - arrival_certainty: 60, direction_id: 1, schedule_relationship: :scheduled, route_id: "Blue", destination_stop_id: "70060", trip_id: "trip_2", revenue_trip?: true, - vehicle_id: "vehicle_2" + vehicle_id: "vehicle_2", + type: :mid_trip } ] } @@ -318,8 +315,7 @@ defmodule Predictions.PredictionsTest do %{ "arrival" => %{ "delay" => nil, - "time" => Timex.to_unix(@current_time) - 100, - "uncertainty" => 60 + "time" => Timex.to_unix(@current_time) - 100 }, "departure" => nil, "schedule_relationship" => "SCHEDULED", @@ -371,264 +367,6 @@ defmodule Predictions.PredictionsTest do ] }, _} = get_all(feed_message, @current_time) end - - test "include predictions with low uncertainty" do - reassign_env(:filter_uncertain_predictions?, true) - - feed_message = %{ - "entity" => [ - %{ - "alert" => nil, - "id" => "1490783458_32568935", - "is_deleted" => false, - "trip_update" => %{ - "delay" => nil, - "stop_time_update" => [ - %{ - "arrival" => nil, - "departure" => %{ - "delay" => nil, - "time" => 1_491_570_120, - "uncertainty" => 60 - }, - "schedule_relationship" => "SCHEDULED", - "stop_id" => "70063", - "stop_sequence" => 1, - "stops_away" => 1, - "stopped?" => true, - "boarding_status" => "Stopped 1 stop away" - } - ], - "timestamp" => nil, - "trip" => %{ - "direction_id" => 0, - "route_id" => "Red", - "schedule_relationship" => "SCHEDULED", - "start_date" => "20170329", - "start_time" => nil, - "trip_id" => "32568935", - "revenue" => true - }, - "vehicle" => %{ - "id" => "R-54639F6C", - "label" => "1631", - "license_plate" => nil - } - }, - "vehicle" => nil - } - ], - "header" => %{ - "gtfs_realtime_version" => "1.0", - "incrementality" => "FULL_DATASET", - "timestamp" => 1_490_783_458 - } - } - - assert {%{ - {"70063", 0} => [ - %Predictions.Prediction{ - seconds_until_departure: 120 - } - ] - }, _} = get_all(feed_message, @current_time) - end - - test "filter predictions with high uncertainty" do - reassign_env(:filter_uncertain_predictions?, true) - - feed_message = %{ - "entity" => [ - %{ - "alert" => nil, - "id" => "1490783458_32568935", - "is_deleted" => false, - "trip_update" => %{ - "delay" => nil, - "stop_time_update" => [ - %{ - "arrival" => %{ - "delay" => nil, - "time" => 1_491_570_110, - "uncertainty" => 360 - }, - "departure" => %{ - "delay" => nil, - "time" => 1_491_570_120, - "uncertainty" => 360 - }, - "schedule_relationship" => "SCHEDULED", - "stop_id" => "70063", - "stop_sequence" => 1, - "stops_away" => 1, - "stopped?" => true, - "boarding_status" => "Stopped 1 stop away" - } - ], - "timestamp" => nil, - "trip" => %{ - "direction_id" => 0, - "route_id" => "Blue", - "schedule_relationship" => "SCHEDULED", - "start_date" => "20170329", - "start_time" => nil, - "trip_id" => "32568935", - "revenue" => true - }, - "vehicle" => %{ - "id" => "R-54639F6C", - "label" => "1631", - "license_plate" => nil - } - }, - "vehicle" => nil - } - ], - "header" => %{ - "gtfs_realtime_version" => "1.0", - "incrementality" => "FULL_DATASET", - "timestamp" => 1_490_783_458 - } - } - - {predictions_map, _} = get_all(feed_message, @current_time) - - assert predictions_map == %{} - end - - test "doesn't filter predictions with high uncertainty when feature is off" do - reassign_env(:filter_uncertain_predictions?, false) - - feed_message = %{ - "entity" => [ - %{ - "alert" => nil, - "id" => "1490783458_32568935", - "is_deleted" => false, - "trip_update" => %{ - "delay" => nil, - "stop_time_update" => [ - %{ - "arrival" => %{ - "delay" => nil, - "time" => 1_491_570_110, - "uncertainty" => 360 - }, - "departure" => %{ - "delay" => nil, - "time" => 1_491_570_120, - "uncertainty" => 360 - }, - "schedule_relationship" => "SCHEDULED", - "stop_id" => "70063", - "stop_sequence" => 1, - "stops_away" => 1, - "stopped?" => true, - "boarding_status" => "Stopped 1 stop away" - } - ], - "timestamp" => nil, - "trip" => %{ - "direction_id" => 0, - "route_id" => "Red", - "schedule_relationship" => "SCHEDULED", - "start_date" => "20170329", - "start_time" => nil, - "trip_id" => "32568935", - "revenue" => true - }, - "vehicle" => %{ - "id" => "R-54639F6C", - "label" => "1631", - "license_plate" => nil - } - }, - "vehicle" => nil - } - ], - "header" => %{ - "gtfs_realtime_version" => "1.0", - "incrementality" => "FULL_DATASET", - "timestamp" => 1_490_783_458 - } - } - - assert {%{ - {"70063", 0} => [ - %Predictions.Prediction{ - seconds_until_arrival: 110, - seconds_until_departure: 120 - } - ] - }, _} = get_all(feed_message, @current_time) - end - - test "doesn't filter out uncertain light rail predictions" do - reassign_env(:filter_uncertain_predictions?, true) - - feed_message = %{ - "entity" => [ - %{ - "alert" => nil, - "id" => "1490783458_32568935", - "is_deleted" => false, - "trip_update" => %{ - "delay" => nil, - "stop_time_update" => [ - %{ - "arrival" => %{ - "delay" => nil, - "time" => 1_491_570_110, - "uncertainty" => 360 - }, - "departure" => %{ - "delay" => nil, - "time" => 1_491_570_120, - "uncertainty" => 360 - }, - "schedule_relationship" => "SCHEDULED", - "stop_id" => "70263", - "stop_sequence" => 1, - "stops_away" => 1, - "stopped?" => true, - "boarding_status" => "Stopped 1 stop away" - } - ], - "timestamp" => nil, - "trip" => %{ - "direction_id" => 0, - "route_id" => "Mattapan", - "schedule_relationship" => "SCHEDULED", - "start_date" => "20170329", - "start_time" => nil, - "trip_id" => "32568935", - "revenue" => true - }, - "vehicle" => %{ - "id" => "G-10040", - "label" => "3260", - "license_plate" => nil - } - }, - "vehicle" => nil - } - ], - "header" => %{ - "gtfs_realtime_version" => "1.0", - "incrementality" => "FULL_DATASET", - "timestamp" => 1_490_783_458 - } - } - - assert {%{ - {"70263", 0} => [ - %Predictions.Prediction{ - seconds_until_arrival: 110, - seconds_until_departure: 120 - } - ] - }, _} = get_all(feed_message, @current_time) - end end describe "parse_pb_response/1" do diff --git a/test/signs/realtime_test.exs b/test/signs/realtime_test.exs index 294edbd3d..7044b156c 100644 --- a/test/signs/realtime_test.exs +++ b/test/signs/realtime_test.exs @@ -488,7 +488,7 @@ defmodule Signs.RealtimeTest do destination: :mattapan, seconds_until_departure: 2020, stopped: 8, - departure_certainty: 360 + type: :reverse ) ] end) @@ -1214,8 +1214,8 @@ defmodule Signs.RealtimeTest do test "When sign in partial am suppression shows mid-trip and terminal predictions but filters out reverse predictions" do expect(Engine.Predictions.Mock, :for_stop, fn _, _ -> [ - prediction(destination: :ashmont, arrival: 120, arrival_certainty: 360), - prediction(destination: :ashmont, arrival: 240, arrival_certainty: 120) + prediction(destination: :ashmont, arrival: 120, type: :reverse), + prediction(destination: :ashmont, arrival: 240, type: :terminal) ] end) @@ -1250,16 +1250,16 @@ defmodule Signs.RealtimeTest do }) end - test "When sign in partial am suppression, filters stopped predictions based on certainty" do + test "When sign in partial am suppression, filters stopped predictions based on prediction type" do expect(Engine.Predictions.Mock, :for_stop, fn _, _ -> [ - prediction(destination: :ashmont, arrival: 120, stopped: 2, arrival_certainty: 360), + prediction(destination: :ashmont, arrival: 120, stopped: 2, type: :reverse), prediction( destination: :ashmont, arrival: 240, stopped: 3, - arrival_certainty: 120, - trip_id: "1" + trip_id: "1", + type: :terminal ) ] end) @@ -1295,7 +1295,7 @@ defmodule Signs.RealtimeTest do test "mezzanine sign, one line in full am suppression, one line in partial am suppression defaulting to headways" do expect(Engine.Predictions.Mock, :for_stop, fn _, _ -> - [prediction(arrival: 180, destination: :ashmont, arrival_certainty: 360)] + [prediction(arrival: 180, destination: :ashmont, type: :reverse)] end) expect(Engine.Predictions.Mock, :for_stop, fn _, _ -> [] end) @@ -1325,7 +1325,7 @@ defmodule Signs.RealtimeTest do test "mezzanine sign, early am, both lines in partial am suppression defaulting to headways" do expect(Engine.Predictions.Mock, :for_stop, fn _, _ -> - [prediction(arrival: 180, destination: :ashmont, arrival_certainty: 360)] + [prediction(arrival: 180, destination: :ashmont, type: :reverse)] end) expect(Engine.Predictions.Mock, :for_stop, fn _, _ -> [] end) @@ -1428,7 +1428,7 @@ defmodule Signs.RealtimeTest do destination: :alewife, arrival: 240, stop_id: "70086", - arrival_certainty: 360 + type: :reverse ) ] end) @@ -1887,9 +1887,7 @@ defmodule Signs.RealtimeTest do %Predictions.Prediction{ stop_id: Keyword.get(opts, :stop_id, "1"), seconds_until_arrival: Keyword.get(opts, :seconds_until_arrival), - arrival_certainty: Keyword.get(opts, :arrival_certainty), seconds_until_departure: Keyword.get(opts, :seconds_until_departure), - departure_certainty: Keyword.get(opts, :departure_certainty), seconds_until_passthrough: Keyword.get(opts, :seconds_until_passthrough), direction_id: Keyword.get(opts, :direction_id, 0), schedule_relationship: Keyword.get(opts, :schedule_relationship), @@ -1899,7 +1897,8 @@ defmodule Signs.RealtimeTest do stopped_at_predicted_stop?: Keyword.get(opts, :stopped_at_predicted_stop, false), boarding_status: Keyword.get(opts, :boarding_status), revenue_trip?: true, - vehicle_id: "v1" + vehicle_id: "v1", + type: Keyword.get(opts, :type, :mid_trip) } end