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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions