Add e2e test: push mirroring over HTTP

Adds an end-to-end test of push mirroring a repository over HTTP.

Includes addition of QA selectors to views
This commit is contained in:
Mark Lapierre 2018-11-14 09:50:11 -05:00
parent da2da0fa59
commit 1e033f5bd4
10 changed files with 192 additions and 15 deletions

View file

@ -8,14 +8,14 @@
= f.label :auth_method, _('Authentication method'), class: 'label-bold' = f.label :auth_method, _('Authentication method'), class: 'label-bold'
= f.select :auth_method, = f.select :auth_method,
options_for_select(auth_options, mirror.auth_method), options_for_select(auth_options, mirror.auth_method),
{}, { class: "form-control js-mirror-auth-type" } {}, { class: "form-control js-mirror-auth-type qa-authentication-method" }
.form-group .form-group
.collapse.js-well-changing-auth .collapse.js-well-changing-auth
.changing-auth-method= icon('spinner spin lg') .changing-auth-method= icon('spinner spin lg')
.well-password-auth.collapse.js-well-password-auth .well-password-auth.collapse.js-well-password-auth
= f.label :password, _("Password"), class: "label-bold" = f.label :password, _("Password"), class: "label-bold"
= f.password_field :password, value: mirror.password, class: 'form-control', autocomplete: 'new-password' = f.password_field :password, value: mirror.password, class: 'form-control qa-password', autocomplete: 'new-password'
- unless is_push - unless is_push
.well-ssh-auth.collapse.js-well-ssh-auth .well-ssh-auth.collapse.js-well-ssh-auth
%p.js-ssh-public-key-present{ class: ('collapse' unless ssh_public_key_present) } %p.js-ssh-public-key-present{ class: ('collapse' unless ssh_public_key_present) }

View file

@ -1,7 +1,7 @@
- expanded = Rails.env.test? - expanded = Rails.env.test?
- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') - protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|')
%section.settings.project-mirror-settings.js-mirror-settings.no-animate#js-push-remote-settings{ class: ('expanded' if expanded) } %section.settings.project-mirror-settings.js-mirror-settings.no-animate.qa-mirroring-repositories-settings#js-push-remote-settings{ class: ('expanded' if expanded) }
.settings-header .settings-header
%h4= _('Mirroring repositories') %h4= _('Mirroring repositories')
%button.btn.js-settings-toggle %button.btn.js-settings-toggle
@ -20,7 +20,7 @@
.form-group.has-feedback .form-group.has-feedback
= label_tag :url, _('Git repository URL'), class: 'label-light' = label_tag :url, _('Git repository URL'), class: 'label-light'
= text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+" = text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url qa-mirror-repository-url-input', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+"
= render 'projects/mirrors/instructions' = render 'projects/mirrors/instructions'
@ -32,7 +32,7 @@
= link_to icon('question-circle'), help_page_path('user/project/protected_branches') = link_to icon('question-circle'), help_page_path('user/project/protected_branches')
.panel-footer .panel-footer
= f.submit _('Mirror repository'), class: 'btn btn-success js-mirror-submit', name: :update_remote_mirror = f.submit _('Mirror repository'), class: 'btn btn-success js-mirror-submit qa-mirror-repository-button', name: :update_remote_mirror
.panel.panel-default .panel.panel-default
.table-responsive .table-responsive
@ -50,10 +50,10 @@
= render_if_exists 'projects/mirrors/table_pull_row' = render_if_exists 'projects/mirrors/table_pull_row'
- @project.remote_mirrors.each_with_index do |mirror, index| - @project.remote_mirrors.each_with_index do |mirror, index|
- if mirror.enabled - if mirror.enabled
%tr %tr.qa-mirrored-repository-row
%td= mirror.safe_url %td.qa-mirror-repository-url= mirror.safe_url
%td= _('Push') %td= _('Push')
%td= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never') %td.qa-mirror-last-update-at= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never')
%td %td
- if mirror.last_error.present? - if mirror.last_error.present?
.badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error') .badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error')

View file

@ -1,5 +1,5 @@
.form-group .form-group
= label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light'
= select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control js-mirror-direction', disabled: true = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control js-mirror-direction qa-mirror-direction', disabled: true
= render partial: "projects/mirrors/mirror_repos_push", locals: { f: f } = render partial: "projects/mirrors/mirror_repos_push", locals: { f: f }

View file

@ -2,5 +2,5 @@
%button.btn.disabled{ type: 'button', data: { toggle: 'tooltip', container: 'body' }, title: _('Updating') } %button.btn.disabled{ type: 'button', data: { toggle: 'tooltip', container: 'body' }, title: _('Updating') }
= icon("refresh spin") = icon("refresh spin")
- else - else
= link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn", data: { toggle: 'tooltip', container: 'body' }, title: _('Update now') do = link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn qa-update-now-button", data: { toggle: 'tooltip', container: 'body' }, title: _('Update now') do
= icon("refresh") = icon("refresh")

View file

@ -184,6 +184,7 @@ module QA
autoload :Runners, 'qa/page/project/settings/runners' autoload :Runners, 'qa/page/project/settings/runners'
autoload :MergeRequest, 'qa/page/project/settings/merge_request' autoload :MergeRequest, 'qa/page/project/settings/merge_request'
autoload :Members, 'qa/page/project/settings/members' autoload :Members, 'qa/page/project/settings/members'
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
end end
module Issue module Issue

View file

@ -15,7 +15,7 @@ module QA
def_delegators :evaluator, :view, :views def_delegators :evaluator, :view, :views
def refresh def refresh
visit current_url page.refresh
end end
def wait(max: 60, time: 0.1, reload: true) def wait(max: 60, time: 0.1, reload: true)
@ -80,8 +80,8 @@ module QA
page.evaluate_script('xhr.status') == 200 page.evaluate_script('xhr.status') == 200
end end
def find_element(name) def find_element(name, wait: Capybara.default_max_wait_time)
find(element_selector_css(name)) find(element_selector_css(name), wait: wait)
end end
def all_elements(name) def all_elements(name)
@ -100,6 +100,14 @@ module QA
find_element(name).set(content) find_element(name).set(content)
end end
def select_element(name, value)
element = find_element(name)
return if element.text.downcase.to_s == value.to_s
element.select value.to_s.capitalize
end
def has_element?(name) def has_element?(name)
has_css?(element_selector_css(name)) has_css?(element_selector_css(name))
end end
@ -110,6 +118,12 @@ module QA
end end
end end
def within_element_by_index(name, index)
page.within all_elements(name)[index] do
yield
end
end
def scroll_to_element(name, *args) def scroll_to_element(name, *args)
scroll_to(element_selector_css(name), *args) scroll_to(element_selector_css(name), *args)
end end

View file

@ -0,0 +1,91 @@
# frozen_string_literal: true
module QA
module Page
module Project
module Settings
class MirroringRepositories < Page::Base
view 'app/views/projects/mirrors/_authentication_method.html.haml' do
element :authentication_method
element :password
end
view 'app/views/projects/mirrors/_mirror_repos.html.haml' do
element :mirror_repository_url_input
element :mirror_repository_button
element :mirror_repository_url
element :mirror_last_update_at
element :mirrored_repository_row
end
view 'app/views/projects/mirrors/_mirror_repos_form.html.haml' do
element :mirror_direction
end
view 'app/views/shared/_remote_mirror_update_button.html.haml' do
element :update_now_button
end
def repository_url=(value)
fill_element :mirror_repository_url_input, value
end
def password=(value)
fill_element :password, value
end
def mirror_direction=(value)
raise ArgumentError, "Mirror direction must be :push or :pull" unless [:push, :pull].include? value
select_element(:mirror_direction, value)
end
def authentication_method=(value)
raise ArgumentError, "Authentication method must be :password or :none" unless [:password, :none].include? value
select_element(:authentication_method, value)
end
def mirror_repository
click_element :mirror_repository_button
end
def update(url)
row_index = find_repository_row_index url
within_element_by_index(:mirrored_repository_row, row_index) do
click_element :update_now_button
end
# Wait a few seconds for the sync to occur and then refresh the page
# so that 'last update' shows 'just now' or a period in seconds
sleep 5
refresh
wait(time: 1) do
within_element_by_index(:mirrored_repository_row, row_index) do
last_update = find_element(:mirror_last_update_at, wait: 0)
last_update.has_text?('just now') || last_update.has_text?('seconds')
end
end
# Fail early if the page still shows that there has been no update
within_element_by_index(:mirrored_repository_row, row_index) do
find_element(:mirror_last_update_at, wait: 0).assert_no_text('Never')
end
end
private
def find_repository_row_index(target_url)
all_elements(:mirror_repository_url).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
URI.parse(url.text).path == target_url.path
end
end
end
end
end
end
end

View file

@ -13,6 +13,10 @@ module QA
element :protected_branches_settings element :protected_branches_settings
end end
view 'app/views/projects/mirrors/_mirror_repos.html.haml' do
element :mirroring_repositories_settings
end
def expand_deploy_keys(&block) def expand_deploy_keys(&block)
expand_section(:deploy_keys_settings) do expand_section(:deploy_keys_settings) do
DeployKeys.perform(&block) DeployKeys.perform(&block)
@ -30,6 +34,12 @@ module QA
DeployTokens.perform(&block) DeployTokens.perform(&block)
end end
end end
def expand_mirroring_repositories(&block)
expand_section(:mirroring_repositories_settings) do
MirroringRepositories.perform(&block)
end
end
end end
end end
end end

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
module QA
context 'Create' do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs a (push) mirrored repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
target_project = Resource::Project.fabricate! do |project|
project.name = 'push-mirror-target-project'
end
target_project_uri = target_project.repository_http_location.uri
target_project_uri.user = Runtime::User.username
source_project_push = Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md'
push.file_content = '# This is a test project'
push.commit_message = 'Add README.md'
end
source_project_push.project.visit!
Page::Project::Show.perform(&:wait_for_push)
Page::Project::Menu.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |settings|
settings.expand_mirroring_repositories do |mirror_settings|
# Configure the source project to push to the target project
mirror_settings.repository_url = target_project_uri
mirror_settings.mirror_direction = :push
mirror_settings.authentication_method = :password
mirror_settings.password = Runtime::User.password
mirror_settings.mirror_repository
mirror_settings.update target_project_uri
end
end
# Check that the target project has the commit from the source
target_project.visit!
expect(page).to have_content('README.md')
expect(page).to have_content('This is a test project')
end
end
end
end

View file

@ -37,8 +37,8 @@ module QA
exists exists
end end
def find_element(name) def find_element(name, wait: Capybara.default_max_wait_time)
log("finding :#{name}") log("finding :#{name} (wait: #{wait})")
element = super element = super
@ -71,6 +71,12 @@ module QA
super super
end end
def select_element(name, value)
log(%Q(selecting "#{value}" in :#{name}))
super
end
def has_element?(name) def has_element?(name)
found = super found = super
@ -89,6 +95,16 @@ module QA
element element
end end
def within_element_by_index(name, index)
log("within elements :#{name} at index #{index}")
element = super
log("end within elements :#{name} at index #{index}")
element
end
private private
def log(msg) def log(msg)