summaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-03 03:08:02 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-03 03:08:02 +0000
commit173b547fb98ab12ae41f295915453e598be3a647 (patch)
tree2ade7b72b501275292e6984c6cba2cbaba9d9aa6 /qa
parenta77c9fccd057514a8b78a10642779f54a22f3f76 (diff)
downloadgitlab-ce-173b547fb98ab12ae41f295915453e598be3a647.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'qa')
-rw-r--r--qa/qa/page/merge_request/show.rb5
-rw-r--r--qa/qa/resource/api_fabricator.rb120
-rw-r--r--qa/qa/resource/base.rb35
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb2
-rw-r--r--qa/qa/tools/test_resource_data_processor.rb2
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb2
6 files changed, 100 insertions, 66 deletions
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 14faa6a2e05..dd26c2c3bf7 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -82,6 +82,7 @@ module QA
element :merge_moment_dropdown
element :merge_immediately_menu_item
element :merged_status_content
+ element :auto_merge_helper_text
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue' do
@@ -279,7 +280,7 @@ module QA
def merge_when_pipeline_succeeds!
wait_until_ready_to_merge
- click_element(:merge_button, text: 'Merge when pipeline succeeds')
+ click_element(:merge_button, text: 'Set auto-merge')
end
def merged?
@@ -365,7 +366,7 @@ module QA
# Revisit after merge page re-architect is done https://gitlab.com/gitlab-org/gitlab/-/issues/300042
# To remove page refresh logic if possible
wait_until_ready_to_merge
- wait_until { !find_element(:merge_button).text.include?('when pipeline succeeds') } # rubocop:disable Rails/NegateInclude
+ wait_until { !has_element?(:auto_merge_helper_text) || !find_element(:auto_merge_helper_text).text.include?('when pipeline succeeds') } # rubocop:disable Rails/NegateInclude
click_element(:merge_button)
end
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index d7a220bc83f..cbb68cccdf1 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -10,6 +10,7 @@ module QA
include Support::API
include Errors
+ attr_reader :api_fabrication_http_method
attr_writer :api_client
attr_accessor :api_user, :api_resource, :api_response
@@ -49,22 +50,6 @@ module QA
end
end
- def api_put(body = api_put_body)
- response = put(
- Runtime::API::Request.new(api_client, api_put_path).url,
- body)
-
- unless response.code == HTTP_STATUS_OK
- raise ResourceFabricationFailedError, "Updating #{self.class.name} using the API failed (#{response.code}) with `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
- end
-
- process_api_response(parse_body(response))
- end
-
- def api_fabrication_http_method
- @api_fabrication_http_method ||= :post
- end
-
# Checks if a resource already exists
#
# @return [Boolean] true if the resource returns HTTP status code 200
@@ -84,14 +69,15 @@ module QA
private
- def resource_web_url(resource)
- resource.fetch(:web_url) do
- raise ResourceURLMissingError, "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
- end
- end
-
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
def api_get
- process_api_response(parse_body(api_get_from(api_get_path)))
+ process_api_response(parse_body(api_get_from(api_get_path))).tap do
+ # Record method that was used to create certain resource
+ # :get - resource already existed in GitLab instance and was fetched via get request
+ # :post - resource was created from scratch using post request
+ # :put - resource was created from scratch using put request
+ @api_fabrication_http_method ||= :get
+ end
end
def api_get_from(get_path)
@@ -100,27 +86,24 @@ module QA
response = get(request.url)
if response.code == HTTP_STATUS_SERVER_ERROR
- raise InternalServerError, "Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(InternalServerError, <<~MSG.strip)
+ Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
elsif response.code != HTTP_STATUS_OK
- raise ResourceNotFoundError, "Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(ResourceNotFoundError, <<~MSG.strip)
+ Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
- @api_fabrication_http_method ||= :get # rubocop:disable Gitlab/ModuleWithInstanceVariables
-
response
end
- # Query parameters formatted as `?key1=value1&key2=value2...`
- #
- # @return [String]
- def query_parameters_to_string
- query_parameters.each_with_object([]) do |(k, v), arr|
- arr << "#{k}=#{v}"
- end.join('&').prepend('?').chomp('?') # prepend `?` unless the string is blank
- end
-
def api_post
- process_api_response(api_post_to(api_post_path, api_post_body))
+ process_api_response(api_post_to(api_post_path, api_post_body)).tap do
+ @api_fabrication_http_method ||= :post
+ end
end
def api_post_to(post_path, post_body, args = {})
@@ -131,7 +114,7 @@ module QA
body = flatten_hash(parse_body(graphql_response))
unless graphql_response.code == HTTP_STATUS_OK && (body[:errors].nil? || body[:errors].empty?)
- raise(ResourceFabricationFailedError, <<~MSG)
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
Fabrication of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`.
#{QA::Support::Loglinking.failure_metadata(graphql_response.headers[:x_request_id])}
MSG
@@ -144,36 +127,64 @@ module QA
response = post(Runtime::API::Request.new(api_client, post_path).url, post_body, args)
unless response.code == HTTP_STATUS_CREATED
- raise(
- ResourceFabricationFailedError,
- "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
- )
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
+ Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
parse_body(response)
end
end
- def flatten_hash(param)
- param.each_pair.reduce({}) do |a, (k, v)|
- v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ def api_put
+ process_api_response(api_put_to(api_put_path, api_put_body)).tap do
+ @api_fabrication_http_method ||= :put
end
end
+ def api_put_to(put_path, body)
+ response = put(Runtime::API::Request.new(api_client, put_path).url, body)
+
+ unless response.code == HTTP_STATUS_OK
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
+ Updating #{self.class.name} using the API failed (#{response.code}) with `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
+ end
+
+ parse_body(response)
+ end
+
def api_delete
request = Runtime::API::Request.new(api_client, api_delete_path)
response = delete(request.url)
unless [HTTP_STATUS_NO_CONTENT, HTTP_STATUS_ACCEPTED].include? response.code
- raise ResourceNotDeletedError, "Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(ResourceNotDeletedError, <<~MSG.strip)
+ Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
response
end
+ def resource_web_url(resource)
+ resource.fetch(:web_url) do
+ raise ResourceURLMissingError,
+ "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
+ end
+ end
+
def api_client
- @api_client ||= Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'), user: api_user)
+ @api_client ||= Runtime::API::Client.new(
+ :gitlab,
+ is_new_session: !current_url.start_with?('http'),
+ user: api_user
+ )
end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
def process_api_response(parsed_response)
self.api_response = parsed_response
@@ -191,6 +202,21 @@ module QA
def request_url(path, **opts)
Runtime::API::Request.new(api_client, path, **opts).url
end
+
+ # Query parameters formatted as `?key1=value1&key2=value2...`
+ #
+ # @return [String]
+ def query_parameters_to_string
+ query_parameters.each_with_object([]) do |(k, v), arr|
+ arr << "#{k}=#{v}"
+ end.join('&').prepend('?').chomp('?') # prepend `?` unless the string is blank
+ end
+
+ def flatten_hash(param)
+ param.each_pair.reduce({}) do |a, (k, v)|
+ v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb
index 2abe1904c92..6c03f45bdfd 100644
--- a/qa/qa/resource/base.rb
+++ b/qa/qa/resource/base.rb
@@ -45,7 +45,7 @@ module QA
resource = options.fetch(:resource) { new }
parents = options.fetch(:parents) { [] }
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) }
current_url
@@ -61,7 +61,7 @@ module QA
resource.eager_load_api_client!
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! }
end
end
@@ -73,14 +73,14 @@ module QA
resource.eager_load_api_client!
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:api, resource, parents, args) { resource.remove_via_api! }
end
end
private
- def do_fabricate!(resource:, prepare_block:, parents: [])
+ def do_fabricate!(resource:, prepare_block:)
prepare_block.call(resource) if prepare_block
resource_web_url = yield
@@ -89,17 +89,12 @@ module QA
resource
end
- def log_and_record_fabrication(fabrication_method, resource, parents, args)
+ def log_and_record_fabrication(fabrication_method, resource, parents, _args)
start = Time.now
Support::FabricationTracker.start_fabrication
result = yield.tap do
fabrication_time = Time.now - start
- fabrication_http_method = if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache
- "Retrieved"
- else
- "Built"
- end
Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time)
@@ -114,7 +109,7 @@ module QA
Runtime::Logger.info do
msg = ["==#{'=' * parents.size}>"]
- msg << "#{fabrication_http_method} a #{Rainbow(name).black.bg(:white)}"
+ msg << "#{fabrication_type(resource, fabrication_method)} a #{Rainbow(name).black.bg(:white)}"
msg << resource.identifier
msg << "as a dependency of #{parents.last}" if parents.any?
msg << "via #{resource.retrieved_from_cache ? 'cache' : fabrication_method}"
@@ -129,6 +124,19 @@ module QA
result
end
+ # Fetch type of fabrication, either resource was built or fetched
+ #
+ # @param [Resource] resource
+ # @param [Symbol] method
+ # @return [String]
+ def fabrication_type(resource, method)
+ return "Built" if method == :browser_ui || [:post, :put].include?(resource.api_fabrication_http_method)
+ return "Retrieved" if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache
+
+ Runtime::Logger.warn("Resource fabrication http method has not been set properly, assuming :get value!")
+ "Built"
+ end
+
# Define custom attribute
#
# @param [Symbol] name
@@ -215,8 +223,7 @@ module QA
def diff(other)
return if self == other
- diff_values = self.comparable.to_a - other.comparable.to_a
- diff_values.to_h
+ (comparable.to_a - other.comparable.to_a).to_h
end
def identifier
@@ -271,7 +278,7 @@ module QA
def all_attributes
@all_attributes ||= self.class.ancestors
.select { |clazz| clazz <= QA::Resource::Base }
- .map { |clazz| clazz.instance_variable_get(:@attribute_names) }
+ .map { |clazz| clazz.instance_variable_get(:@attribute_names) } # rubocop:disable Performance/FlatMap
.flatten
.compact
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
index 1b82543a5d4..366ced10af0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
@@ -79,7 +79,7 @@ module QA
mr.retry_until(reload: true, message: 'Wait until ready to click MWPS') do
# Click the MWPS button if we can
- break mr.merge_when_pipeline_succeeds! if mr.has_element?(:merge_button, text: 'Merge when pipeline succeeds')
+ break mr.merge_when_pipeline_succeeds! if mr.has_element?(:merge_button, text: 'Set auto-merge')
# But fail if the button is missing because the pipeline is complete
raise "The pipeline already finished before we could click MWPS" if mr.wait_until { project.pipelines.first }[:status] == 'success'
diff --git a/qa/qa/tools/test_resource_data_processor.rb b/qa/qa/tools/test_resource_data_processor.rb
index a86c94b4914..3312285ecc4 100644
--- a/qa/qa/tools/test_resource_data_processor.rb
+++ b/qa/qa/tools/test_resource_data_processor.rb
@@ -38,7 +38,7 @@ module QA
api_path: api_path,
fabrication_method: fabrication_method,
fabrication_time: fabrication_time,
- http_method: resource.api_fabrication_http_method,
+ http_method: resource.api_fabrication_http_method || :post,
timestamp: Time.now.to_s
}
end
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index 337c6772a06..96823ea7ada 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe QA::Resource::ApiFabricator do
expect { subject.fabricate_via_api! }.to raise_error do |error|
expect(error.class).to eql(described_class::ResourceFabricationFailedError)
- expect(error.to_s).to eql(<<~ERROR.chomp)
+ expect(error.to_s).to eql(<<~ERROR.strip)
Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`.\n
ERROR
end