Sanic and pytest errors: "Socket is not connected" and "Sanic app name X not found"

308 views Asked by At

Update to Sanic 22.12 from 21.x broke all app.test_client tests. Examples from the official documentation do not work.

server.py

app = Sanic("app_name")
app.config.RESPONSE_TIMEOUT = 3600
TestManager(app)

# routes defined here
# ...

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

test.py

from server import app

def test_deploy_plan():
    _, response = app.test_client.get('/some/route')
    assert response.status_code == 200

pytest test.py yields:

Sanic app name 'app_name' not found.
App instantiation must occur outside if __name__ == '__main__' block or by using an AppLoader.
See https://sanic.dev/en/guide/deployment/app-loader.html for more details.
Traceback (most recent call last):
  File "<redacted>/venv/lib/python3.9/site-packages/sanic/app.py", line 1491, in get_app
    return cls._app_registry[name]
KeyError: 'app_name'

During handling of the above exception, another exception occurred:

[...]

App instantiation must occur outside if __name__ == '__main__' block or by using an AppLoader.
See https://sanic.dev/en/guide/deployment/app-loader.html for more details.
[2023-02-08 17:38:18 -0800] [6280] [ERROR] Not all workers acknowledged a successful startup. Shutting down.

One of your worker processes terminated before startup was completed. Please solve any errors experienced during startup. If you do not see an exception traceback in your error logs, try running Sanic in in a single process using --single-process or single_process=True. Once you are confident that the server is able to start without errors you can switch back to multiprocess mode.
------------------------------ Captured log call ------------------------------
INFO     sanic.root:motd.py:54 Sanic v22.12.0
INFO     sanic.root:motd.py:54 Goin' Fast @ http://127.0.0.1:57940
INFO     sanic.root:motd.py:54 mode: production, ASGI
INFO     sanic.root:motd.py:54 server: sanic, HTTP/1.1
INFO     sanic.root:motd.py:54 python: 3.9.16
INFO     sanic.root:motd.py:54 platform: macOS-12.4-arm64-arm-64bit
INFO     sanic.root:motd.py:54 packages: sanic-routing==22.8.0, sanic-testing==22.6.0
ERROR    sanic.error:manager.py:230 Not all workers acknowledged a successful startup. Shutting down.

One of your worker processes terminated before startup was completed. Please solve any errors experienced during startup. If you do not see an exception traceback in your error logs, try running Sanic in in a single process using --single-process or single_process=True. Once you are confident that the server is able to start without errors you can switch back to multiprocess mode.

This used to work in Sanic 21.x:

from server import app

def test_route_returns_200():
    request, response = app.test_client.get('/some/route')
    assert response.status == 200

Another official example defines the routes in the app inside the fixture, which doesn't help me because all the app functionality is defined in a different module:

# official doc example, not good for this purpose
import pytest

@pytest.fixture
def app():
    sanic_app = Sanic(__name__)
    TestManager(sanic_app)

    @sanic_app.get("/")
    def basic(request):
        return response.text("foo")

    return sanic_app

def test_basic_test_client(app):
    request, response = app.test_client.get("/")

    assert response.body == b"foo"
    assert response.status == 200
1

There are 1 answers

0
rbm On

I found a way to do this.

from pytest import fixture
from sanic_testing.reusable import ReusableClient

import my.application.server as SERVER

@fixture
def client():
    yield ReusableClient(SERVER.app)

def test_something(client):
    with client:
        _, response = client.get('/some/route/')
        assert response.status_code == 200