The feed conformance kit: the contract of spec/08 §10–§11 as checks every provider runs (spec/08 §12, D-145).
check/3 runs one of six checks against a feed and answers its findings,
{check, reason} terms, [] for a feed that passes; check/2 runs them all and
format/1 words a finding. use Visualize.Feed.Conformance, opts inside a module that
uses ExUnit.Case writes one test per check that fails with the findings:
defmodule MyApp.FeedTest do
use ExUnit.Case, async: true
use Visualize.Feed.Conformance,
feed: MyApp.Feed.new(),
windows: [nil, [10, 20]],
push: &MyApp.Feed.emit/1
endThe kit drives the feed through Visualize.Feed alone and calls every callback in a
process of its own, so a callback that raises is a finding ({:raised, call, reason}),
not a crash of the check. It references no ExUnit function itself: describe, test
and flunk appear only in the code use writes into the caller's module. A callback
is judged by the reductions its process spends, never by the clock, so a loaded host
changes no verdict (#852, D-221).
Options
feed:— the feed (touse: an expression, evaluated in each test).windows:— the windows fetched,[nil]by default; a feed naming:windowneeds one with a bound.budgets:— the budgets each window is fetched with,[nil, 5].push:— a function of the feed that makes it push; a feed naming:pushneeds one.down:— a feed of the same provider that cannot answer, held to error values.timeout:— the liveness bound: milliseconds before a callback that has not answered is hung — blocked, not slow — and the wait for a first push (30_000).reductions:— the most reductions one callback may spend, the feed author's cost budget;nil, the default, makes no cost claim.processes:— pids or registered names whose reductions during a callback count toward its budget, for a feed that does its work in a server ([]).quiet:— milliseconds of silence that end a push (100).name:— touseonly: thedescribeblock's name,"feed conformance".
Examples
iex> signal = Visualize.Signals.new(:discrete, [:t, :n], window: 3)
iex> feed = Visualize.Feed.Signals.new(signal, tick: 10)
iex> Visualize.Feed.Conformance.check(feed, windows: [nil, [2, 6]])
[]
Summary
Functions
One ExUnit test per check, in a describe block, written into a module that uses
ExUnit.Case (spec/08 §12.1). feed: and down: are expressions evaluated in each
test, in the test process.
Every check's findings for a feed, concatenated in the order of checks/0.
One check's findings for a feed, [] when it passes (spec/08 §12.3). Raises
ArgumentError for an unknown check or option.
One finding as a line a person reads.
Types
Functions
One ExUnit test per check, in a describe block, written into a module that uses
ExUnit.Case (spec/08 §12.1). feed: and down: are expressions evaluated in each
test, in the test process.
@spec check(Visualize.Feed.t(), keyword()) :: [finding()]
Every check's findings for a feed, concatenated in the order of checks/0.
@spec check(check(), Visualize.Feed.t(), keyword()) :: [finding()]
One check's findings for a feed, [] when it passes (spec/08 §12.3). Raises
ArgumentError for an unknown check or option.
@spec checks() :: [check(), ...]
The six checks, in the order check/2 runs them.
One finding as a line a person reads.
iex> Visualize.Feed.Conformance.format({:supports, {:over_budget, {nil, 5}, 9}})
"supports: asked for at most 5 rows (window nil), the feed names :budget and served 9"