defmodule RoomGtfs.DifferentialFeedTest do
@moduledoc """
Holding a differential feed open.
GTFS-RT publishes in two modes that mean opposite things by the same message.
A full dataset is a snapshot and replaces what was held. A differential feed
is a stream of edits: each message carries only what changed, keyed by entity
id, and `is_deleted` means drop it. Replacing on every poll -- correct for the
first -- silently discards everything the newest delta did not restate.
"""
use ExUnit.Case, async: true
alias RoomGtfs.Worker.RT
alias TransitRealtime, as: T
defp feed(entities, incrementality) do
%T.FeedMessage{
header: %T.FeedHeader{gtfs_realtime_version: "2.0", incrementality: incrementality},
entity: entities
}
end
defp full(entities), do: feed(entities, :FULL_DATASET)
defp delta(entities), do: feed(entities, :DIFFERENTIAL)
# The label rides along on the trip id so an updated entity is telling apart
# from the one it replaced.
defp vehicle(id, label \\ "a") do
%T.FeedEntity{
id: id,
vehicle: %T.VehiclePosition{trip: %T.TripDescriptor{trip_id: label}}
}
end
defp deletion(id), do: %T.FeedEntity{id: id, is_deleted: true}
defp ids(feed), do: Enum.map(feed.entity, & &1.id)
defp label(feed, id), do: Enum.find(feed.entity, &(&1.id == id)).vehicle.trip.trip_id
describe "a full dataset" do
test "replaces whatever was held" do
held = full([vehicle("a"), vehicle("b")])
assert RT.merge_feed(held, full([vehicle("c")])) |> ids() == ["c"]
end
test "replaces a differential history too, because it is the whole truth" do
held = delta([vehicle("a"), vehicle("b")])
assert RT.merge_feed(held, full([vehicle("c")])) |> ids() == ["c"]
end
end
describe "a differential message" do
test "adds to what is held rather than replacing it" do
held = delta([vehicle("a"), vehicle("b")])
assert RT.merge_feed(held, delta([vehicle("c")])) |> ids() == ["a", "b", "c"]
end
test "updates an entity in place, keeping its position" do
held = delta([vehicle("a", "old"), vehicle("b", "old")])
merged = RT.merge_feed(held, delta([vehicle("a", "new")]))
assert ids(merged) == ["a", "b"]
assert label(merged, "a") == "new"
assert label(merged, "b") == "old"
end
test "a deletion drops the entity" do
held = delta([vehicle("a"), vehicle("b"), vehicle("c")])
assert RT.merge_feed(held, delta([deletion("b")])) |> ids() == ["a", "c"]
end
test "deletions are not themselves kept as entities" do
merged = RT.merge_feed(delta([vehicle("a")]), delta([deletion("z")]))
assert ids(merged) == ["a"]
end
test "nothing changed is not the feed emptying itself" do
held = delta([vehicle("a"), vehicle("b")])
assert RT.merge_feed(held, delta([])) |> ids() == ["a", "b"]
end
test "the newest header wins, so freshness is the delta's" do
held = delta([vehicle("a")])
incoming = %{delta([]) | header: %T.FeedHeader{gtfs_realtime_version: "2.0", timestamp: 99}}
assert RT.merge_feed(held, incoming).header.timestamp == 99
end
end
describe "within one message" do
test "the last word wins for a repeated entity" do
merged = RT.merge_feed(delta([]), delta([vehicle("a", "first"), vehicle("a", "second")]))
assert label(merged, "a") == "second"
end
test "deleted and then sent again means sent" do
held = delta([vehicle("a", "old")])
merged = RT.merge_feed(held, delta([deletion("a"), vehicle("a", "back")]))
assert ids(merged) == ["a"]
assert label(merged, "a") == "back"
end
test "sent and then deleted means deleted" do
merged = RT.merge_feed(delta([]), delta([vehicle("a"), deletion("a")]))
assert ids(merged) == []
end
end
describe "nothing held yet" do
test "the first delta is applied to an empty feed" do
assert RT.merge_feed(nil, delta([vehicle("a")])) |> ids() == ["a"]
end
test "a first delta deleting something it never sent drops it" do
assert RT.merge_feed(nil, delta([vehicle("a"), deletion("b")])) |> ids() == ["a"]
end
test "a first full dataset is simply the feed" do
assert RT.merge_feed(nil, full([vehicle("a")])) |> ids() == ["a"]
end
end
test "several polls accumulate the way the feed intends" do
merged =
nil
|> RT.merge_feed(delta([vehicle("a"), vehicle("b")]))
|> RT.merge_feed(delta([vehicle("c")]))
|> RT.merge_feed(delta([deletion("a"), vehicle("b", "moved")]))
|> RT.merge_feed(delta([]))
assert ids(merged) == ["b", "c"]
assert label(merged, "b") == "moved"
end
end
neiam
/apollos_crib
It's Apollo's Crib
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions failure · Badges · Packages
⭐
Log in to mark this repository.
4.6 KiB · text
History
4eee00d