Helpers for a test suite that loads fixtures or bulk data into tables Trellis captures. Call them from test code only.
A fixture loader that disables triggers for the load (Rails-style
disable_referential_integrity, pg_restore --disable-triggers, a
hand-written ALTER TABLE ... DISABLE TRIGGER ALL) also disables
Trellis's capture triggers, so the rows it writes never reach a target,
and ENABLE TRIGGER ALL leaves them in a mode the staging worker treats
as a disruption of capture. Trellis then pauses every definition that
reads the table (a Trellis.CaptureFailure of kind :disruption on its
status) rather than let a test read targets that are silently wrong. A
test suite's answer is a RESUME after the load, which rebuilds the
targets from the tables as they are now: resume_capture_disruptions/2.
setup do
Postgrex.query!(pg, "ALTER TABLE orders DISABLE TRIGGER ALL", [])
# ... load the fixtures ...
Postgrex.query!(pg, "ALTER TABLE orders ENABLE TRIGGER ALL", [])
{:ok, _resumed} = Trellis.TestSupport.resume_capture_disruptions(trellis)
:ok
endIt is cheap when nothing was disrupted (one catalog read per captured
table), so running it in every test's setup is fine.
Ecto's SQL sandbox
Trellis sees a write when it commits. A test that writes inside a sandbox
transaction (the default :manual or :shared mode) rolls it back, so
nothing reaches a target. Load the fixtures that targets must reflect
outside the sandbox (in setup_all, or with the sandbox in :auto mode),
then call the helper once.
Summary
Functions
Resumes every definition of trellis that is paused because Trellis's
capture of a table it reads was changed outside Trellis, waits until each
is :live again, then waits until every write committed so far has
reached its targets (Trellis.await_converged/3), so a test that follows
reads exact targets. Returns {:ok, resumed} with the resumed targets
("schema.table"; [] when nothing was disrupted).
Like resume_capture_disruptions/2, but returns the resumed targets and
raises Trellis.Error, or Trellis.TestSupport.ResumeRefused when a
resume is refused.
Functions
@spec resume_capture_disruptions(Trellis.trellis(), [{:timeout_ms, non_neg_integer()}]) :: {:ok, [String.t()]} | {:error, {:resume_refused, %{required(String.t()) => String.t()}}} | {:error, Trellis.Error.t()}
Resumes every definition of trellis that is paused because Trellis's
capture of a table it reads was changed outside Trellis, waits until each
is :live again, then waits until every write committed so far has
reached its targets (Trellis.await_converged/3), so a test that follows
reads exact targets. Returns {:ok, resumed} with the resumed targets
("schema.table"; [] when nothing was disrupted).
It runs a disruption check of its own first
(Trellis.detect_capture_disruptions/1), so a disruption the staging
worker has not seen yet is paused and resumed here rather than a pass
later.
It resumes only a Trellis.CaptureFailure of kind :disruption. A
definition an operator paused (PAUSE TRANSFORM), or one paused by a
schema change, a drain halt or a failing build, stays paused. A definition
paused because an upstream one was resumes with its upstream.
A RESUME the engine refuses (for example, the table a definition read is
missing, or a table define would now refuse) leaves that definition
paused. The others are still resumed and waited for; then
{:error, {:resume_refused, refused}} is returned, refused mapping each
target to the reason. Any other engine error, or a definition that is not
:live within :timeout_ms (default 30 000; a :timeout error), is
{:error, %Trellis.Error{}}.
The instance needs its staging worker and a drain worker running somewhere
(a test setup usually connects with staging: true, drain_threads: 1):
resuming rebuilds through them.
@spec resume_capture_disruptions!(Trellis.trellis(), [ {:timeout_ms, non_neg_integer()} ]) :: [String.t()]
Like resume_capture_disruptions/2, but returns the resumed targets and
raises Trellis.Error, or Trellis.TestSupport.ResumeRefused when a
resume is refused.