ac6ece75c9
- For the notifications page the unread and pinned notifications are gathered for doer those that and are ordered by the updated unix. MariaDB makes a bad decision (sometimes, for most users it does not make this decision) with this query, it uses the index for the `updated_unix` column to speed up this query, however this is not the correct index to be taking, if the doer does not have more than 20 (the page size) unread and pinned notifications combined MariaDB will traverse the whole notifications table before it realizes that there are no more notifications to be gathered. It instead should use the index for the `user_id` column (this is what MariaDB already does for most users), so the list that has to be traversed is limited to the doer's notifications which is significantly less than the whole notifications table. - This is a different approach than what Gitea has taken to solve this problem, which is to add a index to the (status, userid, updated_unix) tuple (Ref: https://github.com/go-gitea/gitea/pull/32395). Adding more and more indexes is not a good way if we can use existing indexes to get a query to a acceptable performance. - The code cannot use `db.Find` as it's hard to add a index hint option specifically for this query and not for the other instances that uses `activities_model.FindNotificationOptions`. - Only add a index hint for MySQL as I have not been able to test if SQLite or PostgreSQL are smart enough to use the better index (as you need a large enough dataset to test this meaningfully). - Integration test added to ensure the SQL is run by all databases. --- Performance numbers (from Codeberg's database - MariaDB 10.11.6-MariaDB-0+deb12u1): Currently: ```sql SELECT * FROM `notification` WHERE notification.user_id=26734 AND (notification.status=3 OR notification.status=1) ORDER BY notification.updated_unix DESC LIMIT 20; (5.731 sec) +------+-------------+--------------+-------+--------------------------------------------------+-------------------------------+---------+-------+---------+------------+----------+------------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | r_rows | filtered | r_filtered | Extra | +------+-------------+--------------+-------+--------------------------------------------------+-------------------------------+---------+-------+---------+------------+----------+------------+-------------+ | 1 | SIMPLE | notification | index | IDX_notification_status,IDX_notification_user_id | IDX_notification_updated_unix | 8 | const | 1376836 | 1474066.00 | 50.03 | 0.00 | Using where | +------+-------------+--------------+-------+--------------------------------------------------+-------------------------------+---------+-------+---------+------------+----------+------------+-------------+ ``` Using the better index: ```sql SELECT * FROM `notification` USE INDEX (IDX_notification_user_id) WHERE notification.user_id=26734 AND (notification.status=3 OR notification.status=1) ORDER BY notification.updated_unix DESC LIMIT 20; (0.834 sec) +------+-------------+--------------+--------+----------------------------------------------------------+--------------------------+---------+----------------------------------+-------+----------+----------+------------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | r_rows | filtered | r_filtered | Extra | +------+-------------+--------------+--------+----------------------------------------------------------+--------------------------+---------+----------------------------------+-------+----------+----------+------------+----------------------------------------------+ | 1 | PRIMARY | notification | ref | PRIMARY,IDX_notification_status,IDX_notification_user_id | IDX_notification_user_id | 8 | const | 22042 | 10756.00 | 50.03 | 0.02 | Using where; Using temporary; Using filesort | | 1 | PRIMARY | notification | eq_ref | PRIMARY | PRIMARY | 8 | gitea_production.notification.id | 1 | 1.00 | 100.00 | 100.00 | | +------+-------------+--------------+--------+----------------------------------------------------------+--------------------------+---------+----------------------------------+-------+----------+----------+------------+----------------------------------------------+ ``` |
||
---|---|---|
.. | ||
fixtures | ||
migration-test | ||
schemas | ||
actions_commit_status_test.go | ||
actions_route_test.go | ||
actions_trigger_test.go | ||
admin_config_test.go | ||
admin_user_test.go | ||
api_actions_artifact_test.go | ||
api_actions_artifact_v4_test.go | ||
api_activitypub_actor_test.go | ||
api_activitypub_person_test.go | ||
api_activitypub_repository_test.go | ||
api_admin_org_test.go | ||
api_admin_test.go | ||
api_block_test.go | ||
api_branch_test.go | ||
api_comment_attachment_test.go | ||
api_comment_test.go | ||
api_feed_plain_text_titles_test.go | ||
api_feed_user_test.go | ||
api_forgejo_root_test.go | ||
api_forgejo_version_test.go | ||
api_fork_test.go | ||
api_gitignore_templates_test.go | ||
api_gpg_keys_test.go | ||
api_health_test.go | ||
api_helper_for_declarative_test.go | ||
api_httpsig_test.go | ||
api_issue_attachment_test.go | ||
api_issue_config_test.go | ||
api_issue_label_test.go | ||
api_issue_milestone_test.go | ||
api_issue_pin_test.go | ||
api_issue_reaction_test.go | ||
api_issue_stopwatch_test.go | ||
api_issue_subscription_test.go | ||
api_issue_templates_test.go | ||
api_issue_test.go | ||
api_issue_tracked_time_test.go | ||
api_keys_test.go | ||
api_label_templates_test.go | ||
api_license_templates_test.go | ||
api_nodeinfo_test.go | ||
api_notification_test.go | ||
api_oauth2_apps_test.go | ||
api_org_avatar_test.go | ||
api_org_test.go | ||
api_packages_alpine_test.go | ||
api_packages_arch_test.go | ||
api_packages_cargo_test.go | ||
api_packages_chef_test.go | ||
api_packages_composer_test.go | ||
api_packages_conan_test.go | ||
api_packages_conda_test.go | ||
api_packages_container_cleanup_sha256_test.go | ||
api_packages_container_test.go | ||
api_packages_cran_test.go | ||
api_packages_debian_test.go | ||
api_packages_generic_test.go | ||
api_packages_goproxy_test.go | ||
api_packages_helm_test.go | ||
api_packages_maven_test.go | ||
api_packages_npm_test.go | ||
api_packages_nuget_test.go | ||
api_packages_pub_test.go | ||
api_packages_pypi_test.go | ||
api_packages_rpm_test.go | ||
api_packages_rubygems_test.go | ||
api_packages_swift_test.go | ||
api_packages_test.go | ||
api_packages_vagrant_test.go | ||
api_private_serv_test.go | ||
api_pull_commits_test.go | ||
api_pull_review_test.go | ||
api_pull_test.go | ||
api_push_mirror_test.go | ||
api_quota_management_test.go | ||
api_quota_use_test.go | ||
api_releases_test.go | ||
api_repo_activities_test.go | ||
api_repo_archive_test.go | ||
api_repo_avatar_test.go | ||
api_repo_branch_test.go | ||
api_repo_collaborator_test.go | ||
api_repo_compare_test.go | ||
api_repo_edit_test.go | ||
api_repo_file_create_test.go | ||
api_repo_file_delete_test.go | ||
api_repo_file_get_test.go | ||
api_repo_file_helpers.go | ||
api_repo_file_update_test.go | ||
api_repo_files_change_test.go | ||
api_repo_get_contents_list_test.go | ||
api_repo_get_contents_test.go | ||
api_repo_git_blobs_test.go | ||
api_repo_git_commits_test.go | ||
api_repo_git_hook_test.go | ||
api_repo_git_notes_test.go | ||
api_repo_git_ref_test.go | ||
api_repo_git_tags_test.go | ||
api_repo_git_trees_test.go | ||
api_repo_hook_test.go | ||
api_repo_languages_test.go | ||
api_repo_lfs_locks_test.go | ||
api_repo_lfs_migrate_test.go | ||
api_repo_lfs_test.go | ||
api_repo_raw_test.go | ||
api_repo_secrets_test.go | ||
api_repo_tags_test.go | ||
api_repo_teams_test.go | ||
api_repo_test.go | ||
api_repo_topic_test.go | ||
api_repo_variables_test.go | ||
api_settings_test.go | ||
api_team_test.go | ||
api_team_user_test.go | ||
api_token_test.go | ||
api_twofa_test.go | ||
api_user_avatar_test.go | ||
api_user_email_test.go | ||
api_user_follow_test.go | ||
api_user_heatmap_test.go | ||
api_user_info_test.go | ||
api_user_org_perm_test.go | ||
api_user_orgs_test.go | ||
api_user_search_test.go | ||
api_user_secrets_test.go | ||
api_user_star_test.go | ||
api_user_variables_test.go | ||
api_user_watch_test.go | ||
api_wiki_test.go | ||
archived_labels_display_test.go | ||
attachment_test.go | ||
auth_ldap_test.go | ||
auth_token_test.go | ||
avatar.png | ||
benchmarks_test.go | ||
block_test.go | ||
branches_test.go | ||
change_default_branch_test.go | ||
cmd_admin_test.go | ||
cmd_forgejo_actions_test.go | ||
cmd_forgejo_f3_test.go | ||
cmd_keys_test.go | ||
codeowner_test.go | ||
commit_status_test.go | ||
compare_test.go | ||
cors_test.go | ||
create_no_session_test.go | ||
csrf_test.go | ||
db_collation_test.go | ||
delete_user_test.go | ||
doctor_packages_nuget_test.go | ||
download_test.go | ||
dummy_lang_test.go | ||
dump_restore_test.go | ||
easymde_test.go | ||
editor_test.go | ||
empty_repo_test.go | ||
eventsource_test.go | ||
explore_code_test.go | ||
explore_repos_test.go | ||
explore_user_test.go | ||
forgejo_confirmation_repo_test.go | ||
forgejo_git_test.go | ||
git_clone_wiki_test.go | ||
git_helper_for_declarative_test.go | ||
git_push_test.go | ||
git_smart_http_test.go | ||
git_test.go | ||
goget_test.go | ||
gpg_git_test.go | ||
html_helper.go | ||
incoming_email_test.go | ||
integration_test.go | ||
issue_subscribe_test.go | ||
issue_test.go | ||
issues_comment_labels_test.go | ||
last_updated_time_test.go | ||
lfs_getobject_test.go | ||
lfs_local_endpoint_test.go | ||
lfs_view_test.go | ||
linguist_test.go | ||
links_test.go | ||
markup_external_test.go | ||
markup_test.go | ||
mention_test.go | ||
migrate_test.go | ||
milestone_test.go | ||
mirror_pull_test.go | ||
mirror_push_test.go | ||
new_org_test.go | ||
nonascii_branches_test.go | ||
notification_test.go | ||
oauth_test.go | ||
opengraph_test.go | ||
org_count_test.go | ||
org_nav_test.go | ||
org_project_test.go | ||
org_settings_test.go | ||
org_team_invite_test.go | ||
org_test.go | ||
private-testing.key | ||
privateactivity_test.go | ||
proctected_branch_test.go | ||
project_test.go | ||
pull_commit_test.go | ||
pull_compare_test.go | ||
pull_create_test.go | ||
pull_diff_test.go | ||
pull_icon_test.go | ||
pull_merge_test.go | ||
pull_reopen_test.go | ||
pull_request_task_test.go | ||
pull_review_test.go | ||
pull_status_test.go | ||
pull_summary_test.go | ||
pull_test.go | ||
pull_update_test.go | ||
pull_wip_convert_test.go | ||
quota_use_test.go | ||
README.md | ||
release_test.go | ||
remote_test.go | ||
rename_branch_test.go | ||
repo_activity_test.go | ||
repo_archive_test.go | ||
repo_archive_text_test.go | ||
repo_badges_test.go | ||
repo_branch_test.go | ||
repo_citation_test.go | ||
repo_collaborator_test.go | ||
repo_commits_search_test.go | ||
repo_commits_test.go | ||
repo_delete_test.go | ||
repo_flags_test.go | ||
repo_fork_test.go | ||
repo_generate_test.go | ||
repo_git_note_test.go | ||
repo_issue_title_test.go | ||
repo_mergecommit_revert_test.go | ||
repo_migrate_test.go | ||
repo_migration_ui_test.go | ||
repo_pagination_test.go | ||
repo_search_test.go | ||
repo_settings_hook_test.go | ||
repo_settings_test.go | ||
repo_signed_tag_test.go | ||
repo_starwatch_test.go | ||
repo_tag_test.go | ||
repo_test.go | ||
repo_topic_test.go | ||
repo_view_test.go | ||
repo_watch_test.go | ||
repo_webhook_test.go | ||
repo_wiki_test.go | ||
repofiles_change_test.go | ||
session_test.go | ||
setting_test.go | ||
signin_test.go | ||
signout_test.go | ||
signup_test.go | ||
size_translations_test.go | ||
ssh_key_test.go | ||
swagger_test.go | ||
timetracking_test.go | ||
user_avatar_test.go | ||
user_count_test.go | ||
user_dashboard_test.go | ||
user_profile_activity_test.go | ||
user_profile_follows_test.go | ||
user_profile_test.go | ||
user_test.go | ||
version_test.go | ||
view_test.go | ||
webfinger_test.go | ||
webhook_test.go | ||
xss_test.go |
Integration tests
Thank you for your effort to provide good software tests for Forgejo. Please also read the general testing instructions in the Forgejo contributor documentation.
This file is meant to provide specific information for the integration tests as well as some tips and tricks you should know.
Feel free to extend this file with more instructions if you feel like you have something to share!
How to run the tests?
Before running any tests, please ensure you perform a clean build:
make clean build
Integration tests can be run with make commands for the appropriate backends, namely:
make test-sqlite
make test-pgsql
make test-mysql
Run tests via local forgejo runner
If you have a forgejo runner, you can use it to run the test jobs:
Run all jobs
forgejo-runner exec -W .forgejo/workflows/testing.yml --event=pull_request
Warning: This file defines many jobs, so it will be resource-intensive and therefore not recommended.
Run single job
forgejo-runner exec -W .forgejo/workflows/testing.yml --event=pull_request -j <job_name>
You can list all job names via:
forgejo-runner exec -W .forgejo/workflows/testing.yml --event=pull_request -l
Run sqlite integration tests
Start tests
make test-sqlite
Run MySQL integration tests
Setup a MySQL database inside docker
docker run -e MYSQL_DATABASE=test -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -p 3306:3306 --rm --name mysql mysql:latest #(Ctrl-c to stop the database)
Start tests based on the database container
TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test?multiStatements=true TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-mysql
Run pgsql integration tests
Setup a pgsql database inside docker
docker run -e "POSTGRES_DB=test" -e POSTGRES_PASSWORD=postgres -p 5432:5432 --rm --name pgsql postgres:latest #(Ctrl-c to stop the database)
Start tests based on the database container
TEST_STORAGE_TYPE=local TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
Running individual tests
Example command to run GPG test:
For SQLite:
make test-sqlite#GPG
For other databases (replace mysql
to pgsql
):
TEST_MYSQL_HOST=localhost:1433 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=sa TEST_MYSQL_PASSWORD=MwantsaSecurePassword1 make test-mysql#GPG
Setting timeouts for declaring long-tests and long-flushes
We appreciate that some testing machines may not be very powerful and the default timeouts for declaring a slow test or a slow clean-up flush may not be appropriate.
You can either:
- Within the test ini file set the following section:
[integration-tests]
SLOW_TEST = 10s ; 10s is the default value
SLOW_FLUSH = 5S ; 5s is the default value
- Set the following environment variables:
GITEA_SLOW_TEST_TIME="10s" GITEA_SLOW_FLUSH_TIME="5s" make test-sqlite
Tips and tricks
If you know noteworthy tests that can act as an inspiration for new tests, please add some details here.