Is it possible to globally change the `:testing` mode at runtime?

I’m working on an app which sets Oban’s testing: :inline in config/test.exs. In hindsight, :manual would be better, but switching will be painful.

I have a specific test where several processes are involved. With :inline, the Oban job is the same process as the one that inserts it, which causes an issue. I’m trying to use :manual mode to prevent that. Oban.Testing.with_mode(:manual, fn -> ... end) doesn’t do it, but that makes sense given the multiple processes involved. But temporarily altering the global application env var like this also doesn’t work:

  # aysnc: false because we are monkeying with global env settings
  use MyAppWeb.ChannelCase, async: false

  setup do
    prior_testing_mode =
      Application.get_env(:myapp, Oban)
      |> Keyword.fetch!(:testing)

    Application.put_env(:myapp, Oban, testing: :manual)

    on_exit(fn ->
      Application.put_env(:myapp, Oban, testing: prior_testing_mode)
    end)
  end

If I change it in config/test.exs, it does fix this test, it just breaks a lot of others.

So it seems there is no way to change this setting application-wide except at compile time. Is that correct?

Oban doesn’t read the application environment itself. That’s all part of how you pass options into it for your application’s supervisor.

All options, including :testing, can be set at runtime. You can change the mode by restarting the Oban instance, but that’s problematic when it is part of your supervision tree.

Switching to :manual mode is your best bet. But, considering how painful that may be, here are two alternatives:

  1. Use Application.stop to stop the full app, change the config, then restart your entire application. It won’t be very fast and you can’t do it async.
  2. Start another Oban instance using manual mode and use that instance in your test. For example, to start another instance:
opts = 
  :my_app
  |> Application.get_env(Oban)
  |> Keyword.put(:name, OtherOban)
  |> Keyword.put(:testing, :manual)

start_supervised({Oban, opts})

Then use the name OtherOban in the code you’re testing by injecting it, configuring it, etc.

If you’re using Pro there is also a helper to start Oban instances for testing: Oban.Pro.Testing — Oban Pro v1.5.0-rc.3

4 Likes