diff options
47 files changed, 197 insertions, 154 deletions
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb index 99c48186fba..1d6711e3c22 100644 --- a/app/controllers/boards/issues_controller.rb +++ b/app/controllers/boards/issues_controller.rb @@ -27,17 +27,7 @@ module Boards issues = list_service.execute issues = issues.page(params[:page]).per(params[:per] || 20).without_count Issue.move_nulls_to_end(issues) if Gitlab::Database.read_write? - issues = issues.preload(:milestone, - :assignees, - project: [ - :route, - { - namespace: [:route] - } - ], - labels: [:priorities], - notes: [:award_emoji, :author] - ) + issues = issues.preload(associations_to_preload) render_issues(issues, list_service.metadata) end @@ -74,6 +64,21 @@ module Boards private + def associations_to_preload + [ + :milestone, + :assignees, + project: [ + :route, + { + namespace: [:route] + } + ], + labels: [:priorities], + notes: [:award_emoji, :author] + ] + end + def can_move_issues? head(:forbidden) unless can?(current_user, :admin_issue, board) end @@ -139,3 +144,5 @@ module Boards end end end + +Boards::IssuesController.prepend_if_ee('EE::Boards::IssuesController') diff --git a/changelogs/unreleased/ab-projects-api-indexes-authenticated-calls.yml b/changelogs/unreleased/ab-projects-api-indexes-authenticated-calls.yml new file mode 100644 index 00000000000..1bfa3b87a88 --- /dev/null +++ b/changelogs/unreleased/ab-projects-api-indexes-authenticated-calls.yml @@ -0,0 +1,5 @@ +--- +title: Add indexes for authenticated Project API calls +merge_request: 22886 +author: +type: performance diff --git a/db/migrate/20200113133352_add_indexes_for_projects_api_authenticated.rb b/db/migrate/20200113133352_add_indexes_for_projects_api_authenticated.rb new file mode 100644 index 00000000000..53d317b3321 --- /dev/null +++ b/db/migrate/20200113133352_add_indexes_for_projects_api_authenticated.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class AddIndexesForProjectsApiAuthenticated < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + COLUMNS = %i(updated_at name) + + def up + add_concurrent_index :projects, %i(created_at id), order: { id: :desc }, name: 'index_projects_api_created_at_id_desc' + + add_concurrent_index :projects, %i(last_activity_at id), name: 'index_projects_on_last_activity_at_and_id' + remove_concurrent_index :projects, :last_activity_at + add_concurrent_index :projects, %i(last_activity_at id), order: { id: :desc }, name: 'index_projects_api_last_activity_at_id_desc' + + add_concurrent_index :projects, %i(path id), name: 'index_projects_on_path_and_id' + remove_concurrent_index_by_name :projects, 'index_projects_on_path' + add_concurrent_index :projects, %i(path id), order: { id: :desc }, name: 'index_projects_api_path_id_desc' + + COLUMNS.each do |column| + add_concurrent_index :projects, [column, :id], name: "index_projects_on_#{column}_and_id" + add_concurrent_index :projects, [column, :id], order: { id: :desc }, name: "index_projects_api_#{column}_id_desc" + end + end + + def down + remove_concurrent_index_by_name :projects, 'index_projects_api_created_at_id_desc' + + remove_concurrent_index_by_name :projects, 'index_projects_on_last_activity_at_and_id' + add_concurrent_index :projects, :last_activity_at, name: 'index_projects_on_last_activity_at' + remove_concurrent_index_by_name :projects, 'index_projects_api_last_activity_at_id_desc' + + remove_concurrent_index_by_name :projects, 'index_projects_on_path_and_id' + add_concurrent_index :projects, :path, name: 'index_projects_on_path' + remove_concurrent_index_by_name :projects, 'index_projects_api_path_id_desc' + + COLUMNS.each do |column| + remove_concurrent_index_by_name :projects, "index_projects_on_#{column}_and_id" + remove_concurrent_index_by_name :projects, "index_projects_api_#{column}_id_desc" + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c2c5bb43c5e..16b8bf9dda8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_01_10_144316) do +ActiveRecord::Schema.define(version: 2020_01_13_133352) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -3353,6 +3353,7 @@ ActiveRecord::Schema.define(version: 2020_01_10_144316) do t.boolean "autoclose_referenced_issues" t.string "suggestion_commit_message", limit: 255 t.index "lower((name)::text)", name: "index_projects_on_lower_name" + t.index ["created_at", "id"], name: "index_projects_api_created_at_id_desc", order: { id: :desc } t.index ["created_at", "id"], name: "index_projects_api_vis20_created_at", where: "(visibility_level = 20)" t.index ["created_at", "id"], name: "index_projects_api_vis20_created_at_id_desc", order: { id: :desc }, where: "(visibility_level = 20)" t.index ["created_at", "id"], name: "index_projects_on_created_at_and_id" @@ -3362,9 +3363,10 @@ ActiveRecord::Schema.define(version: 2020_01_10_144316) do t.index ["id"], name: "index_on_id_partial_with_legacy_storage", where: "((storage_version < 2) OR (storage_version IS NULL))" t.index ["id"], name: "index_projects_on_id_partial_for_visibility", unique: true, where: "(visibility_level = ANY (ARRAY[10, 20]))" t.index ["id"], name: "index_projects_on_mirror_and_mirror_trigger_builds_both_true", where: "((mirror IS TRUE) AND (mirror_trigger_builds IS TRUE))" + t.index ["last_activity_at", "id"], name: "index_projects_api_last_activity_at_id_desc", order: { id: :desc } t.index ["last_activity_at", "id"], name: "index_projects_api_vis20_last_activity_at", where: "(visibility_level = 20)" t.index ["last_activity_at", "id"], name: "index_projects_api_vis20_last_activity_at_id_desc", order: { id: :desc }, where: "(visibility_level = 20)" - t.index ["last_activity_at"], name: "index_projects_on_last_activity_at" + t.index ["last_activity_at", "id"], name: "index_projects_on_last_activity_at_and_id" t.index ["last_repository_check_at"], name: "index_projects_on_last_repository_check_at", where: "(last_repository_check_at IS NOT NULL)" t.index ["last_repository_check_failed"], name: "index_projects_on_last_repository_check_failed" t.index ["last_repository_updated_at"], name: "index_projects_on_last_repository_updated_at" @@ -3372,13 +3374,16 @@ ActiveRecord::Schema.define(version: 2020_01_10_144316) do t.index ["marked_for_deletion_by_user_id"], name: "index_projects_on_marked_for_deletion_by_user_id", where: "(marked_for_deletion_by_user_id IS NOT NULL)" t.index ["mirror_last_successful_update_at"], name: "index_projects_on_mirror_last_successful_update_at" t.index ["mirror_user_id"], name: "index_projects_on_mirror_user_id" + t.index ["name", "id"], name: "index_projects_api_name_id_desc", order: { id: :desc } t.index ["name", "id"], name: "index_projects_api_vis20_name", where: "(visibility_level = 20)" t.index ["name", "id"], name: "index_projects_api_vis20_name_id_desc", order: { id: :desc }, where: "(visibility_level = 20)" + t.index ["name", "id"], name: "index_projects_on_name_and_id" t.index ["name"], name: "index_projects_on_name_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["namespace_id"], name: "index_projects_on_namespace_id" + t.index ["path", "id"], name: "index_projects_api_path_id_desc", order: { id: :desc } t.index ["path", "id"], name: "index_projects_api_vis20_path", where: "(visibility_level = 20)" t.index ["path", "id"], name: "index_projects_api_vis20_path_id_desc", order: { id: :desc }, where: "(visibility_level = 20)" - t.index ["path"], name: "index_projects_on_path" + t.index ["path", "id"], name: "index_projects_on_path_and_id" t.index ["path"], name: "index_projects_on_path_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["pending_delete"], name: "index_projects_on_pending_delete" t.index ["pool_repository_id"], name: "index_projects_on_pool_repository_id", where: "(pool_repository_id IS NOT NULL)" @@ -3387,8 +3392,10 @@ ActiveRecord::Schema.define(version: 2020_01_10_144316) do t.index ["runners_token"], name: "index_projects_on_runners_token" t.index ["runners_token_encrypted"], name: "index_projects_on_runners_token_encrypted" t.index ["star_count"], name: "index_projects_on_star_count" + t.index ["updated_at", "id"], name: "index_projects_api_updated_at_id_desc", order: { id: :desc } t.index ["updated_at", "id"], name: "index_projects_api_vis20_updated_at", where: "(visibility_level = 20)" t.index ["updated_at", "id"], name: "index_projects_api_vis20_updated_at_id_desc", order: { id: :desc }, where: "(visibility_level = 20)" + t.index ["updated_at", "id"], name: "index_projects_on_updated_at_and_id" end create_table "prometheus_alert_events", force: :cascade do |t| diff --git a/doc/development/logging.md b/doc/development/logging.md index ea099de21d5..202c7a5ce9f 100644 --- a/doc/development/logging.md +++ b/doc/development/logging.md @@ -209,6 +209,36 @@ I, [2020-01-13T19:01:17.091Z #11056] INFO -- : {"message"=>"Message", "project_ {:severity=>"INFO", :time=>"2020-01-13T11:06:09.851Z", :correlation_id=>"d7e0886f096db9a8526a4f89da0e45f6", :message=>"This is my message", :project_id=>123} ``` +### Logging context metadata (through Rails or Grape requests) + +`Gitlab::ApplicationContext` stores metadata in a request +lifecycle, which can then be added to the web request +or Sidekiq logs. + +Entry points can be seen at: + +- [`ApplicationController`](https://gitlab.com/gitlab-org/gitlab/blob/master/app/controllers/application_controller.rb) +- [External API](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/api/api.rb) +- [Internal API](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/api/internal/base.rb) + +#### Adding attributes + +When adding new attributes, make sure they're exposed within the context of the entry points above and: + +- Pass them within the hash to the `with_context` (or `push`) method (make sure to pass a Proc if the +method or variable shouldn't be evaluated right away) +- Change `Gitlab::ApplicationContext` to accept these new values +- Make sure the new attributes are accepted at [`Labkit::Context`](https://gitlab.com/gitlab-org/labkit-ruby/blob/master/lib/labkit/context.rb) + +See our [HOWTO: Use Sidekiq metadata logs](https://www.youtube.com/watch?v=_wDllvO_IY0) for further knowledge on +creating visualizations in Kibana. + +**Note:** +The fields of the context are currently only logged for Sidekiq jobs triggered +through web requests. See the +[follow-up work](https://gitlab.com/gitlab-com/gl-infra/scalability/issues/68) +for more information. + ## Exception Handling It often happens that you catch the exception and want to track it. diff --git a/qa/load/artillery.yml b/qa/load/artillery.yml deleted file mode 100644 index 17d253ec480..00000000000 --- a/qa/load/artillery.yml +++ /dev/null @@ -1,25 +0,0 @@ -config: - target: "{{ $processEnvironment.HOST_URL }}" - http: - pool: 10 # All HTTP requests from all virtual users will be sent over the same <pool> connections. - # This also means that there is a limit on the number of requests sent per second. - phases: - - duration: 30 - arrivalRate: 10 - name: "Warm up" - - duration: 90 - arrivalRate: 10 - rampTo: 100 - name: "Gradual ramp up" - - duration: 90 - arrivalRate: 100 - name: "Sustained max load" -scenarios: - - name: "Visit large issue url" - flow: - - get: - url: "{{ $processEnvironment.LARGE_ISSUE_URL }}" - - name: "Visit large MR url" - flow: - - get: - url: "{{ $processEnvironment.LARGE_MR_URL }}" diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 29946791df7..a4c44f78ad4 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -26,8 +26,8 @@ module QA wait_for_requests end - def wait(max: 60, interval: 0.1, reload: true, raise_on_failure: false) - Support::Waiter.wait_until(max_duration: max, sleep_interval: interval, raise_on_failure: raise_on_failure) do + def wait_until(max_duration: 60, sleep_interval: 0.1, reload: true, raise_on_failure: false) + Support::Waiter.wait_until(max_duration: max_duration, sleep_interval: sleep_interval, raise_on_failure: raise_on_failure) do yield || (reload && refresh && false) end end @@ -71,7 +71,7 @@ module QA xhr.send(); JS - return false unless wait(interval: 0.5, max: 60, reload: false) do + return false unless wait_until(sleep_interval: 0.5, max_duration: 60, reload: false) do page.evaluate_script('xhr.readyState == XMLHttpRequest.DONE') end @@ -115,8 +115,8 @@ module QA end # replace with (..., page = self.class) - def click_element(name, page = nil, text: nil) - find_element(name, text: text).click + def click_element(name, page = nil, text: nil, wait: Capybara.default_max_wait_time) + find_element(name, text: text, wait: wait).click page.validate_elements_present! if page end @@ -161,10 +161,10 @@ module QA page.has_text?(text, wait: wait) end - def has_no_text?(text) + def has_no_text?(text, wait: Capybara.default_max_wait_time) wait_for_requests - page.has_no_text? text + page.has_no_text?(text, wait: wait) end def has_normalized_ws_text?(text, wait: Capybara.default_max_wait_time) @@ -191,7 +191,7 @@ module QA # This loop gives time for the img tags to be rendered and for # images to start loading. previous_total_images = 0 - wait(interval: 1) do + wait_until(sleep_interval: 1) do current_total_images = all("img").size result = previous_total_images == current_total_images previous_total_images = current_total_images diff --git a/qa/qa/page/component/ci_badge_link.rb b/qa/qa/page/component/ci_badge_link.rb index aad8dc1d3df..d3e44fd867d 100644 --- a/qa/qa/page/component/ci_badge_link.rb +++ b/qa/qa/page/component/ci_badge_link.rb @@ -26,7 +26,7 @@ module QA private def completed?(timeout: 60) - wait(reload: false, max: timeout) do + wait_until(reload: false, max_duration: timeout) do COMPLETED_STATUSES.include?(status_badge) end end diff --git a/qa/qa/page/component/clone_panel.rb b/qa/qa/page/component/clone_panel.rb index b80877f5ecd..fbe19e5802b 100644 --- a/qa/qa/page/component/clone_panel.rb +++ b/qa/qa/page/component/clone_panel.rb @@ -24,7 +24,7 @@ module QA private def repository_clone_location(kind) - wait(reload: false) do + wait_until(reload: false) do click_element :clone_dropdown within_element :clone_options do diff --git a/qa/qa/page/component/dropdown_filter.rb b/qa/qa/page/component/dropdown_filter.rb index e896c382779..a39a04a668d 100644 --- a/qa/qa/page/component/dropdown_filter.rb +++ b/qa/qa/page/component/dropdown_filter.rb @@ -5,9 +5,7 @@ module QA module Component module DropdownFilter def filter_and_select(item) - wait(reload: false) do - page.has_css?('.dropdown-input-field') - end + page.has_css?('.dropdown-input-field', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) find('.dropdown-input-field').set(item) click_link item diff --git a/qa/qa/page/component/dropzone.rb b/qa/qa/page/component/dropzone.rb index 757111f240b..2efb96a02bc 100644 --- a/qa/qa/page/component/dropzone.rb +++ b/qa/qa/page/component/dropzone.rb @@ -23,7 +23,7 @@ module QA page.attach_file(attachment, class: 'dz-hidden-input', make_visible: field_style) # Wait for link to be appended to dropzone text - page.wait(reload: false) do + page.wait_until(reload: false) do page.find("#{container} textarea").value.match(filename) end end diff --git a/qa/qa/page/component/groups_filter.rb b/qa/qa/page/component/groups_filter.rb index cc50bb439b4..7eb1257db71 100644 --- a/qa/qa/page/component/groups_filter.rb +++ b/qa/qa/page/component/groups_filter.rb @@ -23,9 +23,7 @@ module QA # Since we submitted after filtering, the presence of # groups_list_tree_container means we have the complete filtered list # of groups - wait(reload: false) do - page.has_css?(element_selector_css(:groups_list_tree_container)) - end + has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) # If there are no groups we'll know immediately because we filtered the list return false if page.has_text?('No groups or projects matched your search', wait: 0) diff --git a/qa/qa/page/component/legacy_clone_panel.rb b/qa/qa/page/component/legacy_clone_panel.rb index e495cf4ef04..7b4b30623a6 100644 --- a/qa/qa/page/component/legacy_clone_panel.rb +++ b/qa/qa/page/component/legacy_clone_panel.rb @@ -30,7 +30,7 @@ module QA private def choose_repository_clone(kind, detect_text) - wait(reload: false) do + wait_until(reload: false) do click_element :clone_dropdown page.within('.clone-options-dropdown') do diff --git a/qa/qa/page/file/shared/commit_button.rb b/qa/qa/page/file/shared/commit_button.rb index 559b4c6ceea..9ea4f4e7818 100644 --- a/qa/qa/page/file/shared/commit_button.rb +++ b/qa/qa/page/file/shared/commit_button.rb @@ -14,7 +14,7 @@ module QA def commit_changes click_element(:commit_button) - wait(reload: false, max: 60) do + wait_until(reload: false, max_duration: 60) do finished_loading? end end diff --git a/qa/qa/page/group/show.rb b/qa/qa/page/group/show.rb index e1f319da134..7639def98b7 100644 --- a/qa/qa/page/group/show.rb +++ b/qa/qa/page/group/show.rb @@ -58,7 +58,7 @@ module QA QA::Support::Retrier.retry_on_exception(sleep_interval: 1.0) do within_element(:new_project_or_subgroup_dropdown) do # May need to click again because it is possible to click the button quicker than the JS is bound - wait(reload: false) do + wait_until(reload: false) do click_element :new_project_or_subgroup_dropdown_toggle has_element?(kind) diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb index 85c859b6bb2..ad5b3c97cb9 100644 --- a/qa/qa/page/merge_request/show.rb +++ b/qa/qa/page/merge_request/show.rb @@ -73,7 +73,7 @@ module QA end def add_comment_to_diff(text) - wait(interval: 5) do + wait_until(sleep_interval: 5) do has_text?("No newline at end of file") end all_elements(:new_diff_line, minimum: 1).first.hover @@ -140,12 +140,12 @@ module QA def mark_to_squash # The squash checkbox is disabled on load - wait do + wait_until do has_element?(:squash_checkbox) end # The squash checkbox is enabled via JS - wait(reload: false) do + wait_until(reload: false) do !find_element(:squash_checkbox).disabled? end @@ -164,30 +164,30 @@ module QA def ready_to_merge? # The merge button is disabled on load - wait do + wait_until do has_element?(:merge_button) end # The merge button is enabled via JS - wait(reload: false) do + wait_until(reload: false) do !find_element(:merge_button).disabled? end end def rebase! # The rebase button is disabled on load - wait do + wait_until do has_element?(:mr_rebase_button) end # The rebase button is enabled via JS - wait(reload: false) do + wait_until(reload: false) do !find_element(:mr_rebase_button).disabled? end click_element :mr_rebase_button - success = wait do + success = wait_until do has_text?('Fast-forward merge without a merge commit') end @@ -209,7 +209,7 @@ module QA end def wait_for_merge_request_error_message - wait(max: 30, reload: false) do + wait_until(max_duration: 30, reload: false) do has_element?(:merge_request_error_content) end end diff --git a/qa/qa/page/project/branches/show.rb b/qa/qa/page/project/branches/show.rb index 480fc7d78cb..63021df30f6 100644 --- a/qa/qa/page/project/branches/show.rb +++ b/qa/qa/page/project/branches/show.rb @@ -29,7 +29,7 @@ module QA end def has_no_branch?(branch_name, reload: false) - wait(reload: reload) do + wait_until(reload: reload) do within_element(:all_branches) do has_no_element?(:branch_name, text: branch_name) end diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb index e73db92de42..b533e0096a8 100644 --- a/qa/qa/page/project/import/github.rb +++ b/qa/qa/page/project/import/github.rb @@ -35,7 +35,7 @@ module QA private def within_repo_path(full_path) - wait(reload: false) do + wait_until(reload: false) do has_element?(:project_import_row, text: full_path) end @@ -67,7 +67,7 @@ module QA end def wait_for_success - wait(max: 60, interval: 1.0, reload: false) do + wait_until(max_duration: 60, sleep_interval: 1.0, reload: false) do page.has_content?('Done', wait: 1.0) end end diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index adfd31e2a7d..a1e1bb4bc98 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -89,9 +89,7 @@ module QA end def has_comment?(comment_text) - wait(reload: false) do - has_element?(:noteable_note_item, text: comment_text) - end + has_element?(:noteable_note_item, text: comment_text, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) end def more_assignees_link @@ -155,7 +153,7 @@ module QA def wait_assignees_block_finish_loading within_element(:assignee_block) do - wait(reload: false, max: 10, interval: 1) do + wait_until(reload: false, max_duration: 10, sleep_interval: 1) do finished_loading_block? yield end diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb index 451ac8069e5..07dea3449f1 100644 --- a/qa/qa/page/project/job/show.rb +++ b/qa/qa/page/project/job/show.rb @@ -24,7 +24,7 @@ module QA::Page def output(wait: 5) result = '' - wait(reload: false, max: wait, interval: 1) do + wait_until(reload: false, max_duration: wait, sleep_interval: 1) do result = find_element(:job_log_content).text result.include?('Job') @@ -36,7 +36,7 @@ module QA::Page private def loaded?(wait: 60) - wait(reload: true, max: wait, interval: 1) do + wait_until(reload: true, max_duration: wait, sleep_interval: 1) do has_element?(:job_log_content, wait: 1) end end diff --git a/qa/qa/page/project/operations/environments/index.rb b/qa/qa/page/project/operations/environments/index.rb index 610a34385b1..6b46fa4985a 100644 --- a/qa/qa/page/project/operations/environments/index.rb +++ b/qa/qa/page/project/operations/environments/index.rb @@ -11,9 +11,7 @@ module QA end def click_environment_link(environment_name) - wait(reload: false) do - find(element_selector_css(:environment_link), text: environment_name).click - end + click_element(:environment_link, text: environment_name) end end end diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb index 269d4dfc411..684ad4a59d5 100644 --- a/qa/qa/page/project/pipeline/index.rb +++ b/qa/qa/page/project/pipeline/index.rb @@ -18,7 +18,7 @@ module QA::Page end def wait_for_latest_pipeline_success - wait(reload: false, max: 300) do + wait_until(reload: false, max_duration: 300) do within_element_by_index(:pipeline_commit_status, 0) do has_text?('passed') end diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb index fd29c5eacdc..45fffbf6000 100644 --- a/qa/qa/page/project/pipeline/show.rb +++ b/qa/qa/page/project/pipeline/show.rb @@ -67,13 +67,7 @@ module QA::Page end def click_on_first_job - css = '.js-pipeline-graph-job-link' - - wait(reload: false) do - has_css?(css) - end - - first(css).click + first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click end end end diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb index ff61e2d2c0c..64a182e5b3a 100644 --- a/qa/qa/page/project/settings/ci_variables.rb +++ b/qa/qa/page/project/settings/ci_variables.rb @@ -55,7 +55,7 @@ module QA private def toggle_masked(masked_node, masked) - wait(reload: false) do + wait_until(reload: false) do masked_node.click masked ? masked_enabled?(masked_node) : masked_disabled?(masked_node) diff --git a/qa/qa/page/project/settings/deploy_keys.rb b/qa/qa/page/project/settings/deploy_keys.rb index 12d7c0a396e..c330d090ce6 100644 --- a/qa/qa/page/project/settings/deploy_keys.rb +++ b/qa/qa/page/project/settings/deploy_keys.rb @@ -56,9 +56,7 @@ module QA private def within_project_deploy_keys - wait(reload: false) do - has_element?(:project_deploy_keys) - end + has_element?(:project_deploy_keys, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) within_element(:project_deploy_keys) do yield diff --git a/qa/qa/page/project/settings/deploy_tokens.rb b/qa/qa/page/project/settings/deploy_tokens.rb index ad34ebc13c2..3173752d40a 100644 --- a/qa/qa/page/project/settings/deploy_tokens.rb +++ b/qa/qa/page/project/settings/deploy_tokens.rb @@ -51,9 +51,7 @@ module QA private def within_new_project_deploy_token - wait(reload: false) do - has_css?(element_selector_css(:created_deploy_token_section)) - end + has_element?(:created_deploy_token_section, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) within_element(:created_deploy_token_section) do yield diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb index cae5831f100..517163a22f1 100644 --- a/qa/qa/page/project/settings/mirroring_repositories.rb +++ b/qa/qa/page/project/settings/mirroring_repositories.rb @@ -77,9 +77,7 @@ module QA # The host key detection process is interrupted if we navigate away # from the page before the fingerprint appears. - wait(max: 5) do - find_element(:fingerprints_list).has_text? /.*/ - end + find_element(:fingerprints_list, text: /.*/) end def mirror_repository @@ -100,7 +98,7 @@ module QA sleep 5 refresh - wait(interval: 1) do + wait_until(sleep_interval: 1) do within_element_by_index(:mirrored_repository_row, row_index) do last_update = find_element(:mirror_last_update_at_cell, wait: 0) last_update.has_text?('just now') || last_update.has_text?('seconds') @@ -117,7 +115,7 @@ module QA private def find_repository_row_index(target_url) - wait(max: 5, reload: false) do + wait_until(max_duration: 5, reload: false) do all_elements(:mirror_repository_url_cell, minimum: 1).index do |url| # The url might be a sanitized url but the target_url won't be so # we compare just the paths instead of the full url diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb index 3f8aba78f44..ce17ca986a6 100644 --- a/qa/qa/page/project/settings/protected_branches.rb +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -46,7 +46,7 @@ module QA end def protect_branch - click_element :protect_button + click_element(:protect_button, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) end private diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 102b6144a1e..c619bd6d6a3 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -61,9 +61,7 @@ module QA end def wait_for_viewers_to_load - wait(reload: false) do - has_no_element?(:spinner) - end + has_no_element?(:spinner, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) end def create_first_new_file! @@ -103,7 +101,7 @@ module QA end def new_merge_request - wait(reload: true) do + wait_until(reload: true) do has_css?(element_selector_css(:create_merge_request)) end @@ -127,7 +125,7 @@ module QA end def wait_for_import - wait(reload: true) do + wait_until(reload: true) do has_css?('.tree-holder') end end diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb index b22828e554f..0977ff0c91b 100644 --- a/qa/qa/page/project/web_ide/edit.rb +++ b/qa/qa/page/project/web_ide/edit.rb @@ -69,7 +69,7 @@ module QA # Wait for the modal to fade out too has_no_element?(:new_file_modal) - wait(reload: false) do + wait_until(reload: false) do within_element(:file_templates_bar) do click_element :file_template_dropdown fill_element :dropdown_filter_input, template @@ -97,7 +97,7 @@ module QA # # Wait for the animation to complete before clicking :commit_button # otherwise the click will quietly do nothing. - wait(reload: false) do + wait_until(reload: false) do has_no_element?(:begin_commit_button) && has_element?(:commit_button) end @@ -112,7 +112,7 @@ module QA click_element(:commit_to_current_branch_radio) if has_element?(:commit_to_current_branch_radio) click_element(:commit_button) if has_element?(:commit_button) - wait(reload: false) do + wait_until(reload: false) do has_text?('Your changes have been committed') end end diff --git a/qa/qa/page/settings/common.rb b/qa/qa/page/settings/common.rb index bd1070158f0..6989e8125d3 100644 --- a/qa/qa/page/settings/common.rb +++ b/qa/qa/page/settings/common.rb @@ -10,7 +10,7 @@ module QA def expand_section(element_name) within_element(element_name) do # Because it is possible to click the button before the JS toggle code is bound - wait(reload: false) do + wait_until(reload: false) do click_button 'Expand' unless has_css?('button', text: 'Collapse', wait: 1) has_content?('Collapse') diff --git a/qa/qa/page/validatable.rb b/qa/qa/page/validatable.rb index 20aad65688d..3c4d9ad68aa 100644 --- a/qa/qa/page/validatable.rb +++ b/qa/qa/page/validatable.rb @@ -11,7 +11,7 @@ module QA elements.each do |element| next unless element.required? - unless base_page.wait(reload: false) { base_page.has_element?(element.name, wait: 15) } + unless base_page.has_element?(element.name, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) raise Validatable::PageValidationError, "#{element.name} did not appear on #{self.name} as expected" end end diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb index 1a6c2e70860..873ba353051 100644 --- a/qa/qa/resource/base.rb +++ b/qa/qa/resource/base.rb @@ -71,7 +71,7 @@ module QA Support::Retrier.retry_until do visit(web_url) - wait { current_url.include?(URI.parse(web_url).path.split('/').last || web_url) } + wait_until { current_url.include?(URI.parse(web_url).path.split('/').last || web_url) } end # Wait until the new page is ready for us to interact with it @@ -82,8 +82,8 @@ module QA attributes.each(&method(:public_send)) end - def wait(max: 60, interval: 0.1) - QA::Support::Waiter.wait(max: max, interval: interval) do + def wait_until(max_duration: 60, sleep_interval: 0.1) + QA::Support::Waiter.wait_until(max_duration: max_duration, sleep_interval: sleep_interval) do yield end end diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb index c12e9dd146b..0824512d238 100644 --- a/qa/qa/resource/group.rb +++ b/qa/qa/resource/group.rb @@ -39,7 +39,7 @@ module QA end # Ensure that the group was actually created - group_show.wait(interval: 1) do + group_show.wait_until(sleep_interval: 1) do group_show.has_text?(path) && group_show.has_new_project_or_subgroup_dropdown? end diff --git a/qa/qa/resource/protected_branch.rb b/qa/qa/resource/protected_branch.rb index 6aadbd55d0a..9c65e0e5a31 100644 --- a/qa/qa/resource/protected_branch.rb +++ b/qa/qa/resource/protected_branch.rb @@ -49,11 +49,6 @@ module QA page.select_branch(branch_name) page.select_allowed_to_merge(allowed_to_merge) page.select_allowed_to_push(allowed_to_push) - - page.wait(reload: false) do - !page.first('.btn-success').disabled? - end - page.protect_branch end end diff --git a/qa/qa/runtime/feature.rb b/qa/qa/runtime/feature.rb index 8c19436ee12..25fc02a887e 100644 --- a/qa/qa/runtime/feature.rb +++ b/qa/qa/runtime/feature.rb @@ -33,7 +33,7 @@ module QA is_enabled = false - QA::Support::Waiter.wait(interval: 1) do + QA::Support::Waiter.wait_until(sleep_interval: 1) do is_enabled = enabled?(key) end diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb index bab6b1ac5fc..664b62db888 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/close_issue_spec.rb @@ -27,7 +27,7 @@ module QA issue.visit! Page::Project::Issue::Show.perform do |show| - reopen_issue_button_visible = show.wait(reload: true) do + reopen_issue_button_visible = show.wait_until(reload: true) do show.has_element?(:reopen_issue_button, wait: 1.0) end expect(reopen_issue_button_visible).to be_truthy diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb index 8420f4112e9..82a679b6d15 100644 --- a/qa/qa/support/page/logging.rb +++ b/qa/qa/support/page/logging.rb @@ -16,7 +16,7 @@ module QA super end - def wait(max: 60, interval: 0.1, reload: true) + def wait_until(max_duration: 60, sleep_interval: 0.1, reload: true) log("next wait uses reload: #{reload}") # Logging of wait start/end/duration is handled by QA::Support::Waiter @@ -119,10 +119,10 @@ module QA found end - def has_no_text?(text) + def has_no_text?(text, **kwargs) found = super - log(%Q{has_no_text?('#{text}') returned #{found}}) + log(%Q{has_no_text?('#{text}', wait: #{kwargs[:wait] || Capybara.default_max_wait_time}) returned #{found}}) found end diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb index c573fc1f8e1..5d5ba70a0c2 100644 --- a/qa/qa/support/wait_for_requests.rb +++ b/qa/qa/support/wait_for_requests.rb @@ -6,7 +6,7 @@ module QA module_function def wait_for_requests - Waiter.wait do + Waiter.wait_until do finished_all_ajax_requests? && finished_all_axios_requests? end end diff --git a/qa/qa/support/waiter.rb b/qa/qa/support/waiter.rb index 73ca0182464..fe63c930c7c 100644 --- a/qa/qa/support/waiter.rb +++ b/qa/qa/support/waiter.rb @@ -7,12 +7,6 @@ module QA module_function - def wait(max: singleton_class::DEFAULT_MAX_WAIT_TIME, interval: 0.1) - wait_until(max_duration: max, sleep_interval: interval, raise_on_failure: false) do - yield - end - end - def wait_until(max_duration: singleton_class::DEFAULT_MAX_WAIT_TIME, reload_page: nil, sleep_interval: 0.1, raise_on_failure: false, retry_on_exception: false) QA::Runtime::Logger.debug( <<~MSG.tr("\n", ' ') diff --git a/qa/qa/vendor/jenkins/page/new_credentials.rb b/qa/qa/vendor/jenkins/page/new_credentials.rb index bdef1a13fd4..b0d13973090 100644 --- a/qa/qa/vendor/jenkins/page/new_credentials.rb +++ b/qa/qa/vendor/jenkins/page/new_credentials.rb @@ -39,7 +39,7 @@ module QA end def wait_for_page_to_load - QA::Support::Waiter.wait(interval: 1.0) do + QA::Support::Waiter.wait_until(sleep_interval: 1.0) do page.has_css?('.setting-name', text: "Description") end end diff --git a/qa/spec/page/base_spec.rb b/qa/spec/page/base_spec.rb index 88d0eac40e6..717112b12ce 100644 --- a/qa/spec/page/base_spec.rb +++ b/qa/spec/page/base_spec.rb @@ -3,7 +3,7 @@ describe QA::Page::Base do describe 'page helpers' do it 'exposes helpful page helpers' do - expect(subject).to respond_to :refresh, :wait, :scroll_to + expect(subject).to respond_to :refresh, :wait_until, :scroll_to end end @@ -69,11 +69,11 @@ describe QA::Page::Base do it 'does not refresh' do expect(subject).not_to receive(:refresh) - subject.wait(max: 0.01, raise_on_failure: false) { true } + subject.wait_until(max_duration: 0.01, raise_on_failure: false) { true } end it 'returns true' do - expect(subject.wait(max: 0.1, raise_on_failure: false) { true }).to be_truthy + expect(subject.wait_until(max_duration: 0.1, raise_on_failure: false) { true }).to be_truthy end end @@ -81,13 +81,13 @@ describe QA::Page::Base do it 'refreshes' do expect(subject).to receive(:refresh).at_least(:once) - subject.wait(max: 0.01, raise_on_failure: false) { false } + subject.wait_until(max_duration: 0.01, raise_on_failure: false) { false } end it 'returns false' do allow(subject).to receive(:refresh) - expect(subject.wait(max: 0.01, raise_on_failure: false) { false }).to be_falsey + expect(subject.wait_until(max_duration: 0.01, raise_on_failure: false) { false }).to be_falsey end end end diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb index 0d68f4bdae9..a6b61e9b1ee 100644 --- a/qa/spec/page/logging_spec.rb +++ b/qa/spec/page/logging_spec.rb @@ -28,20 +28,20 @@ describe QA::Support::Page::Logging do end it 'logs wait' do - expect { subject.wait(max: 0) {} } + expect { subject.wait_until(max_duration: 0) {} } .to output(/next wait uses reload: true/).to_stdout_from_any_process - expect { subject.wait(max: 0) {} } + expect { subject.wait_until(max_duration: 0) {} } .to output(/with wait_until/).to_stdout_from_any_process - expect { subject.wait(max: 0) {} } + expect { subject.wait_until(max_duration: 0) {} } .to output(/ended wait_until$/).to_stdout_from_any_process end it 'logs wait with reload false' do - expect { subject.wait(max: 0, reload: false) {} } + expect { subject.wait_until(max_duration: 0, reload: false) {} } .to output(/next wait uses reload: false/).to_stdout_from_any_process - expect { subject.wait(max: 0, reload: false) {} } + expect { subject.wait_until(max_duration: 0, reload: false) {} } .to output(/with wait_until/).to_stdout_from_any_process - expect { subject.wait(max: 0, reload: false) {} } + expect { subject.wait_until(max_duration: 0, reload: false) {} } .to output(/ended wait_until$/).to_stdout_from_any_process end @@ -121,10 +121,10 @@ describe QA::Support::Page::Logging do end it 'logs has_no_text?' do - allow(page).to receive(:has_no_text?).with('foo').and_return(true) + allow(page).to receive(:has_no_text?).with('foo', any_args).and_return(true) expect { subject.has_no_text? 'foo' } - .to output(/has_no_text\?\('foo'\) returned true/).to_stdout_from_any_process + .to output(/has_no_text\?\('foo', wait: #{QA::Runtime::Browser::CAPYBARA_MAX_WAIT_TIME}\) returned true/).to_stdout_from_any_process end it 'logs finished_loading?' do diff --git a/spec/fixtures/api/schemas/entities/issue_board.json b/spec/fixtures/api/schemas/entities/issue_board.json index 7cb65e1f2f5..09f66813c95 100644 --- a/spec/fixtures/api/schemas/entities/issue_board.json +++ b/spec/fixtures/api/schemas/entities/issue_board.json @@ -36,7 +36,8 @@ "real_path": { "type": "string" }, "issue_sidebar_endpoint": { "type": "string" }, "toggle_subscription_endpoint": { "type": "string" }, - "assignable_labels_endpoint": { "type": "string" } + "assignable_labels_endpoint": { "type": "string" }, + "blocked": { "type": "boolean" } }, "additionalProperties": false } diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 439f1343514..e0b4c8ae1f7 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1475,7 +1475,11 @@ describe Gitlab::Database::MigrationHelpers do describe '#index_exists_by_name?' do it 'returns true if an index exists' do - expect(model.index_exists_by_name?(:projects, 'index_projects_on_path')) + ActiveRecord::Base.connection.execute( + 'CREATE INDEX test_index_for_index_exists ON projects (path);' + ) + + expect(model.index_exists_by_name?(:projects, 'test_index_for_index_exists')) .to be_truthy end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index ee4db935b58..ce7894ea955 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -38,6 +38,8 @@ issues: - vulnerability_links - related_vulnerabilities - user_mentions +- blocked_by_issue_links +- blocked_by_issues events: - author - project diff --git a/spec/serializers/issue_board_entity_spec.rb b/spec/serializers/issue_board_entity_spec.rb index f6fa2a794f6..d013b27369b 100644 --- a/spec/serializers/issue_board_entity_spec.rb +++ b/spec/serializers/issue_board_entity_spec.rb @@ -3,12 +3,12 @@ require 'spec_helper' describe IssueBoardEntity do - let(:project) { create(:project) } - let(:resource) { create(:issue, project: project) } - let(:user) { create(:user) } - let(:milestone) { create(:milestone, project: project) } - let(:label) { create(:label, project: project, title: 'Test Label') } - let(:request) { double('request', current_user: user) } + let_it_be(:project) { create(:project) } + let_it_be(:resource) { create(:issue, project: project) } + let_it_be(:user) { create(:user) } + let_it_be(:milestone) { create(:milestone, project: project) } + let_it_be(:label) { create(:label, project: project, title: 'Test Label') } + let(:request) { double('request', current_user: user) } subject { described_class.new(resource, request: request).as_json } |