-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
⚡️ Improve backend test performance by patching password hashing #1389
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
base: master
Are you sure you want to change the base?
⚡️ Improve backend test performance by patching password hashing #1389
Conversation
85712f8
to
05710bd
Compare
05710bd
to
5fe9712
Compare
This substantially reduces testing time - thank you! Only thing I noticed is that |
At least according to mypy, mypy output when using
I'm not sure what's the better option here. Do we ignore the type checker and provided signature for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saltie2193, good idea!
In addition to the comment below, I think we should leave 1 test that would be run without this patching to ensure real algorithm works (mark test with @pytest.mark.noautofixt
and pass db
fixture explicitly).
backend/app/tests/conftest.py
Outdated
@pytest.fixture(scope="session", autouse=True) | ||
def db() -> Generator[Session, None, None]: | ||
def db( | ||
disable_password_hashing: Generator[None, None, None], # noqa: ARG001 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we shouldn't mix disable_password_hashing
with db
fixture
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case should we make disable_password_hashing
an autouse fixture and just explicitly disable the fixture in tests where we want hashing to be enabled?
I think this would still be necessary since I would assume we want hashing disabled for almost all tests and only enable it for a few specific ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some investigation the disable_password_hashing
and db
fixtures were mixed because of the call to init_db
in the db
fixture. When password hashing is not enabled during this setup, the database is initialized with a hashed password of the superuser, while the tests try to authenticate the user without hashing the provided password.
This could be mitigated if tests would not rely on an initial setup of the database and the configured superuser, but setup up (and tear down) the required test data on their own. I don't think this easily fixable here, since we would need to remove the dependency of the tests to an initial setup.
For the time being while this interdependency between test exists, a workaround or solution could be to create a new module testing authentication with hashing enabled and create overrides for db
and client
with enabled password hashing, recreating the database with hashed passwords. In this case the default db
and client
fixtures would stay mixed with the disable_password_hashing
fixture, since we want to disable it by default in almost every test case and it is required due to the dependency on the initial setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand the problem..
What if we create init_db_fixtrue
fixture:
@pytest.fixture(scope="session", autouse=True)
def init_db_fixture(db: Session) -> Generator[None, None, None]:
init_db(db)
yield
.. and remove the init_db
call from db
fixture?
The main question is: if the order of fixtures in conftest.py
defines the order they will be applied automatically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is the password patching needs to be applied, before the init_db_fixture
is executed. Every time we want to disable or enable it, the database needs to be initialized again.
As far as I understand the pytest documentation, only factors are
- scope,
- dependencies, or
- autouse.
For the time being it seems to work, but the dependency of tests to an initial setup is still a problem. The current compromise is to introduce a marker to enable password hashing on a module level. So the initial setup is only run before every module. In the long term I think it would be best to remove this dependency allowing to enable or disable hashing per test. This would remove the problem of execution order of the fixtures as well.
* Patch password hashing during tests
- Add marker to activate password hashing on module level. - Change scope of `db` and `client` fixtures to `module`. - Add test without patched password hashing
5874ecf
to
5e2bdf0
Compare
Sorry for pushing to your branch, it was simpler than explaining this in review.. I suggest simplify tests:
|
This pull request has a merge conflict that needs to be resolved. |
That's basically the original proposal now so looks fine to me. I hope it's fine I reverted the changes to keep the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
This disables password hashing for all tests except one (in test_login_with_hashing.py
- added to make sure login functionality still works with password hashing).
I still think it would be simpler to just use two patch
es instead of implementing patch_password_hashing
with ExitStack
, but let's Sebastian decide. I would revert this commit
@saltie2193, thank you for working on this!
Contextmanager to patch ``pwd_context`` in the given modules. | ||
:param modules: list of modules to patch. | ||
:return: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contextmanager to patch ``pwd_context`` in the given modules. | |
:param modules: list of modules to patch. | |
:return: | |
Contextmanager to patch `pwd_context` in the given modules. |
We don't use this style for docstrings in this project
Improve performance of backend tests by patching password hashing during tests.
NOTE: To reduce interference with preexisting data, all existing users and items are now deleted before the tests are run.
This should not be noticable outside of testing, since all users and items already have been deleted after testing anyway.