From dfcde7943f91f4e2a56661bcbbaa169d19a4dd58 Mon Sep 17 00:00:00 2001 From: Carter Pedersen Date: Wed, 18 Feb 2026 12:11:01 -0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Clean=20up=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Goal here is to reduce flakiness and remove extraneous log messages --- config/test.exs | 6 +- lib/sequin/application.ex | 2 +- .../message_consistency_check_worker.ex | 8 +- mix.exs | 7 +- test/sequin/gcp_pubsub_pipeline_test.exs | 85 ++++++++++--------- .../message_consistency_check_worker_test.exs | 33 +++---- test/sequin/message_handler_test.exs | 4 +- .../sequin/postgres/benchmark_source_test.exs | 2 +- test/sequin/postgres_replication_test.exs | 16 ++++ test/sequin/postgres_test.exs | 2 + .../slot_producer/integration_test.exs | 1 + .../slot_producer/reorder_buffer_test.exs | 2 + .../slot_producer/slot_producer_test.exs | 1 + test/sequin/slot_message_store_state_test.exs | 2 + test/sequin/table_reader_server_test.exs | 2 + test/sequin/table_reader_test.exs | 6 ++ test/sequin/yaml_loader_test.exs | 28 +++--- .../controllers/pull_controller_test.exs | 2 +- test/test_helper.exs | 40 +++++++++ 19 files changed, 171 insertions(+), 78 deletions(-) diff --git a/config/test.exs b/config/test.exs index 410da089e..f3db2d5f6 100644 --- a/config/test.exs +++ b/config/test.exs @@ -41,10 +41,10 @@ config :sequin, Sequin.Repo, hostname: "localhost", database: "sequin_test", pool: Ecto.Adapters.SQL.Sandbox, - pool_size: 20, + pool_size: 40, port: 5432, - queue_target: 100, - queue_interval: 1000, + queue_target: 500, + queue_interval: 2000, ssl: false, types: PostgrexTypes diff --git a/lib/sequin/application.ex b/lib/sequin/application.ex index 323abfa1e..c6e0d166f 100644 --- a/lib/sequin/application.ex +++ b/lib/sequin/application.ex @@ -54,6 +54,7 @@ defmodule Sequin.Application do children = base_children() ++ [ + Sequin.SystemMetricsServer, SequinWeb.Telemetry, MutexedSupervisor.child_spec( Sequin.Runtime.MutexedSupervisor, @@ -91,7 +92,6 @@ defmodule Sequin.Application do Sequin.Sinks.Nats.ConnectionCache, Sequin.Sinks.RabbitMq.ConnectionCache, SequinWeb.Presence, - Sequin.SystemMetricsServer, {Task, fn -> enqueue_workers() end}, # Start to serve requests, typically the last entry SequinWeb.Endpoint, diff --git a/lib/sequin/runtime/message_consistency_check_worker.ex b/lib/sequin/runtime/message_consistency_check_worker.ex index 3d9396417..27a5d409b 100644 --- a/lib/sequin/runtime/message_consistency_check_worker.ex +++ b/lib/sequin/runtime/message_consistency_check_worker.ex @@ -25,15 +25,17 @@ defmodule Sequin.Runtime.MessageConsistencyCheckWorker do def audit_and_trim_undelivered_cursors(consumer_id, older_than_timestamp) do case MessageLedgers.count_undelivered_wal_cursors(consumer_id, older_than_timestamp) do {:ok, 0} -> - :ok + {:ok, 0} {:ok, undelivered_cursor_count} -> - Logger.warning("[MessageConsistencyCheckWorker] Found undelivered cursors (count=#{undelivered_cursor_count})", + Logger.warning( + "[MessageConsistencyCheckWorker] Found undelivered cursors (count=#{undelivered_cursor_count})", consumer_id: consumer_id, undelivered_cursor_count: undelivered_cursor_count ) - MessageLedgers.trim_stale_undelivered_wal_cursors(consumer_id, older_than_timestamp) + :ok = MessageLedgers.trim_stale_undelivered_wal_cursors(consumer_id, older_than_timestamp) + {:ok, undelivered_cursor_count} end end diff --git a/mix.exs b/mix.exs index f4e29ffcb..22b4f9d3c 100644 --- a/mix.exs +++ b/mix.exs @@ -23,13 +23,14 @@ defmodule Sequin.MixProject do def application do [ mod: {Sequin.Application, []}, - extra_applications: [:logger, :runtime_tools, :os_mon] ++ extra_applications(Mix.env()), + extra_applications: [:logger, :runtime_tools] ++ extra_applications(Mix.env()), included_applications: [:aws_credentials] ] end - defp extra_applications(:dev), do: [:wx, :observer] - defp extra_applications(_), do: [] + defp extra_applications(:dev), do: [:os_mon, :wx, :observer] + defp extra_applications(:test), do: [] + defp extra_applications(_), do: [:os_mon] # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "test/support"] diff --git a/test/sequin/gcp_pubsub_pipeline_test.exs b/test/sequin/gcp_pubsub_pipeline_test.exs index 0673d2319..604a1b34f 100644 --- a/test/sequin/gcp_pubsub_pipeline_test.exs +++ b/test/sequin/gcp_pubsub_pipeline_test.exs @@ -12,34 +12,30 @@ defmodule Sequin.Runtime.GcpPubsubPipelineTest do setup do consumer = ConsumersFactory.insert_sink_consumer!(type: :gcp_pubsub, batch_size: 10) - # Setup auth token expectation for all tests - Req.Test.expect(PubSub, fn conn -> - if conn.host == "oauth2.googleapis.com" do - Req.Test.json(conn, %{"access_token" => "test_token"}) - end - end) - {:ok, %{consumer: consumer}} end test "events are sent to PubSub", %{consumer: consumer} do message = ConsumersFactory.consumer_message() - # Mock PubSub publish - Req.Test.expect(PubSub, fn conn -> - assert conn.method == "POST" - assert conn.host == "pubsub.googleapis.com" - assert String.contains?(conn.request_path, ":publish") + Req.Test.stub(PubSub, fn conn -> + if conn.host == "oauth2.googleapis.com" do + Req.Test.json(conn, %{"access_token" => "test_token"}) + else + assert conn.method == "POST" + assert conn.host == "pubsub.googleapis.com" + assert String.contains?(conn.request_path, ":publish") - {:ok, body, _} = Plug.Conn.read_body(conn) - body = Jason.decode!(body) + {:ok, body, _} = Plug.Conn.read_body(conn) + body = Jason.decode!(body) - data = get_in(body, ["messages", Access.at(0), "data"]) - data = data |> Base.decode64!() |> Jason.decode!() - assert Map.has_key?(data, "record") - assert Map.has_key?(data, "metadata") + data = get_in(body, ["messages", Access.at(0), "data"]) + data = data |> Base.decode64!() |> Jason.decode!() + assert Map.has_key?(data, "record") + assert Map.has_key?(data, "metadata") - Req.Test.json(conn, %{}) + Req.Test.json(conn, %{}) + end end) start_pipeline!(consumer) @@ -55,16 +51,19 @@ defmodule Sequin.Runtime.GcpPubsubPipelineTest do message1 = ConsumersFactory.consumer_message(group_id: group_id) message2 = ConsumersFactory.consumer_message(group_id: group_id) - # Mock PubSub publish and verify batch - Req.Test.expect(PubSub, fn conn -> - assert conn.method == "POST" - assert conn.host == "pubsub.googleapis.com" + Req.Test.stub(PubSub, fn conn -> + if conn.host == "oauth2.googleapis.com" do + Req.Test.json(conn, %{"access_token" => "test_token"}) + else + assert conn.method == "POST" + assert conn.host == "pubsub.googleapis.com" - {:ok, body, _} = Plug.Conn.read_body(conn) - body = Jason.decode!(body) - assert length(body["messages"]) == 2 + {:ok, body, _} = Plug.Conn.read_body(conn) + body = Jason.decode!(body) + assert length(body["messages"]) == 2 - Req.Test.json(conn, %{}) + Req.Test.json(conn, %{}) + end end) start_pipeline!(consumer) @@ -78,7 +77,9 @@ defmodule Sequin.Runtime.GcpPubsubPipelineTest do message1 = ConsumersFactory.consumer_message(group_id: group_id) message2 = ConsumersFactory.consumer_message(group_id: group_id) - Req.Test.expect(PubSub, 3, fn conn -> + # Use stub to handle non-deterministic auth request count (1 or 2 auth requests + # depending on whether the token is cached before the second batch processor starts) + Req.Test.stub(PubSub, fn conn -> if conn.host == "oauth2.googleapis.com" do Req.Test.json(conn, %{"access_token" => "test_token"}) else @@ -102,11 +103,14 @@ defmodule Sequin.Runtime.GcpPubsubPipelineTest do @tag capture_log: true test "failed PubSub publish results in failed events", %{consumer: consumer} do - # Mock failed PubSub publish - Req.Test.expect(PubSub, fn conn -> - conn - |> Plug.Conn.put_status(500) - |> Req.Test.json(%{"error" => "Failed to publish to PubSub"}) + Req.Test.stub(PubSub, fn conn -> + if conn.host == "oauth2.googleapis.com" do + Req.Test.json(conn, %{"access_token" => "test_token"}) + else + conn + |> Plug.Conn.put_status(500) + |> Req.Test.json(%{"error" => "Failed to publish to PubSub"}) + end end) start_pipeline!(consumer) @@ -133,13 +137,16 @@ defmodule Sequin.Runtime.GcpPubsubPipelineTest do message = ConsumersFactory.consumer_message() - # Mock PubSub publish and verify topic - Req.Test.expect(PubSub, fn conn -> - assert conn.method == "POST" - assert conn.host == "pubsub.googleapis.com" - assert String.contains?(conn.request_path, "/my_topic:publish") + Req.Test.stub(PubSub, fn conn -> + if conn.host == "oauth2.googleapis.com" do + Req.Test.json(conn, %{"access_token" => "test_token"}) + else + assert conn.method == "POST" + assert conn.host == "pubsub.googleapis.com" + assert String.contains?(conn.request_path, "/my_topic:publish") - Req.Test.json(conn, %{}) + Req.Test.json(conn, %{}) + end end) start_pipeline!(consumer) diff --git a/test/sequin/message_consistency_check_worker_test.exs b/test/sequin/message_consistency_check_worker_test.exs index 945208472..6e81b85cc 100644 --- a/test/sequin/message_consistency_check_worker_test.exs +++ b/test/sequin/message_consistency_check_worker_test.exs @@ -1,8 +1,6 @@ defmodule Sequin.MessageConsistencyCheckWorkerTest do use Sequin.DataCase, async: true - import ExUnit.CaptureLog - alias Sequin.Factory.ConsumersFactory alias Sequin.Runtime.MessageConsistencyCheckWorker alias Sequin.Runtime.MessageLedgers @@ -26,10 +24,11 @@ defmodule Sequin.MessageConsistencyCheckWorkerTest do # Set timestamp to 2 minutes ago two_minutes_ago = DateTime.add(DateTime.utc_now(), -2 * 60, :second) - # Capture logs to verify output - assert capture_log(fn -> - MessageConsistencyCheckWorker.audit_and_trim_undelivered_cursors(consumer.id, two_minutes_ago) - end) =~ "Found undelivered cursors (count=3)" + assert {:ok, 3} = + MessageConsistencyCheckWorker.audit_and_trim_undelivered_cursors( + consumer.id, + two_minutes_ago + ) # Verify that the undelivered cursors set was trimmed assert {:ok, 0} = MessageLedgers.count_undelivered_wal_cursors(consumer.id, two_minutes_ago) @@ -42,10 +41,12 @@ defmodule Sequin.MessageConsistencyCheckWorkerTest do # Set timestamp to 2 minutes ago two_minutes_ago = DateTime.add(DateTime.utc_now(), -2 * 60, :second) - # Capture logs to verify output - assert capture_log(fn -> - MessageConsistencyCheckWorker.audit_and_trim_undelivered_cursors(consumer.id, two_minutes_ago) - end) == "" + # Should return :ok without logging (0-count path) + assert {:ok, 0} = + MessageConsistencyCheckWorker.audit_and_trim_undelivered_cursors( + consumer.id, + two_minutes_ago + ) # Verify that the undelivered cursors set is empty assert {:ok, 0} = MessageLedgers.count_undelivered_wal_cursors(consumer.id, two_minutes_ago) @@ -67,13 +68,15 @@ defmodule Sequin.MessageConsistencyCheckWorkerTest do # Set timestamp to 1 minute ago (not stale enough) one_minute_ago = DateTime.add(DateTime.utc_now(), -60, :second) - # Capture logs to verify output - assert capture_log(fn -> - MessageConsistencyCheckWorker.audit_and_trim_undelivered_cursors(consumer.id, one_minute_ago) - end) == "" + assert {:ok, 0} = + MessageConsistencyCheckWorker.audit_and_trim_undelivered_cursors( + consumer.id, + one_minute_ago + ) # Verify that the undelivered cursors set still contains the messages - assert {:ok, 2} = MessageLedgers.count_undelivered_wal_cursors(consumer.id, DateTime.utc_now()) + assert {:ok, 2} = + MessageLedgers.count_undelivered_wal_cursors(consumer.id, DateTime.utc_now()) end end end diff --git a/test/sequin/message_handler_test.exs b/test/sequin/message_handler_test.exs index ef900fe9b..d5c2d6ecb 100644 --- a/test/sequin/message_handler_test.exs +++ b/test/sequin/message_handler_test.exs @@ -143,8 +143,8 @@ defmodule Sequin.MessageHandlerTest do database = DatabasesFactory.insert_postgres_database!(account_id: account.id) field = ReplicationFactory.field() - table_schema1 = Factory.postgres_object() - table_schema2 = Factory.postgres_object() + table_schema1 = "schema_one_#{Factory.sequence()}" + table_schema2 = "schema_two_#{Factory.sequence()}" message1 = ReplicationFactory.postgres_message(table_oid: 123, action: :insert, fields: [field], table_schema: table_schema1) diff --git a/test/sequin/postgres/benchmark_source_test.exs b/test/sequin/postgres/benchmark_source_test.exs index b2940f35d..ab456520b 100644 --- a/test/sequin/postgres/benchmark_source_test.exs +++ b/test/sequin/postgres/benchmark_source_test.exs @@ -173,7 +173,7 @@ defmodule Sequin.Postgres.BenchmarkSourceTest do receive do {:messages_received, messages} -> receive_messages(count, acc ++ messages) after - 100 -> acc + 1_000 -> acc end end end diff --git a/test/sequin/postgres_replication_test.exs b/test/sequin/postgres_replication_test.exs index d3c35bb68..d26396d7a 100644 --- a/test/sequin/postgres_replication_test.exs +++ b/test/sequin/postgres_replication_test.exs @@ -44,6 +44,7 @@ defmodule Sequin.PostgresReplicationTest do alias Sequin.TestSupport.SimpleHttpServer @moduletag :unboxed + @moduletag :capture_log @publication "characters_publication" @@ -1499,6 +1500,21 @@ defmodule Sequin.PostgresReplicationTest do defp stop_replication!(pg_replication) do # Stop the supervisor using its via_tuple stop_supervised!(Supervisor.via_tuple(pg_replication.id)) + # Wait for :syn to clean up the process registration asynchronously + wait_for_syn_cleanup({Supervisor, pg_replication.id}) + end + + defp wait_for_syn_cleanup(key, attempts \\ 50) do + if :syn.lookup(:replication, key) == :undefined do + :ok + else + if attempts > 0 do + Process.sleep(10) + wait_for_syn_cleanup(key, attempts - 1) + else + raise "Timed out waiting for :syn to clean up registration for #{inspect(key)}" + end + end end # defp config do diff --git a/test/sequin/postgres_test.exs b/test/sequin/postgres_test.exs index 7aacb4471..b4edb3635 100644 --- a/test/sequin/postgres_test.exs +++ b/test/sequin/postgres_test.exs @@ -7,6 +7,8 @@ defmodule Sequin.PostgresTest do alias Sequin.Repo alias Sequin.Test.UnboxedRepo + @moduletag :capture_log + setup do {:ok, conn} = Postgrex.start_link(UnboxedRepo.config()) %{conn: conn} diff --git a/test/sequin/runtime/slot_producer/integration_test.exs b/test/sequin/runtime/slot_producer/integration_test.exs index 0bc76584f..f3292433b 100644 --- a/test/sequin/runtime/slot_producer/integration_test.exs +++ b/test/sequin/runtime/slot_producer/integration_test.exs @@ -24,6 +24,7 @@ defmodule Sequin.Runtime.SlotProducer.IntegrationTest do alias Sequin.TestSupport.ReplicationSlots @moduletag :unboxed + @moduletag :capture_log @publication "characters_publication" def replication_slot, do: ReplicationSlots.slot_name(__MODULE__) diff --git a/test/sequin/runtime/slot_producer/reorder_buffer_test.exs b/test/sequin/runtime/slot_producer/reorder_buffer_test.exs index d3f9b80cb..6c29b215c 100644 --- a/test/sequin/runtime/slot_producer/reorder_buffer_test.exs +++ b/test/sequin/runtime/slot_producer/reorder_buffer_test.exs @@ -13,6 +13,8 @@ defmodule Sequin.Runtime.SlotProducer.ReorderBufferTest do alias Sequin.Runtime.SlotProducer.Message alias Sequin.Runtime.SlotProducer.ReorderBuffer + @moduletag :capture_log + @reorder_buffer_id Module.concat(__MODULE__, ReorderBuffer) def reorder_buffer_id, do: @reorder_buffer_id diff --git a/test/sequin/runtime/slot_producer/slot_producer_test.exs b/test/sequin/runtime/slot_producer/slot_producer_test.exs index 825118d1a..eb44b2178 100644 --- a/test/sequin/runtime/slot_producer/slot_producer_test.exs +++ b/test/sequin/runtime/slot_producer/slot_producer_test.exs @@ -27,6 +27,7 @@ defmodule Sequin.Runtime.SlotProducerTest do alias Sequin.TestSupport.ReplicationSlots @moduletag :unboxed + @moduletag :capture_log @publication "characters_publication" def replication_slot, do: ReplicationSlots.slot_name(__MODULE__) diff --git a/test/sequin/slot_message_store_state_test.exs b/test/sequin/slot_message_store_state_test.exs index 5d1ebb7b7..b7c9cfffe 100644 --- a/test/sequin/slot_message_store_state_test.exs +++ b/test/sequin/slot_message_store_state_test.exs @@ -9,6 +9,8 @@ defmodule Sequin.Runtime.SlotMessageStoreStateTest do alias Sequin.Runtime.SlotMessageStore.State alias Sequin.Size + @moduletag :capture_log + setup do state = %State{ consumer: %SinkConsumer{seq: Factory.unique_integer()}, diff --git a/test/sequin/table_reader_server_test.exs b/test/sequin/table_reader_server_test.exs index bc922d05c..9852a94c5 100644 --- a/test/sequin/table_reader_server_test.exs +++ b/test/sequin/table_reader_server_test.exs @@ -23,6 +23,8 @@ defmodule Sequin.Runtime.TableReaderServerTest do alias Sequin.Runtime.TableReaderServer alias Sequin.TestSupport.Models.CharacterDetailed + @moduletag :capture_log + @task_sup_name Module.concat(__MODULE__, TaskSupervisor) setup do diff --git a/test/sequin/table_reader_test.exs b/test/sequin/table_reader_test.exs index 9ff71b1c0..681a7f411 100644 --- a/test/sequin/table_reader_test.exs +++ b/test/sequin/table_reader_test.exs @@ -9,8 +9,11 @@ defmodule Sequin.TableReaderTest do alias Sequin.Factory.DatabasesFactory alias Sequin.Runtime.KeysetCursor alias Sequin.Runtime.TableReader + alias Sequin.TestSupport.Models.Character alias Sequin.TestSupport.Models.CharacterMultiPK + @moduletag :capture_log + setup do db = DatabasesFactory.insert_configured_postgres_database!(tables: []) ConnectionCache.cache_connection(db, Repo) @@ -355,6 +358,9 @@ defmodule Sequin.TableReaderTest do db: db, characters_table: table } do + # Clean up any characters committed by concurrent unboxed tests + Repo.delete_all(Character) + # Create a table with nil sort_column_attnum table_with_nil_sort = %{table | sort_column_attnum: nil} diff --git a/test/sequin/yaml_loader_test.exs b/test/sequin/yaml_loader_test.exs index 4f7ef490a..a00fa908b 100644 --- a/test/sequin/yaml_loader_test.exs +++ b/test/sequin/yaml_loader_test.exs @@ -37,6 +37,7 @@ defmodule Sequin.YamlLoaderTest do alias Sequin.YamlLoader @moduletag :unboxed + @moduletag :capture_log @publication "characters_publication" @@ -609,16 +610,16 @@ defmodule Sequin.YamlLoaderTest do end """) - assert [function1, function2] = Repo.all(Function, order_by: :name) - assert function1.name == "my-path-transform" - assert function1.type == "path" - assert function1.function.path == "record" - - assert function2.name == "my-function-transform" - assert function2.type == "transform" + assert [function1, function2] = Repo.all(from(f in Function, order_by: f.name)) + assert function1.name == "my-function-transform" + assert function1.type == "transform" - assert function2.function.code == + assert function1.function.code == "def transform(action, record, changes, metadata) do\n %{id: record[\"id\"], action: action}\nend" + + assert function2.name == "my-path-transform" + assert function2.type == "path" + assert function2.function.path == "record" end test "updates an existing function" do @@ -2548,8 +2549,15 @@ defmodule Sequin.YamlLoaderTest do initial_backfill: true """) - # Consumer should still exist, but no backfill should have been created - assert [^consumer] = Repo.all(SinkConsumer) + # Consumer should still exist unchanged, but no backfill should have been created + assert [updated_consumer] = Repo.all(SinkConsumer) + assert updated_consumer.id == consumer.id + assert updated_consumer.name == consumer.name + assert updated_consumer.status == consumer.status + assert updated_consumer.backfill_completed_at == consumer.backfill_completed_at + assert updated_consumer.replication_slot_id == consumer.replication_slot_id + assert updated_consumer.source == consumer.source + assert updated_consumer.sink == consumer.sink assert [] = Repo.all(Backfill) end diff --git a/test/sequin_web/controllers/pull_controller_test.exs b/test/sequin_web/controllers/pull_controller_test.exs index e1f9ec86d..2b6ad0c24 100644 --- a/test/sequin_web/controllers/pull_controller_test.exs +++ b/test/sequin_web/controllers/pull_controller_test.exs @@ -185,7 +185,7 @@ defmodule SequinWeb.PullControllerTest do record = ConsumersFactory.deliverable_consumer_event(consumer_id: consumer.id) SlotMessageStore.put_messages(consumer, [record]) - assert_elapsed_under(100, fn -> + assert_elapsed_under(120, fn -> conn = get(conn, ~p"/api/sequin_streams/#{consumer.id}/receive", wait_for: 5000) assert %{"data" => [_message]} = json_response(conn, 200) end) diff --git a/test/test_helper.exs b/test/test_helper.exs index 99b7e141d..a56e046c6 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,6 +1,46 @@ alias Sequin.Databases.PostgresDatabaseTable alias Sequin.Test.UnboxedRepo +# Suppress noisy log messages in tests that come from OTP/library processes +# (not test-owned) and would otherwise leak into test output. +# ExUnit's capture_log only captures from direct children via $callers metadata, +# so logs from deeply nested supervised processes leak through. +:logger.add_handler_filter(:default, :suppress_test_noise, { + fn + # Postgrex disconnect errors when test processes exit with checked-out connections + %{meta: %{mfa: {DBConnection.Connection, :handle_event, _}}}, _extra -> + :stop + + # GenServer terminating errors during test teardown + %{meta: %{mfa: {:gen_server, :error_info, _}}}, _extra -> + :stop + + # DebouncedLogger flush messages from timer processes + %{meta: %{mfa: {Sequin.DebouncedLogger, :flush_bucket, _}}}, _extra -> + :stop + + # DebouncedLogger initial log calls from nested supervised processes + %{meta: %{mfa: {Sequin.DebouncedLogger, _, _}}}, _extra -> + :stop + + # SlotMessageStoreState warnings (backfill group conflict, etc.) from supervised processes + %{meta: %{mfa: {Sequin.Runtime.SlotMessageStoreState, _, _}}}, _extra -> + :stop + + # ReorderBuffer exit warnings during test teardown + %{meta: %{mfa: {Sequin.Runtime.SlotProducer.ReorderBuffer, :handle_info, _}}}, _extra -> + :stop + + # Req retry warnings from HTTP requests in nested processes + %{meta: %{mfa: {Req.Steps, :log_retry, _}}}, _extra -> + :stop + + _log, _extra -> + :ignore + end, + %{} +}) + UnboxedRepo.start_link() Sequin.TestSupport.ReplicationSlots.setup_all() ExUnit.start()