Passed Run of Oct 26, 23:43
pytest --flakytest-profile --flakytest-rate 5000.
Where the time goes
Test time by category- Password hashing27.35 s
- Migrations25.35 s
- Libraries18.89 s
- Database12.57 s
- Templates3.37 s
- DB schema2.67 s
- Imports1.95 s
- Mocking1.36 s
- pytest525 ms
- Factories389 ms
- Unsampled361 ms
- App code109 ms
- Deep copies67 ms
- Cache46 ms
- Network43 ms
- Test code16 ms
- Waiting16 ms
- Logging15 ms
- Serialization12 ms
Session timeline
Fix next
Ranked by the time each fix saves per runUse plain static file storage in tests
Static file storage/manifest handling costs 28.3s.
Details
Where:
- accounts/views.py:425 index · 1.01 s
- starter_packs/tests.py:841 TestShareStarterPack.test_api_formats · 740 ms
- confs/views.py:509 create_conference · 691 ms
- accounts/tests.py:550 TestAccountIndexRobots.assert_noindex · 606 ms
- starter_packs/views.py:862 share_starter_pack · 528 ms
- starter_packs/tests.py:781 TestShareStarterPack.test_order_by · 419 ms
- starter_packs/tests.py:723 TestShareStarterPack.test_header_shows_gradient_and_account_avatars · 411 ms
- confs/tests.py:152 TestMigratedLegacyConferences._assert_no_naive_warning · 374 ms
- accounts/views.py:28 CountlessPage.__init__ · 335 ms
- confs/views.py:296 _conference_detail · 323 ms
Most affected tests:
- accounts/tests.py::TestAccountIndexRobots::test_two_facets_are_noindex
- starter_packs/tests.py::TestShareStarterPack::test_header_shows_gradient_and_account_avatars
- confs/tests.py::TestCreateConference::test_rejects_end_date_before_start
- accounts/tests.py::TestSelectedInstance::test_invalid_selected_instance
- confs/tests.py::TestCreateConference::test_form_renders_for_authenticated_user
- starter_packs/tests.py::TestShareStarterPack::test_order_by_5___alphabetical____4__3__2__1__0__
- confs/tests.py::TestMigratedLegacyConferences::test_djangoconafrica_page
- accounts/tests.py::TestAccountIndexRobots::test_single_facet_is_indexable
Use a fast password hasher in tests
27.3s (29% of test time) is spent hashing passwords. Slow hashing protects real passwords; in tests it only burns CPU.
Details
Only change the hasher in test settings. Tests that assert on a specific hash format need updating.
Where:
- confs/tests.py:1044 TestCreateConference.setUp · 5.51 s
- confs/tests.py:1177 TestEditConference.setUp · 3.78 s
- confs/tests.py:1175 TestEditConference.setUp · 3.75 s
- confs/tests.py:1176 TestEditConference.setUp · 3.37 s
- confs/tests.py:1371 TestApproveConference.setUp · 2.85 s
- confs/tests.py:1372 TestApproveConference.setUp · 2.80 s
- confs/tests.py:1317 TestConferenceApprovalVisibility.setUp · 1.52 s
- confs/tests.py:1316 TestConferenceApprovalVisibility.setUp · 1.51 s
- confs/tests.py:1295 TestUnapproveConference.setUp · 618 ms
- confs/tests.py:1296 TestUnapproveConference.setUp · 601 ms
Most affected tests:
- confs/tests.py::TestEditConference::test_edit_does_not_change_slug
- confs/tests.py::TestEditConference::test_other_user_forbidden_on_approved_conference
- confs/tests.py::TestEditConference::test_other_user_forbidden
- confs/tests.py::TestEditConference::test_owner_can_edit
- confs/tests.py::TestApproveConference::test_non_staff_forbidden
- confs/tests.py::TestApproveConference::test_staff_sees_approve_button_on_detail
- confs/tests.py::TestApproveConference::test_staff_approves
- confs/tests.py::TestEditConference::test_owner_can_edit_after_approval
Stop re-running migrations on every test run
Migrations take 25.3s per run, before the first test can start.
Details
CI should still build the database from scratch (no --reuse-db) so broken migrations are caught.
Where:
- confs/tests.py:432 TestLegacyConferenceDataMigration._migrate · 1.33 s
- confs/migrations/0031_seed_conference_tags.py:14 seed_conference_tags · 761 ms
- confs/tests.py:412 TestLegacyConferenceDataMigration._leaf_targets · 148 ms
- confs/migrations/0033_remove_legacy_conference_tables.py:214 _pk_batches · 113 ms
- confs/migrations/0033_remove_legacy_conference_tables.py:388 _get_or_create_conference · 87 ms
- confs/tests.py:431 TestLegacyConferenceDataMigration._migrate · 71 ms
- starter_packs/migrations/0004_starterpack_published_at.py:9 set_published_at · 65 ms
- starter_packs/migrations/0009_starterpack_num_accounts.py:21 update_num_accounts · 61 ms
- confs/tests.py:486 TestLegacyConferenceDataMigration._seed_overlapping_legacy_data · 54 ms
- confs/migrations/0011_conferencepost_alter_conference_posts.py:13 update · 54 ms
Most affected tests:
- confs/tests.py::TestMigratedLegacyConferences::test_fwd50_date_redirects
- accounts/tests.py::TestAccountIndexRobots::test_two_facets_are_noindex
- accounts/tests.py::TestSelectedInstance::test_invalid_selected_instance
- confs/tests.py::TestSyncAnnouncements::test_is_idempotent_and_refreshes_unposted_content
- confs/tests.py::TestLegacyConferenceDataMigration::test_copies_overlapping_legacy_rows_without_clobbering_existing_data
- confs/tests.py::TestLegacyConferenceDataMigration::test_drops_legacy_tables_when_uniques_are_mysql_style_indexes
Create shared test data in setUpTestData instead of setUp
setUp() runs before every test and takes 26.5s in total (password hashing 26.3s, db 196ms, factories 12ms) in 7 classes: TestApproveConference (6 tests), TestFollowStarterPack (3 tests), TestCreateConference (10 tests), TestEditConference (9 tests).
Details
Since Django 3.2 attributes assigned in setUpTestData are deep-copied per test, so in-memory changes don't leak between tests. Keep objects a test modifies in the database (or re-fetches) as before.
Where:
- confs/tests.py:1044 TestCreateConference.setUp · 5.53 s
- confs/tests.py:1177 TestEditConference.setUp · 3.80 s
- confs/tests.py:1175 TestEditConference.setUp · 3.76 s
- confs/tests.py:1176 TestEditConference.setUp · 3.38 s
- confs/tests.py:1371 TestApproveConference.setUp · 2.86 s
- confs/tests.py:1372 TestApproveConference.setUp · 2.81 s
- confs/tests.py:1317 TestConferenceApprovalVisibility.setUp · 1.53 s
- confs/tests.py:1316 TestConferenceApprovalVisibility.setUp · 1.52 s
- confs/tests.py:1295 TestUnapproveConference.setUp · 620 ms
- confs/tests.py:1296 TestUnapproveConference.setUp · 603 ms
Most affected tests:
- confs/tests.py::TestEditConference::test_edit_does_not_change_slug
- confs/tests.py::TestEditConference::test_other_user_forbidden_on_approved_conference
- confs/tests.py::TestEditConference::test_other_user_forbidden
- confs/tests.py::TestEditConference::test_owner_can_edit
- confs/tests.py::TestApproveConference::test_non_staff_forbidden
- confs/tests.py::TestApproveConference::test_staff_sees_approve_button_on_detail
- confs/tests.py::TestApproveConference::test_staff_approves
- confs/tests.py::TestEditConference::test_owner_can_edit_after_approval
Disable django-debug-toolbar in tests
django-debug-toolbar is installed in the test settings and costs 11.8s.
Details
Where:
- accounts/views.py:425 index · 1.01 s
- confs/views.py:509 create_conference · 691 ms
- starter_packs/views.py:862 share_starter_pack · 528 ms
- accounts/views.py:28 CountlessPage.__init__ · 335 ms
- confs/views.py:296 _conference_detail · 323 ms
- starter_packs/views.py:60 get_editable_pack · 299 ms
- starter_packs/views.py:856 share_starter_pack · 285 ms
- starter_packs/views.py:858 share_starter_pack · 280 ms
- starter_packs/tests.py:192 TestEditStarterPack.test_not_logged_in · 267 ms
- starter_packs/views.py:729 share_starter_pack · 265 ms
Most affected tests:
- accounts/tests.py::TestAccountIndexRobots::test_two_facets_are_noindex
- confs/tests.py::TestCreateConference::test_rejects_end_date_before_start
- accounts/tests.py::TestSelectedInstance::test_invalid_selected_instance
- starter_packs/tests.py::TestShareStarterPack::test_order_by_5___alphabetical____4__3__2__1__0__
- starter_packs/tests.py::TestEditStarterPack::test_not_logged_in
- accounts/tests.py::TestAccountIndexRobots::test_single_facet_is_indexable
- confs/tests.py::TestCreateConference::test_form_renders_for_authenticated_user
- confs/tests.py::TestMigratedLegacyConferences::test_djangoconafrica_page
Repeated queries (N+1) in the code under test
10 tests run the same query 10+ times, e.g. 45x in test_invalid_selected_instance. N+1 queries slow the tests and production alike.
Details
This changes application code, so it speeds up production too; the tests stay as they are.
- 45x in test_invalid_selected_instance: SELECT "confs_conferencetag"."id", "confs_conferencetag"."name", "confs_conferencetag"."slug", "confs_conferencetag"."icon" FROM "confs_conferencetag" WHERE "confs_conferencetag"."slug" = %s LIMIT ? FOR UPDATE
- 45x in test_fwd50_date_redirects: SELECT "confs_conferencetag"."id", "confs_conferencetag"."name", "confs_conferencetag"."slug", "confs_conferencetag"."icon" FROM "confs_conferencetag" WHERE "confs_conferencetag"."slug" = %s LIMIT ? FOR UPDATE
- 45x in test_is_idempotent_and_refreshes_unposted_content: SELECT "confs_conferencetag"."id", "confs_conferencetag"."name", "confs_conferencetag"."slug", "confs_conferencetag"."icon" FROM "confs_conferencetag" WHERE "confs_conferencetag"."slug" = %s LIMIT ? FOR UPDATE
- 45x in test_two_facets_are_noindex: SELECT "confs_conferencetag"."id", "confs_conferencetag"."name", "confs_conferencetag"."slug", "confs_conferencetag"."icon" FROM "confs_conferencetag" WHERE "confs_conferencetag"."slug" = %s LIMIT ? FOR UPDATE
- 44x in test_posts_from_yesterday_are_updated: SELECT COUNT(*) AS "__count" FROM "accounts_accountlookup" WHERE UPPER("accounts_accountlookup"."language"::text) LIKE UPPER(%s)
Most affected tests:
- accounts/tests.py::TestSelectedInstance::test_invalid_selected_instance
- confs/tests.py::TestMigratedLegacyConferences::test_fwd50_date_redirects
- confs/tests.py::TestSyncAnnouncements::test_is_idempotent_and_refreshes_unposted_content
- accounts/tests.py::TestAccountIndexRobots::test_two_facets_are_noindex
- stats/tests.py::TestStats::test_posts_from_yesterday_are_updated
- stats/tests.py::TestStats::test_store_daily_stats
- stats/tests.py::TestStats::test_store_daily_stats_with_accounts
- confs/tests.py::TestLegacyConferenceDataMigration::test_copies_overlapping_legacy_rows_without_clobbering_existing_data
Make the test database server skip durability work
Tests spend 40.6s (43%) in the database. Test databases don't need to survive a crash, so the server can skip flushing to disk.
Details
Only affects crash safety of the throwaway test server; query behaviour is identical.
Where:
- confs/tests.py:432 TestLegacyConferenceDataMigration._migrate · 1.33 s
- confs/migrations/0031_seed_conference_tags.py:14 seed_conference_tags · 761 ms
- starter_packs/tests.py:397 TestToggleStarterPackAccount.test_toggle_after_limit · 580 ms
- accounts/views.py:28 CountlessPage.__init__ · 335 ms
- starter_packs/views.py:60 get_editable_pack · 299 ms
- starter_packs/views.py:856 share_starter_pack · 285 ms
- starter_packs/views.py:858 share_starter_pack · 280 ms
- starter_packs/views.py:729 share_starter_pack · 265 ms
- stats/models.py:20 store_daily_stats · 252 ms
- starter_packs/views.py:862 share_starter_pack · 232 ms
Most affected tests:
- confs/tests.py::TestMigratedLegacyConferences::test_fwd50_date_redirects
- accounts/tests.py::TestSelectedInstance::test_invalid_selected_instance
- accounts/tests.py::TestAccountIndexRobots::test_two_facets_are_noindex
- confs/tests.py::TestSyncAnnouncements::test_is_idempotent_and_refreshes_unposted_content
- confs/tests.py::TestLegacyConferenceDataMigration::test_copies_overlapping_legacy_rows_without_clobbering_existing_data
- confs/tests.py::TestLegacyConferenceDataMigration::test_drops_legacy_tables_when_uniques_are_mysql_style_indexes
- starter_packs/tests.py::TestToggleStarterPackAccount::test_toggle_after_limit
- accounts/tests.py::TestInstanceIndexingBridgy::test_follows_redirect_and_coerces_null_version
pytest-xdist workers finish at very different times
The busiest worker ran 31.9s of tests, the least busy 20.3s.
Details
pytest takes a long time before the first test runs
Startup takes 8.5s and collection 3.5s on every run, even when you only run one test.
Details
- mastodon_auth/tests.py (1.5s)
- starter_packs/tests.py (338ms)
- accounts/tests.py (127ms)
- confs/tests.py (21ms)
- stats/tests.py (1ms)
- fedidevs/settings.py (2.1s)
- debug_toolbar/panels/sql/__init__.py (1.2s)
- starter_packs/admin.py (755ms)
Modules are imported while tests run
2.0s of test time is spent importing modules: whichever test imports a heavy module first pays for it, which makes that test look slow (and varies with test order).
Details
Where:
- confs/views.py:366 <module> · 176 ms
- accounts/views.py:425 index · 120 ms
- confs/management/commands/syncannouncements.py:14 Command.handle · 107 ms
- accounts/tests.py:550 TestAccountIndexRobots.assert_noindex · 82 ms
- accounts/management/commands/indexer.py:81 Command.handle · 74 ms
- fedidevs/views.py:11 <module> · 69 ms
- mastodon_auth/forms.py:27 MastodonLoginForm.clean_instance · 50 ms
- confs/views.py:296 _conference_detail · 44 ms
- confs/views.py:509 create_conference · 41 ms
- confs/og_images.py:246 render_conference_og_image · 39 ms
Most affected tests:
- accounts/tests.py::TestAccountIndexRobots::test_two_facets_are_noindex
- accounts/tests.py::TestSelectedInstance::test_invalid_selected_instance
- confs/tests.py::TestSyncAnnouncements::test_is_idempotent_and_refreshes_unposted_content
- confs/tests.py::TestMigratedLegacyConferences::test_fwd50_date_redirects
- confs/tests.py::TestConferenceOgImage::test_management_command_renders_missing_and_skips_current
- mastodon_auth/tests.py::MastodonLoginFormTests::test_cleans_instance_to_ascii_hostname
- confs/tests.py::TestMigratedLegacyConferences::test_fwd50_page
- confs/tests.py::TestCreateConference::test_form_renders_for_authenticated_user
Run migrations once, not once per worker
Each of the 4 pytest-xdist workers builds its own test database by running every migration: 25.8s in total, about 6.5s per worker. 19.4s of it repeats work another worker already did.
Details
Every copy is built by the same migrations, so a broken migration still fails the run.
- {'total': 25.805, 'builds': 4, 'workers': 4, 'per_build': 6.451}
Tests
201–308 of 308, slowest first · click a column to sort this pageMemory
Busiest worker peaked at 209 MB; all 4 together at about 662 MB| Worker | Tests | Peak | Grew by |
|---|---|---|---|
| gw0 | 85 | 189 MB | 46 MB |
| gw1 | 71 | 209 MB | 43 MB |
| gw2 | 35 | 183 MB | 42 MB |
| gw3 | 117 | 204 MB | 60 MB |
Slowest fixtures
Exact setup time across the session| Fixture | Scope | Calls | Total |
|---|---|---|---|
| _django_setup_unittest | class | 76 | 25.84 s |
| django_db_setup | session | 4 | 25.81 s |
| _unittest_setUpClass_fixture_TestSelectedInstance | class | 1 | 213 ms |
| _unittest_setUpClass_fixture_TestShareStarterPack | class | 3 | 209 ms |
| _unittest_setUpClass_fixture_TestStarterPacks | class | 2 | 99 ms |
| _unittest_setUpClass_fixture_TestFollowStarterPack | class | 2 | 94 ms |
| _unittest_setUpClass_fixture_TestOwnerManagement | class | 2 | 88 ms |
| _unittest_setUpClass_fixture_TestPinAccountInStarterPack | class | 2 | 85 ms |
| _unittest_setUpClass_fixture_TestEditStarterPackAccounts | class | 2 | 76 ms |
| _unittest_setUpClass_fixture_TestWebfingerBackfill | class | 1 | 72 ms |
| _unittest_setUpClass_fixture_TestFollowBg | class | 1 | 70 ms |
| _unittest_setUpClass_fixture_TestRemoteFollowStarterPack | class | 2 | 46 ms |
| _unittest_setUpClass_fixture_TestAddAccountsSearch | class | 1 | 42 ms |
| _unittest_setUpClass_fixture_TestConferenceOgImage | class | 1 | 35 ms |
| _unittest_setUpClass_fixture_TestToggleStarterPackAccount | class | 1 | 35 ms |