From 1ddbaed266b40282225c8c2209565b0da674e963 Mon Sep 17 00:00:00 2001 From: Allison King Date: Mon, 6 Jul 2026 16:51:49 -0400 Subject: [PATCH 1/3] Remove call to hook Alerts manager handles adding informed entities now --- apps/state/lib/state/alert.ex | 3 - apps/state/lib/state/alert/hooks.ex | 117 ---------------------------- 2 files changed, 120 deletions(-) delete mode 100644 apps/state/lib/state/alert/hooks.ex diff --git a/apps/state/lib/state/alert.ex b/apps/state/lib/state/alert.ex index af6d925bd..c3c9c6a46 100644 --- a/apps/state/lib/state/alert.ex +++ b/apps/state/lib/state/alert.ex @@ -77,7 +77,4 @@ defmodule State.Alert do for table <- @subtables, do: table.update(all_alerts) :ok end - - @impl State.Server - defdelegate pre_insert_hook(alert), to: State.Alert.Hooks end diff --git a/apps/state/lib/state/alert/hooks.ex b/apps/state/lib/state/alert/hooks.ex deleted file mode 100644 index a4ca3edea..000000000 --- a/apps/state/lib/state/alert/hooks.ex +++ /dev/null @@ -1,117 +0,0 @@ -defmodule State.Alert.Hooks do - @moduledoc """ - Implementation of hooks to process Alerts before inserting them into the table. - """ - alias Model.Alert - - @spec pre_insert_hook(Alert.t()) :: [Alert.t()] - def pre_insert_hook(alert) do - entities = add_computed_entities(alert.informed_entity) - - [ - %{alert | informed_entity: entities} - ] - end - - defp add_computed_entities(entities) do - entities - |> Stream.concat(get_parent_station_entities(entities)) - |> Enum.flat_map(&include_alternate_trip_entities/1) - |> Enum.uniq() - end - - # Parent station informed entities that share values for these keys - # will each have their `activities` replaced with the union of all of - # the group's `activities` lists: - # [%{activities: ["BOARD"]}, %{activities: ["BOARD", "EXIT"]}] - # => - # [%{activities: ["BOARD", "EXIT"]}, %{activities: ["BOARD", "EXIT"]}] - @parent_station_entity_activity_merge_criteria [:route, :stop, :trip] - - @spec get_parent_station_entities([Alert.informed_entity()]) :: [Alert.informed_entity()] - defp get_parent_station_entities(entities) do - entities - |> Stream.map(&get_parent_station_entity/1) - |> Stream.reject(&is_nil/1) - |> Enum.group_by(&Map.take(&1, @parent_station_entity_activity_merge_criteria)) - |> Enum.flat_map(&merge_parent_entity_activities/1) - end - - defp get_parent_station_entity(%{stop: stop_id} = entity) when is_binary(stop_id) do - case State.Stop.by_id(stop_id) do - %{parent_station: station} when is_binary(station) -> - %{entity | stop: station} - - _ -> - nil - end - end - - defp get_parent_station_entity(_entity) do - nil - end - - defp merge_parent_entity_activities({_key, parent_entities}) do - merged_activities = - parent_entities - |> Enum.flat_map(&(&1[:activities] || [])) - |> Enum.uniq() - |> Enum.sort() - - if merged_activities == [] do - parent_entities - else - parent_entities - |> Enum.map(&Map.put(&1, :activities, merged_activities)) - |> Enum.uniq() - end - end - - @spec include_alternate_trip_entities(Alert.informed_entity()) :: [Alert.informed_entity()] - defp include_alternate_trip_entities(%{trip: trip_id} = entity) when is_binary(trip_id) do - case all_route_entities(entity) do - [] -> - [entity] - - entities -> - entities - end - end - - defp include_alternate_trip_entities(entity) do - [entity] - end - - defp all_route_entities(%{trip: trip_id} = entity) when is_binary(trip_id) do - trips = State.Trip.by_id(trip_id) - - trip_entities = - for trip <- trips do - merge = - case State.Route.by_id(trip.route_id) do - nil -> - %{route: trip.route_id, direction_id: trip.direction_id} - - route -> - %{ - route: route.id, - route_type: route.type, - direction_id: trip.direction_id - } - end - - Map.merge(entity, merge) - end - - with {:ok, route_id} <- Map.fetch(entity, :route), - false <- Enum.any?(trips, &(&1.route_id == route_id)) do - # if the route in the alert doesn't match the routes we have for the - # trip, keep the original entity - [entity | trip_entities] - else - _ -> - # otherwise, ignore the original entity - trip_entities - end - end -end From 163249344ef1c01e02ae3f1a6ca5c07f20f82be6 Mon Sep 17 00:00:00 2001 From: Allison King Date: Mon, 6 Jul 2026 16:52:08 -0400 Subject: [PATCH 2/3] Update tests --- apps/state/test/state/alert/hooks_test.exs | 552 --------------------- apps/state/test/state/alert_test.exs | 8 +- 2 files changed, 7 insertions(+), 553 deletions(-) delete mode 100644 apps/state/test/state/alert/hooks_test.exs diff --git a/apps/state/test/state/alert/hooks_test.exs b/apps/state/test/state/alert/hooks_test.exs deleted file mode 100644 index cdb3544ac..000000000 --- a/apps/state/test/state/alert/hooks_test.exs +++ /dev/null @@ -1,552 +0,0 @@ -defmodule State.Alert.HooksTest do - @moduledoc false - use ExUnit.Case - import State.Alert.Hooks - alias Model.Alert - - setup do - State.Stop.new_state([]) - State.Trip.new_state([]) - State.Route.new_state([]) - :ok - end - - @type hook_result :: %{ - added: [Alert.informed_entity()], - removed: [Alert.informed_entity()], - preserved: [Alert.informed_entity()] - } - - @spec apply_hook([Alert.informed_entity()]) :: hook_result - @spec apply_hook(Alert.t()) :: hook_result - defp apply_hook(informed_entities) when is_list(informed_entities) do - apply_hook(%Alert{id: "alert1", informed_entity: informed_entities}) - end - - defp apply_hook(%Alert{} = alert) do - assert [%Alert{informed_entity: new_informed_entities}] = pre_insert_hook(alert) - - old = MapSet.new(alert.informed_entity) - new = MapSet.new(new_informed_entities) - - [ - added: MapSet.difference(new, old), - removed: MapSet.difference(old, new), - preserved: MapSet.intersection(old, new) - ] - |> Map.new(fn {k, ies} -> {k, normalize(ies)} end) - end - - defp normalize(ies) do - ies - |> Enum.map(fn ie -> Map.replace_lazy(ie, :activities, &Enum.sort/1) end) - |> Enum.sort() - end - - describe "pre_insert_hook/1" do - test "adds informed entities for parent stations" do - State.Stop.new_state([ - %Model.Stop{id: "child-stop1", parent_station: "parent-stationA"}, - %Model.Stop{id: "child-stop2", parent_station: "parent-stationB"}, - %Model.Stop{id: "child-stop3", parent_station: "parent-stationB"}, - %Model.Stop{id: "parentless-stop"} - ]) - - informed_entities = - [ - %{stop: "child-stop1"}, - %{stop: "child-stop2"}, - %{stop: "child-stop3"}, - %{stop: "parentless-stop"} - ] - |> normalize() - - assert %{ - preserved: ^informed_entities, - added: [%{stop: "parent-stationA"}, %{stop: "parent-stationB"}] - } = apply_hook(informed_entities) - end - - test "merges child informed entities' activities for parent station informed entities," <> - " and does *not* merge activities for pre-existing child stop informed entities" do - State.Stop.new_state([ - %Model.Stop{id: "child-stop1", parent_station: "parent-stationA"}, - %Model.Stop{id: "child-stop2", parent_station: "parent-stationA"}, - %Model.Stop{id: "child-stop3", parent_station: "parent-stationB"}, - %Model.Stop{id: "child-stop4", parent_station: "parent-stationB"}, - %Model.Stop{id: "child-stop5", parent_station: "parent-stationC"}, - %Model.Stop{id: "parentless-stop"} - ]) - - informed_entities = - [ - %{ - stop: "child-stop1", - route: "route1", - activities: ["BOARD", "EXIT", "USING_WHEELCHAIR"] - }, - %{stop: "child-stop1", route: "route2", activities: ["BOARD"]}, - %{stop: "child-stop2", route: "route1", activities: ["BOARD", "EXIT", "RIDE"]}, - %{stop: "child-stop3", activities: ["BOARD"], route: "route1", trip: "trip1"}, - %{stop: "child-stop4", activities: ["EXIT"], route: "route1", trip: "trip1"}, - %{stop: "child-stop4", activities: ["RIDE"], route: "route1", trip: "trip2"}, - %{stop: "child-stop4", activities: ["RIDE"], route: "route2", trip: "trip1"}, - %{stop: "child-stop5", activities: ["USING_ESCALATOR"]}, - %{stop: "parentless-stop", activities: ["BRINGING_BIKE", "STORE_BIKE"]} - ] - |> normalize() - - assert %{ - preserved: ^informed_entities, - added: [ - %{stop: "parent-stationC", activities: ["USING_ESCALATOR"]}, - %{stop: "parent-stationA", route: "route2", activities: ["BOARD"]}, - %{ - stop: "parent-stationA", - route: "route1", - activities: ["BOARD", "EXIT", "RIDE", "USING_WHEELCHAIR"] - }, - %{ - stop: "parent-stationB", - activities: ["BOARD", "EXIT"], - route: "route1", - trip: "trip1" - }, - %{stop: "parent-stationB", activities: ["RIDE"], route: "route1", trip: "trip2"}, - %{stop: "parent-stationB", activities: ["RIDE"], route: "route2", trip: "trip1"} - ] - } = apply_hook(informed_entities) - end - - test "adds informed entities for alternate trips" do - State.Trip.new_state([ - %Model.Trip{id: "trip1", alternate_route: false, route_id: "main-route"}, - %Model.Trip{id: "trip1", alternate_route: true, route_id: "alt-route1"}, - %Model.Trip{id: "trip1", alternate_route: true, route_id: "alt-route2"}, - %Model.Trip{id: "trip1", alternate_route: true, route_id: "alt-routeX", direction_id: 1} - ]) - - State.Route.new_state([ - %Model.Route{id: "main-route", type: 3}, - %Model.Route{id: "alt-route1", type: 3}, - %Model.Route{id: "alt-route2", type: 3} - ]) - - informed_entities = - [ - %{ - stop: "bus-stop1", - trip: "trip1", - route: "main-route", - direction_id: 0, - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "bus-stop2", - trip: "trip1", - route: "a-different-route", - direction_id: 0, - activities: ["BOARD"] - }, - %{stop: "bus-stop3", trip: "trip2", direction_id: 1} - ] - |> normalize() - - assert %{ - preserved: [ - %{stop: "bus-stop3", trip: "trip2", direction_id: 1}, - %{ - stop: "bus-stop2", - trip: "trip1", - route: "a-different-route", - direction_id: 0, - activities: ["BOARD"] - } - ], - added: [ - %{ - stop: "bus-stop2", - trip: "trip1", - route: "alt-routeX", - direction_id: 1, - activities: ["BOARD"] - }, - %{ - stop: "bus-stop1", - trip: "trip1", - route: "alt-routeX", - direction_id: 1, - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "bus-stop2", - route: "alt-route1", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD"] - }, - %{ - stop: "bus-stop2", - route: "alt-route2", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD"] - }, - %{ - stop: "bus-stop2", - route: "main-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD"] - }, - %{ - stop: "bus-stop1", - route: "alt-route1", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "bus-stop1", - route: "alt-route2", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "bus-stop1", - route: "main-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT"] - } - ], - removed: [ - %{ - stop: "bus-stop1", - trip: "trip1", - route: "main-route", - direction_id: 0, - activities: ["BOARD", "EXIT"] - } - ] - } = apply_hook(informed_entities) - end - - test "adds Cartesian product of computed informed entities for parent stations X alternate trips" do - State.Stop.new_state([ - %Model.Stop{id: "busway-berth1", parent_station: "parent-stationA"}, - %Model.Stop{id: "busway-berth2", parent_station: "parent-stationA"} - ]) - - State.Trip.new_state([ - %Model.Trip{id: "trip1", alternate_route: false, route_id: "main-route"}, - %Model.Trip{id: "trip1", alternate_route: true, route_id: "alt-route"} - ]) - - State.Route.new_state([ - %Model.Route{id: "main-route", type: 3}, - %Model.Route{id: "alt-route", type: 3} - ]) - - informed_entities = - [ - %{ - stop: "busway-berth1", - trip: "trip1", - route: "main-route", - direction_id: 0, - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "busway-berth2", - trip: "trip1", - route: "main-route", - direction_id: 0, - activities: ["BOARD", "USING_WHEELCHAIR"] - } - ] - |> normalize() - - assert %{ - preserved: [], - added: [ - %{ - stop: "busway-berth1", - route: "alt-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "busway-berth1", - route: "main-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "parent-stationA", - route: "alt-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT", "USING_WHEELCHAIR"] - }, - %{ - stop: "parent-stationA", - route: "main-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "EXIT", "USING_WHEELCHAIR"] - }, - %{ - stop: "busway-berth2", - route: "alt-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "USING_WHEELCHAIR"] - }, - %{ - stop: "busway-berth2", - route: "main-route", - direction_id: nil, - route_type: 3, - trip: "trip1", - activities: ["BOARD", "USING_WHEELCHAIR"] - } - ], - removed: [ - %{ - stop: "busway-berth1", - route: "main-route", - direction_id: 0, - trip: "trip1", - activities: ["BOARD", "EXIT"] - }, - %{ - stop: "busway-berth2", - route: "main-route", - direction_id: 0, - trip: "trip1", - activities: ["BOARD", "USING_WHEELCHAIR"] - } - ] - } = apply_hook(informed_entities) - end - - test "handles specific case from bugfix ticket" do - # https://app.asana.com/1/15492006741476/project/584764604969369/task/1213450825693783?focus=true - - State.Stop.new_state([ - %Model.Stop{id: "BNT-0000", parent_station: "place-north"}, - %Model.Stop{id: "WR-0045-S", parent_station: "place-mlmnl"}, - %Model.Stop{id: "WR-0053-S", parent_station: "place-ogmnl"} - ]) - - assert [alert] = Parse.Alerts.parse(alerts_enhanced_json_excerpt()) - - informed_entities = normalize(alert.informed_entity) - - expected_new_informed_entities = - [ - %{ - stop: "place-mlmnl", - activities: ["BOARD", "EXIT", "RIDE"], - route: "CR-Haverhill", - direction_id: 1, - route_type: 2 - }, - %{ - stop: "place-mlmnl", - activities: ["BOARD", "EXIT", "RIDE"], - route: "CR-Haverhill", - direction_id: 0, - route_type: 2 - }, - %{ - stop: "place-north", - activities: ["BOARD", "EXIT", "RIDE"], - route: "CR-Haverhill", - direction_id: 1, - route_type: 2 - }, - %{ - stop: "place-north", - activities: ["BOARD", "EXIT", "RIDE"], - route: "CR-Haverhill", - direction_id: 0, - route_type: 2 - }, - %{ - stop: "place-ogmnl", - activities: ["BOARD", "EXIT", "RIDE"], - route: "CR-Haverhill", - direction_id: 1, - route_type: 2 - }, - %{ - stop: "place-ogmnl", - activities: ["BOARD", "EXIT", "RIDE"], - route: "CR-Haverhill", - direction_id: 0, - route_type: 2 - } - ] - |> normalize() - - assert %{ - preserved: ^informed_entities, - added: ^expected_new_informed_entities - } = apply_hook(alert) - end - end - - defp alerts_enhanced_json_excerpt do - ~S""" - { - "entity": [ - { - "id": "1000217", - "alert": { - "cause": "UNKNOWN_CAUSE", - "effect": "REDUCED_SERVICE", - "severity": 7, - "active_period": [ - { - "start": 1772415300, - "end": 1772697600 - } - ], - "duration_certainty": "KNOWN", - "cause_detail": { - "translation": [ - { - "text": "UNKNOWN_CAUSE", - "language": "en" - } - ] - }, - "effect_detail": { - "translation": [ - { - "text": "SUSPENSION", - "language": "en" - } - ] - }, - "informed_entity": [ - { - "direction_id": 1, - "stop_id": "BNT-0000", - "route_id": "CR-Haverhill", - "route_type": 2, - "agency_id": "1", - "activities": [ - "EXIT", - "RIDE" - ] - }, - { - "direction_id": 1, - "stop_id": "WR-0045-S", - "route_id": "CR-Haverhill", - "route_type": 2, - "agency_id": "1", - "activities": [ - "BOARD", - "EXIT", - "RIDE" - ] - }, - { - "direction_id": 1, - "stop_id": "WR-0053-S", - "route_id": "CR-Haverhill", - "route_type": 2, - "agency_id": "1", - "activities": [ - "BOARD", - "RIDE" - ] - }, - { - "direction_id": 0, - "stop_id": "BNT-0000", - "route_id": "CR-Haverhill", - "route_type": 2, - "agency_id": "1", - "activities": [ - "BOARD", - "RIDE" - ] - }, - { - "direction_id": 0, - "stop_id": "WR-0045-S", - "route_id": "CR-Haverhill", - "route_type": 2, - "agency_id": "1", - "activities": [ - "BOARD", - "EXIT", - "RIDE" - ] - }, - { - "direction_id": 0, - "stop_id": "WR-0053-S", - "route_id": "CR-Haverhill", - "route_type": 2, - "agency_id": "1", - "activities": [ - "EXIT", - "RIDE" - ] - } - ], - "last_modified_timestamp": 1772415513, - "severity_level": "SEVERE", - "header_text": { - "translation": [ - { - "text": "Haverhill Line: service suspended between North Station and Oak Grove today.", - "language": "en" - } - ] - }, - "description_text": { - "translation": [ - { - "text": "Affected stations:\r\nNorth Station\r\nMalden Center\r\nOak Grove", - "language": "en" - } - ] - }, - "service_effect_text": { - "translation": [ - { - "text": "Suspension of service on Haverhill Line", - "language": "en" - } - ] - }, - "created_timestamp": 1772415356, - "alert_lifecycle": "NEW" - } - } - ] - } - """ - end -end diff --git a/apps/state/test/state/alert_test.exs b/apps/state/test/state/alert_test.exs index 4bb2f3842..38ca22af8 100644 --- a/apps/state/test/state/alert_test.exs +++ b/apps/state/test/state/alert_test.exs @@ -178,7 +178,13 @@ defmodule State.AlertTest do alert = put_in(@alert.informed_entity, [ - %{activities: ["BOARD"], trip: "trip"} + %{ + activities: ["BOARD"], + trip: trip, + route: route.id, + route_type: route.type, + direction_id: 1 + } ]) insert_alerts!([alert]) From cd5805718f61d3c3abe718794d5a4259601a3d55 Mon Sep 17 00:00:00 2001 From: Allison King Date: Tue, 7 Jul 2026 10:45:34 -0400 Subject: [PATCH 3/3] Remove alternate trip and parent entities tests --- apps/state/test/state/alert_test.exs | 199 +-------------------------- 1 file changed, 1 insertion(+), 198 deletions(-) diff --git a/apps/state/test/state/alert_test.exs b/apps/state/test/state/alert_test.exs index 38ca22af8..1ac91b824 100644 --- a/apps/state/test/state/alert_test.exs +++ b/apps/state/test/state/alert_test.exs @@ -3,7 +3,6 @@ defmodule State.AlertTest do alias Parse.Time alias State.Alert.{InformedEntity, InformedEntityActivity} - alias State.{Service, Trip} import State.Alert @@ -20,12 +19,7 @@ defmodule State.AlertTest do service_id: @service_id } @today Time.service_date() - @service %Model.Service{ - id: @service_id, - start_date: @today, - end_date: @today, - added_dates: [@today] - } + @alert %Model.Alert{ id: @alert_id, informed_entity: [ @@ -413,195 +407,4 @@ defmodule State.AlertTest do assert_receive :done, 200 end end - - describe "alternate trip entities" do - setup :service_by_date - - test "updates entities to include alternate routes" do - added_route_id = "added_route_id" - - Trip.new_state(%{ - multi_route_trips: [ - %Model.MultiRouteTrip{added_route_id: added_route_id, trip_id: @trip_id} - ], - trips: [@trip] - }) - - input_informed_entity = %{direction_id: 1, route: @route_id, route_type: 3, trip: @trip_id} - - new_state([%Model.Alert{id: @alert_id, informed_entity: [input_informed_entity]}]) - - %Model.Alert{informed_entity: output_informed_entity} = by_id(@alert_id) - - assert length(output_informed_entity) == 2 - - assert %{direction_id: 1, route: @route_id, route_type: 3, trip: @trip_id} in output_informed_entity - - assert %{direction_id: 1, route: added_route_id, route_type: 3, trip: @trip_id} in output_informed_entity - end - - test "does not set `route` if no alternate routes" do - Trip.new_state(%{multi_route_trips: [], trips: [@trip]}) - informed_entity = [%{direction_id: 1, route: @route_id, route_type: 3, trip: @trip_id}] - new_state([%Model.Alert{id: @alert_id, informed_entity: informed_entity}]) - - alert = by_id(@alert_id) - - assert alert.informed_entity == informed_entity - end - - test "returns original entity if `trip` is not found" do - informed_entity = [%{trip: "unknown"}] - new_state([%Model.Alert{id: @alert_id, informed_entity: informed_entity}]) - alert = by_id(@alert_id) - - assert alert.informed_entity == informed_entity - end - - test "includes original route if `trip` does not have route" do - added_route_id = "added_route_id" - - Trip.new_state(%{ - multi_route_trips: [ - %Model.MultiRouteTrip{added_route_id: added_route_id, trip_id: @trip_id} - ], - trips: [@trip] - }) - - other_route_id = "other_route_id" - - input_informed_entity = %{ - direction_id: 1, - route: other_route_id, - route_type: 3, - trip: @trip_id - } - - new_state([%Model.Alert{id: @alert_id, informed_entity: [input_informed_entity]}]) - - %Model.Alert{informed_entity: output_informed_entity} = by_id(@alert_id) - - assert length(output_informed_entity) == 3 - - assert %{direction_id: 1, route: @route_id, route_type: 3, trip: @trip_id} in output_informed_entity - - assert %{direction_id: 1, route: other_route_id, route_type: 3, trip: @trip_id} in output_informed_entity - - assert %{direction_id: 1, route: added_route_id, route_type: 3, trip: @trip_id} in output_informed_entity - end - - test "only includes alternate routes once if incoming informed entities already contain alternate route" do - added_by_upstream_route_id = "added_by_upstream_route_id" - added_by_multi_route_trips_route_id = "added_by_multi_route_trips_route_id" - - Trip.new_state(%{ - multi_route_trips: [ - %Model.MultiRouteTrip{added_route_id: added_by_upstream_route_id, trip_id: @trip_id}, - %Model.MultiRouteTrip{ - added_route_id: added_by_multi_route_trips_route_id, - trip_id: @trip_id - } - ], - trips: [@trip] - }) - - primary_upstream_informed_entity = %{ - direction_id: 1, - route: @route_id, - route_type: 3, - trip: @trip_id - } - - alternate_upstream_informed_entity = %{ - primary_upstream_informed_entity - | route: added_by_upstream_route_id - } - - new_state([ - %Model.Alert{ - id: @alert_id, - informed_entity: [primary_upstream_informed_entity, alternate_upstream_informed_entity] - } - ]) - - %Model.Alert{informed_entity: informed_entities} = by_id(@alert_id) - - assert length(informed_entities) == 3 - - assert primary_upstream_informed_entity in informed_entities - assert alternate_upstream_informed_entity in informed_entities - - added_entity = %{ - direction_id: 1, - route: added_by_multi_route_trips_route_id, - route_type: 3, - trip: @trip_id - } - - assert added_entity in informed_entities - end - - test "includes route/route type/direction in the entity if not already present" do - route = %Model.Route{ - id: @route_id, - type: 3 - } - - State.Route.new_state([route]) - State.Trip.new_state([@trip]) - entity = %{trip: @trip_id} - alert = %Model.Alert{id: @alert_id, informed_entity: [entity]} - State.Alert.new_state([alert]) - - alert = by_id(@alert_id) - - expected_entity = %{ - route_type: 3, - route: @route_id, - direction_id: @trip.direction_id, - trip: @trip_id - } - - assert expected_entity in alert.informed_entity - assert length(alert.informed_entity) == 1 - end - end - - describe "parent station entity" do - test "updates entities to include the parent station" do - State.Stop.new_state([ - %Model.Stop{id: "child", parent_station: "parent"}, - %Model.Stop{id: "parent"} - ]) - - new_state([ - %Model.Alert{id: @alert_id, informed_entity: [%{stop: "child"}]} - ]) - - alert = by_id(@alert_id) - assert %{stop: "child"} in alert.informed_entity - assert %{stop: "parent"} in alert.informed_entity - end - - test "does not include parent station entities twice" do - State.Stop.new_state([ - %Model.Stop{id: "child", parent_station: "parent"}, - %Model.Stop{id: "parent"} - ]) - - new_state([ - %Model.Alert{id: @alert_id, informed_entity: [%{stop: "child"}, %{stop: "parent"}]} - ]) - - alert = by_id(@alert_id) - assert [_, _] = alert.informed_entity - end - end - - defp service_by_date(_) do - # Reset received keys - Trip.reset_gather() - - Service.new_state([@service]) - end end