Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions test/distributed_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5717,16 +5717,21 @@ defmodule Group.DistributedTest do
:ok = TestCluster.rpc!(node_a, Group, :disconnect, [name, "tenant/transient"])
:ok = TestCluster.rpc!(node_a, Group, :connect, [name, "tenant/after-close"])

{:messages, queued_messages} =
TestCluster.rpc!(node_b, Process, :info, [receiver, :messages])
queued_controls = fn ->
{:messages, queued_messages} =
TestCluster.rpc!(node_b, Process, :info, [receiver, :messages])

queued_controls =
for {kind, remote_pid, _generation, revision, _epochs} <- queued_messages,
kind in [:replica_cluster_open, :replica_cluster_close],
node(remote_pid) == node_a,
do: {kind, revision}
end

# Local connect completion does not order a separate RPC to the receiver
# after delivery of the sender's distribution messages.
TestCluster.assert_eventually(fn -> length(queued_controls.()) == 3 end)

assert queued_controls == [
assert queued_controls.() == [
{:replica_cluster_open, 33},
{:replica_cluster_close, 34},
{:replica_cluster_open, 35}
Expand Down
8 changes: 5 additions & 3 deletions test/mutation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ and runs the designated real multi-node regression. A compiling mutant is
`killed` only when the regression fails. Any surviving or non-compiling mutant
makes the campaign fail.
Before either listing or running mutants, it also requires every production
replacement to match exactly once and every test selector to point at the test
declaration itself. Source edits therefore fail loudly instead of turning a
stale mutation into a placebo run of an adjacent test.
replacement to match exactly once. Test selectors pair a file with a literal
test/property name, resolved to its current declaration line before execution.
Moving a test requires no selector update; missing or ambiguous names fail
instead of turning a stale mutation into a placebo run of an adjacent test.
The local PR gate validates all definitions without running the campaign.

```bash
mix run --no-start test/mutation/run.exs
Expand Down
45 changes: 41 additions & 4 deletions test/mutation/isolation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule Group.MutationIsolationTest do

@repo Path.expand("../..", __DIR__)
@mutation "drain_oversized_ingress_batch_without_yield"
@target "an oversized incoming batch yields to an already queued local write"

setup do
work = Path.join(@repo, "tmp/mutation-isolation-#{System.unique_integer([:positive])}")
Expand Down Expand Up @@ -71,7 +72,7 @@ defmodule Group.MutationIsolationTest do
assert output =~ "#{@mutation}: SURVIVED"
refute File.exists?(Path.join(work, "checker-invocations"))

{output, status} = command(work, ["mix", "test", "test/group_test.exs:34"])
{output, status} = command(work, ["mix", "test", "test/group_test.exs"])
assert status != 0, output
assert File.read!(Path.join(work, "checker-invocations")) == "invoked\n"
end
Expand Down Expand Up @@ -108,13 +109,49 @@ defmodule Group.MutationIsolationTest do
refute output =~ "#{@mutation}: killed"
end

test "selectors follow a moved declaration without running adjacent tests", %{work: work} do
target(work, "assert Isolation.Target.split([1, 2]) == {[1], [2]}")
path = Path.join(work, "test/group_test.exs")

File.write!(
path,
String.replace(
File.read!(path),
" use ExUnit.Case\n",
" use ExUnit.Case\n\n test \"not the target\", do: flunk(\"must not be selected\")\n\n"
)
)

{output, status} = campaign(work)
assert status == 0, output
assert output =~ "#{@mutation}: killed"
end

test "missing and ambiguous names fail before running a baseline", %{work: work} do
for {name, copies, count} <- [{"renamed target", 1, 0}, {@target, 2, 2}] do
declarations = String.duplicate(" test #{inspect(name)}, do: assert(true)\n", copies)
write(work, "test/group_test.exs", "defmodule TargetTest do\n#{declarations}end\n")

{output, status} = campaign(work)
assert status != 0, output
assert output =~ "must match exactly one test/property declaration"
assert output =~ "(found #{count})"
refute output =~ "baseline "
end
end

defp target(work, assertion) do
write(
work,
"test/group_test.exs",
"defmodule Isolation.TargetTest do\n use ExUnit.Case\n" <>
String.duplicate("\n", 31) <>
" test \"target\" do\n #{assertion}\n end\nend\n"
"""
defmodule Isolation.TargetTest do
use ExUnit.Case
test #{inspect(@target)} do
#{assertion}
end
end
"""
)
end

Expand Down
Loading