Skip to content

Phoenix.Ecto.SQL.Sandbox plug not working reliably with Bandit #192

@michallepicki

Description

@michallepicki

Hello!

When trying to switch from Cowboy to Bandit we found a possible incompatibility with plug Phoenix.Ecto.SQL.Sandbox. Our async API "integration" tests are working correctly with Cowboy, but fail in odd ways with Bandit. I made a repro repository using the Phoenix 1.8 rc installer from the phoenix master branch. Example failures on this repro look like:

$ mix test
Generated hello app
Running ExUnit with seed: 836115, max_cases: 32

  1) test create a few things, then list them all (HelloWeb.Integration.ABCDTest)
     test/hello_web/integration/abcd_test.exs:10
     match (=) failed
     The following variables were pinned:
       names = ["a", "b", "c", "d"]
     code:  assert ^names = Enum.map(response.body["data"], & &1["name"]) |> Enum.sort()
     left:  ^names
     right: ["a", "d", "f", "g"]
     stacktrace:
       test/hello_web/integration/abcd_test.exs:20: (test)

  2) test create a few things, then list them all (HelloWeb.Integration.EFGHTest)
     test/hello_web/integration/efgh_test.exs:10
     match (=) failed
     The following variables were pinned:
       names = ["e", "f", "g", "h"]
     code:  assert ^names = Enum.map(response.body["data"], & &1["name"]) |> Enum.sort()
     left:  ^names
     right: ["b", "c", "e", "h"]
     stacktrace:
       test/hello_web/integration/efgh_test.exs:20: (test)

Finished in 1.0 seconds (1.0s async, 0.00s sync)
2 tests, 2 failures

My suspicion is that since Bandit re-uses processes by default, when handling a request in a process that previously already handled a request for a different test, Phoenix's Ecto Sandbox plug will not switch from one sandbox to another. And setting http_1_options: [max_requests: 1], seemingly fixes the problem - but it feels wrong to do this change in tests because it's changing crucial config of our web server infrastructure which we do want to test as-is...

Maybe the plug should either switch from one sandbox to another when called? Or it should have a before_send that "disallows" the web handler process from using the sandbox it's allowing it to use?

cc @mtrudel

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions