diff options
Diffstat (limited to 'qa/qa/tools')
-rw-r--r-- | qa/qa/tools/delete_test_resources.rb | 87 | ||||
-rw-r--r-- | qa/qa/tools/initialize_gitlab_auth.rb | 2 | ||||
-rw-r--r-- | qa/qa/tools/reliable_report.rb | 2 | ||||
-rw-r--r-- | qa/qa/tools/test_resource_data_processor.rb | 107 |
4 files changed, 117 insertions, 81 deletions
diff --git a/qa/qa/tools/delete_test_resources.rb b/qa/qa/tools/delete_test_resources.rb index 917cb2fa992..6f63c56f736 100644 --- a/qa/qa/tools/delete_test_resources.rb +++ b/qa/qa/tools/delete_test_resources.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -# This script reads from test_resources.txt file to collect data about resources to delete -# Deletes all deletable resources that E2E tests created -# Resource type: Sandbox, User, Fork and RSpec::Mocks::Double are not included +# This script reads from test-resources JSON file to collect data about resources to delete +# Filter out resources that cannot be deleted +# Then deletes all deletable resources that E2E tests created # # Required environment variables: GITLAB_QA_ACCESS_TOKEN and GITLAB_ADDRESS # When in CI also requires: QA_TEST_RESOURCES_FILE_PATTERN @@ -13,7 +13,15 @@ module QA class DeleteTestResources include Support::API - def initialize(file_pattern = nil) + IGNORED_RESOURCES = [ + 'QA::Resource::PersonalAccessToken', + 'QA::Resource::CiVariable', + 'QA::Resource::Repository::Commit', + 'QA::EE::Resource::GroupIteration', + 'QA::EE::Resource::Settings::Elasticsearch' + ].freeze + + def initialize(file_pattern = Runtime::Env.test_resources_created_filepath) raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS'] raise ArgumentError, "Please provide GITLAB_QA_ACCESS_TOKEN" unless ENV['GITLAB_QA_ACCESS_TOKEN'] @@ -22,45 +30,58 @@ module QA end def run - puts 'Deleting test created resources...' - - if Runtime::Env.running_in_ci? - raise ArgumentError, 'Please provide QA_TEST_RESOURCES_FILE_PATTERN' unless ENV['QA_TEST_RESOURCES_FILE_PATTERN'] - - Dir.glob(@file_pattern).each do |file| - delete_resources(load_file(file)) - end - else - file = Runtime::Env.test_resources_created_filepath - raise ArgumentError, "'#{file}' either does not exist or empty." if !File.exist?(file) || File.zero?(file) - - delete_resources(load_file(file)) + failures = files.flat_map do |file| + resources = read_file(file) + filtered_resources = filter_resources(resources) + delete_resources(filtered_resources) end - puts "\nDone" + return puts "\nDone" if failures.empty? + + puts "\nFailed to delete #{failures.size} resources:\n" + puts failures end private - def load_file(json) - JSON.parse(File.read(json)) + def files + puts "Gathering JSON files...\n" + files = Dir.glob(@file_pattern) + abort("There is no file with this pattern #{@file_pattern}") if files.empty? + + files.reject { |file| File.zero?(file) } + + files end - def delete_resources(resources) - failures = [] + def read_file(file) + JSON.parse(File.read(file)) + end - resources.each_key do |type| - next if resources[type].empty? + def filter_resources(resources) + puts "Filtering resources - Only keep deletable resources...\n" - resources[type].each do |resource| - next if resource_not_found?(resource['api_path']) + transformed_values = resources.transform_values! do |v| + v.reject do |attributes| + attributes['info'] == "with full_path 'gitlab-qa-sandbox-group'" || + attributes['http_method'] == 'get' && !attributes['info']&.include?("with username 'qa-") || + attributes['api_path'] == 'Cannot find resource API path' + end + end + + transformed_values.reject! { |k, v| v.empty? || IGNORED_RESOURCES.include?(k) } + end - msg = resource['info'] ? "#{type} - #{resource['info']}" : "#{type} at #{resource['api_path']}" + def delete_resources(resources) + resources.each_with_object([]) do |(key, value), failures| + value.each do |resource| + next if resource_not_found?(resource['api_path']) + msg = resource['info'] ? "#{key} - #{resource['info']}" : "#{key} at #{resource['api_path']}" puts "\nDeleting #{msg}..." delete_response = delete(Runtime::API::Request.new(@api_client, resource['api_path']).url) - if delete_response.code == 202 + if delete_response.code == 202 || delete_response.code == 204 print "\e[32m.\e[0m" else print "\e[31mF\e[0m" @@ -68,17 +89,11 @@ module QA end end end - - unless failures.empty? - puts "\nFailed to delete #{failures.length} resources:\n" - puts failures - end end def resource_not_found?(api_path) - get_response = get Runtime::API::Request.new(@api_client, api_path).url - - get_response.code.eql? 404 + # if api path contains param "?hard_delete=<boolean>", remove it + get(Runtime::API::Request.new(@api_client, api_path.split('?').first).url).code.eql? 404 end end end diff --git a/qa/qa/tools/initialize_gitlab_auth.rb b/qa/qa/tools/initialize_gitlab_auth.rb index 86791f1f624..18e90f0d739 100644 --- a/qa/qa/tools/initialize_gitlab_auth.rb +++ b/qa/qa/tools/initialize_gitlab_auth.rb @@ -16,7 +16,7 @@ module QA def run Runtime::Scenario.define(:gitlab_address, address) - puts "Signing in and creating the default password for the root user if it's not set already..." + QA::Runtime::Logger.info("Signing in and creating the default password for the root user if it's not set already...") QA::Runtime::Browser.visit(:gitlab, QA::Page::Main::Login) Flow::Login.sign_in diff --git a/qa/qa/tools/reliable_report.rb b/qa/qa/tools/reliable_report.rb index b99b97c1ea6..27e54c2d8bf 100644 --- a/qa/qa/tools/reliable_report.rb +++ b/qa/qa/tools/reliable_report.rb @@ -58,7 +58,7 @@ module QA { title: "Reliable e2e test report", description: report_issue_body, - labels: "Quality,test,type::maintenance,reliable test report" + labels: "Quality,test,type::maintenance,reliable test report,automation:devops-mapping-disable" }, headers: { "PRIVATE-TOKEN" => gitlab_access_token } ) diff --git a/qa/qa/tools/test_resource_data_processor.rb b/qa/qa/tools/test_resource_data_processor.rb index 78fb6ef6cd0..965919dc516 100644 --- a/qa/qa/tools/test_resource_data_processor.rb +++ b/qa/qa/tools/test_resource_data_processor.rb @@ -6,60 +6,81 @@ module QA module Tools class TestResourceDataProcessor - @resources ||= Hash.new { |hsh, key| hsh[key] = [] } + include Singleton + + def initialize + @resources = Hash.new { |hsh, key| hsh[key] = [] } + end class << self - # Ignoring rspec-mocks, sandbox, user and fork resources - # TODO: Will need to figure out which user resources can be collected, ignore for now - # - # Collecting resources created in E2E tests - # Data is a Hash of resources with keys as resource type (group, project, issue, etc.) - # Each type contains an array of resource object (hash) of the same type - # E.g: { "QA::Resource::Project": [ { info: 'foo', api_path: '/foo'}, {...} ] } - def collect(resource, info) - return if resource.api_response.nil? || - resource.is_a?(RSpec::Mocks::Double) || - resource.is_a?(Resource::Sandbox) || - resource.is_a?(Resource::User) || - resource.is_a?(Resource::Fork) + delegate :collect, :write_to_file, :resources, to: :instance + end - api_path = if resource.respond_to?(:api_delete_path) - resource.api_delete_path.gsub('%2F', '/') - elsif resource.respond_to?(:api_get_path) - resource.api_get_path.gsub('%2F', '/') - else - 'Cannot find resource API path' - end + # @return [Hash<String, Array>] + attr_reader :resources - type = resource.class.name + # Collecting resources created in E2E tests + # Data is a Hash of resources with keys as resource type (group, project, issue, etc.) + # Each type contains an array of resource object (hash) of the same type + # E.g: { "QA::Resource::Project": [ { info: 'foo', api_path: '/foo'}, {...} ] } + # + # @param [QA::Resource::Base] resource fabricated resource + # @param [String] info resource info + # @param [Symbol] method fabrication method, api or browser_ui + # @param [Integer] time fabrication time + # @return [Hash] + def collect(resource:, info:, fabrication_method:, fabrication_time:) + api_path = resource_api_path(resource) + type = resource.class.name - @resources[type] << { info: info, api_path: api_path } - end + resources[type] << { + info: info, + api_path: api_path, + fabrication_method: fabrication_method, + fabrication_time: fabrication_time, + http_method: resource.api_fabrication_http_method, + timestamp: Time.now.to_s + } + end + + # If JSON file exists and not empty, read and load file content + # Merge what is saved in @resources into the content from file + # Overwrite file content with the new data hash + # Otherwise create file and write data hash to file for the first time + # + # @return [void] + def write_to_file + return if resources.empty? - # If JSON file exists and not empty, read and load file content - # Merge what is saved in @resources into the content from file - # Overwrite file content with the new data hash - # Otherwise create file and write data hash to file for the first time - def write_to_file - return if @resources.empty? + file = Pathname.new(Runtime::Env.test_resources_created_filepath) + FileUtils.mkdir_p(file.dirname) - file = Runtime::Env.test_resources_created_filepath - FileUtils.mkdir_p('tmp/') - FileUtils.touch(file) - data = nil + data = resources.deep_dup + # merge existing json if present + JSON.parse(File.read(file)).deep_merge!(data) { |key, val, other_val| val + other_val } if file.exist? + + File.write(file, JSON.pretty_generate(data)) + end - if File.zero?(file) - data = @resources - else - data = JSON.parse(File.read(file)) + private - @resources.each_pair do |key, val| - data[key].nil? ? data[key] = val : val.each { |item| data[key] << item } - end - end + # Determine resource api path or return default value + # Some resources fabricated via UI can raise no attribute error + # + # @param [QA::Resource::Base] resource + # @return [String] + def resource_api_path(resource) + default = 'Cannot find resource API path' - File.open(file, 'w') { |f| f.write(JSON.pretty_generate(data.each_value(&:uniq!))) } + if resource.respond_to?(:api_delete_path) + resource.api_delete_path.gsub('%2F', '/') + elsif resource.respond_to?(:api_get_path) + resource.api_get_path.gsub('%2F', '/') + else + default end + rescue QA::Resource::Base::NoValueError + default end end end |