Commit c2d5eb19 authored by Walmyr Lima e Silva Filho's avatar Walmyr Lima e Silva Filho

Merge branch 'ml-add-multi-project-pipelines-test' into 'master'

Adds an E2E test of multi-project pipelines

Closes gitlab-org/quality/testcases#212

See merge request gitlab-org/gitlab!17987
parents bc6828b4 e13631b8
...@@ -115,7 +115,10 @@ export default { ...@@ -115,7 +115,10 @@ export default {
data-qa-selector="merge_request_pipeline_info_content" data-qa-selector="merge_request_pipeline_info_content"
> >
{{ pipeline.details.name }} {{ pipeline.details.name }}
<gl-link :href="pipeline.path" class="pipeline-id font-weight-normal pipeline-number" <gl-link
:href="pipeline.path"
class="pipeline-id font-weight-normal pipeline-number"
data-qa-selector="pipeline_link"
>#{{ pipeline.id }}</gl-link >#{{ pipeline.id }}</gl-link
> >
{{ pipeline.details.status.label }} {{ pipeline.details.status.label }}
......
...@@ -48,6 +48,7 @@ export default { ...@@ -48,6 +48,7 @@ export default {
v-gl-tooltip v-gl-tooltip
:title="tooltipText" :title="tooltipText"
class="js-linked-pipeline-content linked-pipeline-content" class="js-linked-pipeline-content linked-pipeline-content"
data-qa-selector="linked_pipeline_button"
:class="`js-pipeline-expand-${pipeline.id}`" :class="`js-pipeline-expand-${pipeline.id}`"
@click="onClickLinkedPipeline" @click="onClickLinkedPipeline"
> >
......
...@@ -357,6 +357,7 @@ module QA ...@@ -357,6 +357,7 @@ module QA
# Classes describing components that are used by several pages. # Classes describing components that are used by several pages.
# #
module Component module Component
autoload :CiBadgeLink, 'qa/page/component/ci_badge_link'
autoload :ClonePanel, 'qa/page/component/clone_panel' autoload :ClonePanel, 'qa/page/component/clone_panel'
autoload :LazyLoader, 'qa/page/component/lazy_loader' autoload :LazyLoader, 'qa/page/component/lazy_loader'
autoload :LegacyClonePanel, 'qa/page/component/legacy_clone_panel' autoload :LegacyClonePanel, 'qa/page/component/legacy_clone_panel'
......
...@@ -5,15 +5,19 @@ module QA::EE::Page ...@@ -5,15 +5,19 @@ module QA::EE::Page
module Show module Show
def self.prepended(page) def self.prepended(page)
page.module_eval do page.module_eval do
view 'ee/app/views/projects/pipelines/_tabs_holder.html.haml' do view 'ee/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
element :security_tab element :linked_pipeline_button
element :security_counter
end end
view 'ee/app/assets/javascripts/security_dashboard/components/filter.vue' do view 'ee/app/assets/javascripts/security_dashboard/components/filter.vue' do
element :filter_dropdown, ':data-qa-selector="qaSelector"' # rubocop:disable QA/ElementWithPattern element :filter_dropdown, ':data-qa-selector="qaSelector"' # rubocop:disable QA/ElementWithPattern
element :filter_dropdown_content element :filter_dropdown_content
end end
view 'ee/app/views/projects/pipelines/_tabs_holder.html.haml' do
element :security_tab
element :security_counter
end
end end
end end
......
...@@ -95,7 +95,7 @@ module QA ...@@ -95,7 +95,7 @@ module QA
# replace with (..., page = self.class) # replace with (..., page = self.class)
def click_element(name, page = nil, text: nil) def click_element(name, page = nil, text: nil)
find_element(name, text: nil).click find_element(name, text: text).click
page.validate_elements_present! if page page.validate_elements_present! if page
end end
......
# frozen_string_literal: true
module QA
module Page
module Component
module CiBadgeLink
COMPLETED_STATUSES = %w[passed failed canceled blocked skipped manual].freeze # excludes created, pending, running
PASSED_STATUS = 'passed'.freeze
def self.included(base)
base.view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
element :status_badge
end
end
def status_badge
find_element(:status_badge).text
end
def successful?(timeout: 60)
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
status_badge == PASSED_STATUS
end
private
def completed?(timeout: 60)
wait(reload: false, max: timeout) do
COMPLETED_STATUSES.include?(status_badge)
end
end
end
end
end
end
...@@ -14,6 +14,7 @@ module QA ...@@ -14,6 +14,7 @@ module QA
view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue' do view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue' do
element :merge_request_pipeline_info_content element :merge_request_pipeline_info_content
element :pipeline_link
end end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do
...@@ -59,6 +60,18 @@ module QA ...@@ -59,6 +60,18 @@ module QA
element :edit_button element :edit_button
end end
def click_discussions_tab
click_element :notes_tab
end
def click_diffs_tab
click_element :diffs_tab
end
def click_pipeline_link
click_element :pipeline_link
end
def fast_forward_possible? def fast_forward_possible?
has_no_text?('Fast-forward merge is not possible') has_no_text?('Fast-forward merge is not possible')
end end
...@@ -156,14 +169,6 @@ module QA ...@@ -156,14 +169,6 @@ module QA
click_element :squash_checkbox click_element :squash_checkbox
end end
def click_discussions_tab
click_element :notes_tab
end
def click_diffs_tab
click_element :diffs_tab
end
def add_comment_to_diff(text) def add_comment_to_diff(text)
wait(interval: 5) do wait(interval: 5) do
has_text?("No newline at end of file") has_text?("No newline at end of file")
......
...@@ -3,17 +3,12 @@ ...@@ -3,17 +3,12 @@
module QA::Page module QA::Page
module Project::Job module Project::Job
class Show < QA::Page::Base class Show < QA::Page::Base
COMPLETED_STATUSES = %w[passed failed canceled blocked skipped manual].freeze # excludes created, pending, running include Component::CiBadgeLink
PASSED_STATUS = 'passed'.freeze
view 'app/assets/javascripts/jobs/components/job_log.vue' do view 'app/assets/javascripts/jobs/components/job_log.vue' do
element :build_trace element :build_trace
end end
view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
element :status_badge
end
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
element :pipeline_path element :pipeline_path
end end
...@@ -45,16 +40,6 @@ module QA::Page ...@@ -45,16 +40,6 @@ module QA::Page
has_element?(:build_trace, wait: 1) has_element?(:build_trace, wait: 1)
end end
end end
def completed?(timeout: 60)
wait(reload: false, max: timeout) do
COMPLETED_STATUSES.include?(status_badge)
end
end
def status_badge
find_element(:status_badge).text
end
end end
end end
end end
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module QA::Page module QA::Page
module Project::Pipeline module Project::Pipeline
class Show < QA::Page::Base class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
end end
...@@ -38,6 +40,14 @@ module QA::Page ...@@ -38,6 +40,14 @@ module QA::Page
end end
end end
def has_job?(job_name)
has_element?(:job_link, text: job_name)
end
def has_no_job?(job_name)
has_no_element?(:job_link, text: job_name)
end
def has_tag?(tag_name) def has_tag?(tag_name)
within_element(:pipeline_badges) do within_element(:pipeline_badges) do
has_selector?('.badge', text: tag_name) has_selector?('.badge', text: tag_name)
...@@ -45,7 +55,11 @@ module QA::Page ...@@ -45,7 +55,11 @@ module QA::Page
end end
def click_job(job_name) def click_job(job_name)
find_element(:job_link, text: job_name).click click_element(:job_link, text: job_name)
end
def click_linked_job(project_name)
click_element(:linked_pipeline_button, text: /#{project_name}/)
end end
def click_on_first_job def click_on_first_job
......
...@@ -88,6 +88,10 @@ module QA ...@@ -88,6 +88,10 @@ module QA
"#{api_get_path}/members" "#{api_get_path}/members"
end end
def api_runners_path
"#{api_get_path}/runners"
end
def api_post_path def api_post_path
'/projects' '/projects'
end end
...@@ -108,6 +112,11 @@ module QA ...@@ -108,6 +112,11 @@ module QA
post_body post_body
end end
def runners
response = get Runtime::API::Request.new(api_client, api_runners_path).url
parse_body(response)
end
def share_with_group(invitee, access_level = Resource::Members::AccessLevel::DEVELOPER) def share_with_group(invitee, access_level = Resource::Members::AccessLevel::DEVELOPER)
post Runtime::API::Request.new(api_client, "/projects/#{id}/share").url, { group_id: invitee.id, group_access: access_level } post Runtime::API::Request.new(api_client, "/projects/#{id}/share").url, { group_id: invitee.id, group_access: access_level }
end end
......
...@@ -6,8 +6,9 @@ module QA ...@@ -6,8 +6,9 @@ module QA
module Resource module Resource
class Runner < Base class Runner < Base
attr_writer :name, :tags, :image attr_writer :name, :tags, :image
attr_accessor :config attr_accessor :config, :token
attribute :id
attribute :project do attribute :project do
Project.fabricate_via_api! do |resource| Project.fabricate_via_api! do |resource|
resource.name = 'project-with-ci-cd' resource.name = 'project-with-ci-cd'
...@@ -30,7 +31,7 @@ module QA ...@@ -30,7 +31,7 @@ module QA
def fabricate_via_api! def fabricate_via_api!
Service::Runner.new(name).tap do |runner| Service::Runner.new(name).tap do |runner|
runner.pull runner.pull
runner.token = project.runners_token runner.token = @token ||= project.runners_token
runner.address = Runtime::Scenario.gitlab_address runner.address = Runtime::Scenario.gitlab_address
runner.tags = tags runner.tags = tags
runner.image = image runner.image = image
...@@ -40,6 +41,18 @@ module QA ...@@ -40,6 +41,18 @@ module QA
end end
end end
def remove_via_api!
@id = project.runners.find { |runner| runner[:description] == name }[:id]
super
Service::Runner.new(name).remove!
end
def api_delete_path
"/runners/#{id}"
end
def api_get_path def api_get_path
end end
......
...@@ -10,6 +10,7 @@ module QA ...@@ -10,6 +10,7 @@ module QA
attr_accessor :path attr_accessor :path
attribute :id attribute :id
attribute :runners_token
def initialize def initialize
@path = Runtime::Namespace.sandbox_name @path = Runtime::Namespace.sandbox_name
......
# frozen_string_literal: true
require 'securerandom'
module QA
context 'Release', :docker do
describe 'Multi-project pipelines' do
let(:upstream_project_name) { "upstream-project-#{SecureRandom.hex(8)}" }
let(:downstream_project_name) { "downstream-project-#{SecureRandom.hex(8)}" }
let(:upstream_project) do
Resource::Project.fabricate_via_api! do |project|
project.name = upstream_project_name
end
end
let(:downstream_project) do
Resource::Project.fabricate_via_api! do |project|
project.name = downstream_project_name
end
end
let!(:runner) do
Resource::Runner.fabricate_via_api! do |runner|
runner.project = upstream_project
runner.token = upstream_project.group.sandbox.runners_token
runner.name = upstream_project_name
runner.tags = %w[qa test]
end
end
before do
Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = upstream_project
project_push.file_name = '.gitlab-ci.yml'
project_push.commit_message = 'Add .gitlab-ci.yml'
project_push.file_content = <<~CI
stages:
- test
- deploy
job1:
stage: test
script: echo "done"
staging:
stage: deploy
trigger:
project: #{downstream_project.path_with_namespace}
strategy: depend
CI
end
Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = downstream_project
project_push.file_name = '.gitlab-ci.yml'
project_push.commit_message = 'Add .gitlab-ci.yml'
project_push.file_content = <<~CI
downstream_job:
stage: test
script: echo "done"
CI
end
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.project = upstream_project
merge_request.target_new_branch = false
end.visit!
end
after do
runner.remove_via_api!
end
it 'creates a multi-project pipeline' do
Page::MergeRequest::Show.perform do |show|
pipeline_passed = Support::Retrier.retry_until do
show.has_content?(/Pipeline #\d+ passed/)
end
expect(pipeline_passed).to be_truthy, "The pipeline did not pass."
show.click_pipeline_link
end
Page::Project::Pipeline::Show.perform do |show|
expect(show).to be_successful
expect(show).to have_no_job("downstream_job")
show.click_linked_job(downstream_project_name)
expect(show).to have_job("downstream_job")
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment