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:
parent
da2da0fa59
commit
1e033f5bd4
|
@ -8,14 +8,14 @@
|
|||
= f.label :auth_method, _('Authentication method'), class: 'label-bold'
|
||||
= f.select :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
|
||||
.collapse.js-well-changing-auth
|
||||
.changing-auth-method= icon('spinner spin lg')
|
||||
.well-password-auth.collapse.js-well-password-auth
|
||||
= 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
|
||||
.well-ssh-auth.collapse.js-well-ssh-auth
|
||||
%p.js-ssh-public-key-present{ class: ('collapse' unless ssh_public_key_present) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- expanded = Rails.env.test?
|
||||
- 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
|
||||
%h4= _('Mirroring repositories')
|
||||
%button.btn.js-settings-toggle
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
.form-group.has-feedback
|
||||
= 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'
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
|||
= link_to icon('question-circle'), help_page_path('user/project/protected_branches')
|
||||
|
||||
.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
|
||||
.table-responsive
|
||||
|
@ -50,10 +50,10 @@
|
|||
= render_if_exists 'projects/mirrors/table_pull_row'
|
||||
- @project.remote_mirrors.each_with_index do |mirror, index|
|
||||
- if mirror.enabled
|
||||
%tr
|
||||
%td= mirror.safe_url
|
||||
%tr.qa-mirrored-repository-row
|
||||
%td.qa-mirror-repository-url= mirror.safe_url
|
||||
%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
|
||||
- if mirror.last_error.present?
|
||||
.badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.form-group
|
||||
= 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 }
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
%button.btn.disabled{ type: 'button', data: { toggle: 'tooltip', container: 'body' }, title: _('Updating') }
|
||||
= icon("refresh spin")
|
||||
- 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")
|
||||
|
|
1
qa/qa.rb
1
qa/qa.rb
|
@ -184,6 +184,7 @@ module QA
|
|||
autoload :Runners, 'qa/page/project/settings/runners'
|
||||
autoload :MergeRequest, 'qa/page/project/settings/merge_request'
|
||||
autoload :Members, 'qa/page/project/settings/members'
|
||||
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
|
||||
end
|
||||
|
||||
module Issue
|
||||
|
|
|
@ -15,7 +15,7 @@ module QA
|
|||
def_delegators :evaluator, :view, :views
|
||||
|
||||
def refresh
|
||||
visit current_url
|
||||
page.refresh
|
||||
end
|
||||
|
||||
def wait(max: 60, time: 0.1, reload: true)
|
||||
|
@ -80,8 +80,8 @@ module QA
|
|||
page.evaluate_script('xhr.status') == 200
|
||||
end
|
||||
|
||||
def find_element(name)
|
||||
find(element_selector_css(name))
|
||||
def find_element(name, wait: Capybara.default_max_wait_time)
|
||||
find(element_selector_css(name), wait: wait)
|
||||
end
|
||||
|
||||
def all_elements(name)
|
||||
|
@ -100,6 +100,14 @@ module QA
|
|||
find_element(name).set(content)
|
||||
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)
|
||||
has_css?(element_selector_css(name))
|
||||
end
|
||||
|
@ -110,6 +118,12 @@ module QA
|
|||
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)
|
||||
scroll_to(element_selector_css(name), *args)
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -13,6 +13,10 @@ module QA
|
|||
element :protected_branches_settings
|
||||
end
|
||||
|
||||
view 'app/views/projects/mirrors/_mirror_repos.html.haml' do
|
||||
element :mirroring_repositories_settings
|
||||
end
|
||||
|
||||
def expand_deploy_keys(&block)
|
||||
expand_section(:deploy_keys_settings) do
|
||||
DeployKeys.perform(&block)
|
||||
|
@ -30,6 +34,12 @@ module QA
|
|||
DeployTokens.perform(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def expand_mirroring_repositories(&block)
|
||||
expand_section(:mirroring_repositories_settings) do
|
||||
MirroringRepositories.perform(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -37,8 +37,8 @@ module QA
|
|||
exists
|
||||
end
|
||||
|
||||
def find_element(name)
|
||||
log("finding :#{name}")
|
||||
def find_element(name, wait: Capybara.default_max_wait_time)
|
||||
log("finding :#{name} (wait: #{wait})")
|
||||
|
||||
element = super
|
||||
|
||||
|
@ -71,6 +71,12 @@ module QA
|
|||
super
|
||||
end
|
||||
|
||||
def select_element(name, value)
|
||||
log(%Q(selecting "#{value}" in :#{name}))
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def has_element?(name)
|
||||
found = super
|
||||
|
||||
|
@ -89,6 +95,16 @@ module QA
|
|||
element
|
||||
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
|
||||
|
||||
def log(msg)
|
||||
|
|
Loading…
Reference in New Issue