Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test Gunicorn Worker #1834

Closed
Kludex opened this issue Jan 5, 2023 · 8 comments · Fixed by #2302
Closed

Test Gunicorn Worker #1834

Kludex opened this issue Jan 5, 2023 · 8 comments · Fixed by #2302

Comments

@Kludex
Copy link
Sponsor Member

Kludex commented Jan 5, 2023

The idea here is to create a setup to test the gunicorn worker classes that we have.

I don't know how is the best way to achieve this, as gunicorn test suite didn't give me much insight on how we can test this integration without unittest.mock. Suggestions are welcome.

If you are interested on working on this, go ahead. Some clarifications:

  1. Avoid integration kind of setup. I want to keep it simple.
  2. Avoid unittest.mock - if inevitable, explain the reason.
  3. Add test coverage up to 100% on the workers.py.

Notes

When doing this, please change those lines:

uvicorn/setup.cfg

Lines 39 to 43 in eec7d22

[coverage:run]
omit = venv/*
include = uvicorn/*, tests/*
plugins =
coverage_conditional_plugin

To something more like: https://github.com/encode/starlette/blob/048643adc21e75b668567fc6bcdd3650b89044ea/setup.cfg#L41-L42

Important

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar
@br3ndonland
Copy link
Contributor

I can take this on. I agree we should keep it simple and focus on unit testing.

One way I've approached unit testing without mocks is by starting a Gunicorn server with the --print-config option. This does actually start the Gunicorn server, but Gunicorn will just print out the config and then shut down. You can then parse the output and assert that Gunicorn is using the appropriate settings.

I'll think about some other complementary ways to approach testing of the worker.

@br3ndonland
Copy link
Contributor

Just dropping a note here to say that I'm working on this and making some slow progress.

I started off with the --print-config strategy I mentioned in #1834 (comment), but it wasn't very useful. We're not doing much modification of the Gunicorn config here, other than just setting the worker class, and I've also found that this strategy doesn't really test functionality of the server at all. For example, I can run a command like gunicorn --print-config --worker-class "this.worker.DoesNotExist" "example_package.example_module:app", and Gunicorn will start up, print out the config stating that the worker class is this.worker.DoesNotExist, and exit successfully, even though that config would clearly not work.

Instead, I'm working on some testing capabilities that will:

Hope to have a PR for review soon.

@jawang94

This comment was marked as spam.

@br3ndonland
Copy link
Contributor

br3ndonland commented Apr 15, 2023

I'm working through a few tedious limitations right now. One of them relates to conditional test coverage.

As correctly suggested in the description, we need to change our coverage.py config from include = uvicorn/*, tests/* to source_pkgs = uvicorn, tests. This is because the current include syntax actually excludes uvicorn.workers from test coverage. Switching to source_pkgs will include all the modules.

The limitation is that we can't cover uvicorn.workers or the associated tests on Windows. Gunicorn doesn't test on Windows at all because it depends on various Unix utilities like fcntl.

How do we tell coverage.py, "please exclude uvicorn.workers and tests.test_workers from coverage on Windows"? Seems like there should be some obvious way to do this, but I'm not sure.

Coverage.py has an --omit flag, but I don't think this flag can handle platform-specific conditionals like we need here.

I tried setting pragmas at the top-level of the modules, but coverage-conditional-plugin doesn't support this (wemake-services/coverage-conditional-plugin#2).

Am I missing something? Or will I need to do a PR that resolves wemake-services/coverage-conditional-plugin#2 in order to unblock this?

I guess the simplest option would be to add a # pragma: py-win32 comment to every statement that's not covered. It would add a lot of comments.

@br3ndonland
Copy link
Contributor

Am I missing something? Or will I need to do a PR that resolves wemake-services/coverage-conditional-plugin#2 in order to unblock this?

PR submitted (wemake-services/coverage-conditional-plugin#221). This feature will enable entire modules to be conditionally omitted from test coverage measurement.

@br3ndonland
Copy link
Contributor

Coding for this is done, and we now have a nice way to omit the worker code from test coverage measurement on Windows, thanks to coverage-conditional-plugin 0.9.0.

PR coming up shortly.

@Kludex
Copy link
Sponsor Member Author

Kludex commented Jun 4, 2023

Thanks 🙏

@br3ndonland br3ndonland mentioned this issue Jun 4, 2023
3 tasks
@Kludex
Copy link
Sponsor Member Author

Kludex commented Mar 30, 2024

I'll deprecate the workers within Uvicorn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants