Trellis.TestSupport (Trellis v0.1.0-alpha)

Copy Markdown View Source

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
end

It 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

resume_capture_disruptions(trellis, opts \\ [])

@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.

resume_capture_disruptions!(trellis, opts \\ [])

@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.