Commit 18b79fd0 authored by Andrejs Cunskis's avatar Andrejs Cunskis Committed by Dan Davison

Store resource fabrication time and http method

Store additional information on resource fabrication

Save only resources that were created in resources.json to pass for
deletion

Store resources fabricated via browser_ui

Make TestResourceDataProcessor a singleton and update unit tests

Rescue NoValue errors for resources fabricated via UI

Filter out resources not applicable for deletion when saving in json
file

Fix calling api_get_path for Fork resource
parent ae702ccd
...@@ -31,7 +31,7 @@ module QA ...@@ -31,7 +31,7 @@ module QA
parents = options.fetch(:parents) { [] } parents = options.fetch(:parents) { [] }
do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
log_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) } log_and_record_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) }
current_url current_url
end end
...@@ -47,7 +47,7 @@ module QA ...@@ -47,7 +47,7 @@ module QA
resource.eager_load_api_client! resource.eager_load_api_client!
do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
log_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! } log_and_record_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! }
end end
end end
...@@ -59,7 +59,7 @@ module QA ...@@ -59,7 +59,7 @@ module QA
resource.eager_load_api_client! resource.eager_load_api_client!
do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
log_fabrication(:api, resource, parents, args) { resource.remove_via_api! } log_and_record_fabrication(:api, resource, parents, args) { resource.remove_via_api! }
end end
end end
...@@ -71,36 +71,19 @@ module QA ...@@ -71,36 +71,19 @@ module QA
resource_web_url = yield resource_web_url = yield
resource.web_url = resource_web_url resource.web_url = resource_web_url
QA::Tools::TestResourceDataProcessor.collect(resource, resource_identifier(resource))
resource resource
end end
def resource_identifier(resource) def log_and_record_fabrication(fabrication_method, resource, parents, args)
if resource.respond_to?(:username) && resource.username
"with username '#{resource.username}'"
elsif resource.respond_to?(:full_path) && resource.full_path
"with full_path '#{resource.full_path}'"
elsif resource.respond_to?(:name) && resource.name
"with name '#{resource.name}'"
elsif resource.respond_to?(:id) && resource.id
"with id '#{resource.id}'"
elsif resource.respond_to?(:iid) && resource.iid
"with iid '#{resource.iid}'"
end
rescue QA::Resource::Base::NoValueError
nil
end
def log_fabrication(method, resource, parents, args)
start = Time.now start = Time.now
Support::FabricationTracker.start_fabrication Support::FabricationTracker.start_fabrication
result = yield.tap do result = yield.tap do
fabrication_time = Time.now - start fabrication_time = Time.now - start
identifier = resource_identifier(resource)
fabrication_http_method = if resource.api_fabrication_http_method == :get fabrication_http_method = if resource.api_fabrication_http_method == :get
if self.include?(Reusable) if include?(Reusable)
"Retrieved for reuse" "Retrieved for reuse"
else else
"Retrieved" "Retrieved"
...@@ -109,16 +92,23 @@ module QA ...@@ -109,16 +92,23 @@ module QA
"Built" "Built"
end end
Support::FabricationTracker.save_fabrication(:"#{method}_fabrication", fabrication_time) Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time)
Tools::TestResourceDataProcessor.collect(
resource: resource,
info: identifier,
fabrication_method: fabrication_method,
fabrication_time: fabrication_time
)
Runtime::Logger.debug do Runtime::Logger.debug do
msg = ["==#{'=' * parents.size}>"] msg = ["==#{'=' * parents.size}>"]
msg << "#{fabrication_http_method} a #{name}" msg << "#{fabrication_http_method} a #{name}"
msg << resource_identifier(resource) if resource_identifier(resource) msg << identifier
msg << "as a dependency of #{parents.last}" if parents.any? msg << "as a dependency of #{parents.last}" if parents.any?
msg << "via #{method}" msg << "via #{fabrication_method}"
msg << "in #{fabrication_time} seconds" msg << "in #{fabrication_time} seconds"
msg.join(' ') msg.compact.join(' ')
end end
end end
Support::FabricationTracker.finish_fabrication Support::FabricationTracker.finish_fabrication
...@@ -126,6 +116,26 @@ module QA ...@@ -126,6 +116,26 @@ module QA
result result
end end
# Unique resource identifier
#
# @param [QA::Resource::Base] resource
# @return [String]
def resource_identifier(resource)
if resource.respond_to?(:username) && resource.username
"with username '#{resource.username}'"
elsif resource.respond_to?(:full_path) && resource.full_path
"with full_path '#{resource.full_path}'"
elsif resource.respond_to?(:name) && resource.name
"with name '#{resource.name}'"
elsif resource.respond_to?(:id) && resource.id
"with id '#{resource.id}'"
elsif resource.respond_to?(:iid) && resource.iid
"with iid '#{resource.iid}'"
end
rescue QA::Resource::Base::NoValueError
nil
end
# Define custom attribute # Define custom attribute
# #
# @param [Symbol] name # @param [Symbol] name
......
...@@ -31,6 +31,8 @@ module QA ...@@ -31,6 +31,8 @@ module QA
end end
end end
delegate :path_with_namespace, to: :project
def fabricate! def fabricate!
populate(:upstream, :user) populate(:upstream, :user)
......
...@@ -50,12 +50,6 @@ module QA ...@@ -50,12 +50,6 @@ module QA
resource_web_url(api_get) resource_web_url(api_get)
rescue ResourceNotFoundError rescue ResourceNotFoundError
super super
Support::Retrier.retry_on_exception(sleep_interval: 5) do
resource = resource_web_url(api_get)
populate(:runners_token)
resource
end
end end
def api_get_path def api_get_path
......
...@@ -51,14 +51,6 @@ module QA ...@@ -51,14 +51,6 @@ module QA
resource_web_url(api_get) resource_web_url(api_get)
rescue ResourceNotFoundError rescue ResourceNotFoundError
super super
# If the group was just created the runners token might not be
# available via the API immediately.
Support::Retrier.retry_on_exception(sleep_interval: 5) do
resource = resource_web_url(api_get)
populate(:runners_token)
resource
end
end end
def api_get_path def api_get_path
......
...@@ -25,7 +25,7 @@ module QA ...@@ -25,7 +25,7 @@ module QA
Resource::Runner.fabricate! do |runner| Resource::Runner.fabricate! do |runner|
runner.name = executor runner.name = executor
runner.tags = [executor] runner.tags = [executor]
runner.token = group.sandbox.runners_token runner.token = group.reload!.runners_token
end end
end end
......
...@@ -50,7 +50,7 @@ module QA ...@@ -50,7 +50,7 @@ module QA
runner.name = "qa-runner-#{Time.now.to_i}" runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.group.name}"] runner.tags = ["runner-for-#{project.group.name}"]
runner.executor = :docker runner.executor = :docker
runner.token = project.group.runners_token runner.token = project.group.reload!.runners_token
end end
end end
......
...@@ -53,7 +53,7 @@ module QA ...@@ -53,7 +53,7 @@ module QA
runner.name = "qa-runner-#{Time.now.to_i}" runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.group.name}"] runner.tags = ["runner-for-#{project.group.name}"]
runner.executor = :docker runner.executor = :docker
runner.token = project.group.runners_token runner.token = project.group.reload!.runners_token
end end
end end
......
...@@ -23,7 +23,7 @@ module QA ...@@ -23,7 +23,7 @@ module QA
let!(:runner) do let!(:runner) do
Resource::Runner.fabricate! do |runner| Resource::Runner.fabricate! do |runner|
runner.project = upstream_project runner.project = upstream_project
runner.token = upstream_project.group.sandbox.runners_token runner.token = upstream_project.group.reload!.runners_token
runner.name = executor runner.name = executor
runner.tags = [executor] runner.tags = [executor]
end end
......
...@@ -23,7 +23,7 @@ module QA ...@@ -23,7 +23,7 @@ module QA
let!(:runner) do let!(:runner) do
Resource::Runner.fabricate_via_api! do |runner| Resource::Runner.fabricate_via_api! do |runner|
runner.token = group.sandbox.runners_token runner.token = group.reload!.runners_token
runner.name = executor runner.name = executor
runner.tags = [executor] runner.tags = [executor]
end end
......
...@@ -14,40 +14,38 @@ module QA ...@@ -14,40 +14,38 @@ module QA
return log(:warn, 'Missing QA_INFLUXDB_URL, skipping metrics export!') unless influxdb_url return log(:warn, 'Missing QA_INFLUXDB_URL, skipping metrics export!') unless influxdb_url
return log(:warn, 'Missing QA_INFLUXDB_TOKEN, skipping metrics export!') unless influxdb_token return log(:warn, 'Missing QA_INFLUXDB_TOKEN, skipping metrics export!') unless influxdb_token
data = notification.examples.map { |example| test_stats(example) }.compact push_test_stats(notification.examples)
influx_client.create_write_api.write(data: data) push_fabrication_stats
log(:info, "Pushed #{data.length} entries to influxdb")
rescue StandardError => e
log(:error, "Failed to push data to influxdb, error: #{e}")
end end
private private
# InfluxDb client # Push test execution stats to influxdb
# #
# @return [InfluxDB2::Client] # @param [Array<RSpec::Core::Example>] examples
def influx_client # @return [void]
@influx_client ||= InfluxDB2::Client.new( def push_test_stats(examples)
influxdb_url, data = examples.map { |example| test_stats(example) }.compact
influxdb_token,
bucket: 'e2e-test-stats',
org: 'gitlab-qa',
precision: InfluxDB2::WritePrecision::NANOSECOND
)
end
# InfluxDb instance url influx_client.write(data: data)
# log(:debug, "Pushed #{data.length} test execution entries to influxdb")
# @return [String] rescue StandardError => e
def influxdb_url log(:error, "Failed to push test execution stats to influxdb, error: #{e}")
@influxdb_url ||= env('QA_INFLUXDB_URL')
end end
# Influxdb token # Push resource fabrication stats to influxdb
# #
# @return [String] # @return [void]
def influxdb_token def push_fabrication_stats
@influxdb_token ||= env('QA_INFLUXDB_TOKEN') data = Tools::TestResourceDataProcessor.resources.flat_map do |resource, values|
values.map { |v| fabrication_stats(resource: resource, **v) }
end
return if data.empty?
influx_client.write(data: data)
log(:debug, "Pushed #{data.length} resource fabrication entries to influxdb")
rescue StandardError => e
log(:error, "Failed to push fabrication stats to influxdb, error: #{e}")
end end
# Transform example to influxdb compatible metrics data # Transform example to influxdb compatible metrics data
...@@ -93,6 +91,33 @@ module QA ...@@ -93,6 +91,33 @@ module QA
nil nil
end end
# Resource fabrication data point
#
# @param [String] resource
# @param [String] info
# @param [Symbol] fabrication_method
# @param [Symbol] http_method
# @param [Integer] fabrication_time
# @return [Hash]
def fabrication_stats(resource:, info:, fabrication_method:, http_method:, fabrication_time:, **)
{
name: 'fabrication-stats',
time: time,
tags: {
resource: resource,
fabrication_method: fabrication_method,
http_method: http_method,
run_type: env('QA_RUN_TYPE') || run_type,
merge_request: merge_request
},
fields: {
fabrication_time: fabrication_time,
info: info,
job_url: QA::Runtime::Env.ci_job_url
}
}
end
# Project name # Project name
# #
# @return [String] # @return [String]
...@@ -150,7 +175,7 @@ module QA ...@@ -150,7 +175,7 @@ module QA
# @param [String] message # @param [String] message
# @return [void] # @return [void]
def log(level, message) def log(level, message)
QA::Runtime::Logger.public_send(level, "influxdb exporter: #{message}") QA::Runtime::Logger.public_send(level, "[influxdb exporter]: #{message}")
end end
# Return non empty environment variable value # Return non empty environment variable value
...@@ -170,6 +195,33 @@ module QA ...@@ -170,6 +195,33 @@ module QA
def devops_stage(file_path) def devops_stage(file_path)
file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first
end end
# InfluxDb client
#
# @return [InfluxDB2::WriteApi]
def influx_client
@influx_client ||= InfluxDB2::Client.new(
influxdb_url,
influxdb_token,
bucket: 'e2e-test-stats',
org: 'gitlab-qa',
precision: InfluxDB2::WritePrecision::NANOSECOND
).create_write_api
end
# InfluxDb instance url
#
# @return [String]
def influxdb_url
@influxdb_url ||= env('QA_INFLUXDB_URL')
end
# Influxdb token
#
# @return [String]
def influxdb_token
@influxdb_token ||= env('QA_INFLUXDB_TOKEN')
end
end end
end end
end end
......
...@@ -6,60 +6,80 @@ ...@@ -6,60 +6,80 @@
module QA module QA
module Tools module Tools
class TestResourceDataProcessor class TestResourceDataProcessor
@resources ||= Hash.new { |hsh, key| hsh[key] = [] } include Singleton
def initialize
@resources = Hash.new { |hsh, key| hsh[key] = [] }
end
class << self class << self
# Ignoring rspec-mocks, sandbox, user and fork resources delegate :collect, :write_to_file, :resources, to: :instance
# TODO: Will need to figure out which user resources can be collected, ignore for now end
#
# 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)
api_path = if resource.respond_to?(:api_delete_path) # @return [Hash<String, Array>]
resource.api_delete_path.gsub('%2F', '/') attr_reader :resources
elsif resource.respond_to?(:api_get_path)
resource.api_get_path.gsub('%2F', '/')
else
'Cannot find resource API path'
end
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 } resources[type] << {
end info: info,
api_path: api_path,
fabrication_method: fabrication_method,
fabrication_time: fabrication_time,
http_method: resource.api_fabrication_http_method
}
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 file = Pathname.new(Runtime::Env.test_resources_created_filepath)
# Merge what is saved in @resources into the content from file FileUtils.mkdir_p(file.dirname)
# 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 = Runtime::Env.test_resources_created_filepath data = resources.deep_dup
FileUtils.mkdir_p('tmp/') # merge existing json if present
FileUtils.touch(file) JSON.parse(File.read(file)).deep_merge!(data) { |key, val, other_val| val + other_val } if file.exist?
data = nil
File.write(file, JSON.pretty_generate(data))
end
if File.zero?(file) private
data = @resources
else
data = JSON.parse(File.read(file))
@resources.each_pair do |key, val| # Determine resource api path or return default value
data[key].nil? ? data[key] = val : val.each { |item| data[key] << item } # Some resources fabricated via UI can raise no attribute error
end #
end # @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 end
rescue QA::Resource::Base::NoValueError
default
end end
end end
end end
......
...@@ -7,6 +7,11 @@ RSpec.describe QA::Resource::Base do ...@@ -7,6 +7,11 @@ RSpec.describe QA::Resource::Base do
let(:location) { 'http://location' } let(:location) { 'http://location' }
let(:log_regex) { %r{==> Built a MyResource with username 'qa' via #{method} in [\d.\-e]+ seconds+} } let(:log_regex) { %r{==> Built a MyResource with username 'qa' via #{method} in [\d.\-e]+ seconds+} }
before do
allow(QA::Tools::TestResourceDataProcessor).to receive(:collect)
allow(QA::Tools::TestResourceDataProcessor).to receive(:write_to_file)
end
shared_context 'with fabrication context' do shared_context 'with fabrication context' do
subject do subject do
Class.new(described_class) do Class.new(described_class) do
......
...@@ -22,6 +22,7 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -22,6 +22,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
let(:file_path) { "./qa/specs/features/#{stage}/subfolder/some_spec.rb" } let(:file_path) { "./qa/specs/features/#{stage}/subfolder/some_spec.rb" }
let(:ui_fabrication) { 0 } let(:ui_fabrication) { 0 }
let(:api_fabrication) { 0 } let(:api_fabrication) { 0 }
let(:fabrication_resources) { {} }
let(:influx_client_args) do let(:influx_client_args) do
{ {
...@@ -88,6 +89,7 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -88,6 +89,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
before do before do
allow(InfluxDB2::Client).to receive(:new).with(url, token, **influx_client_args) { influx_client } allow(InfluxDB2::Client).to receive(:new).with(url, token, **influx_client_args) { influx_client }
allow(QA::Tools::TestResourceDataProcessor).to receive(:resources) { fabrication_resources }
end end
context "without influxdb variables configured" do context "without influxdb variables configured" do
...@@ -135,6 +137,7 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -135,6 +137,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
it('spec', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {} it('spec', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
end end
expect(influx_write_api).to have_received(:write).once
expect(influx_write_api).to have_received(:write).with(data: [data]) expect(influx_write_api).to have_received(:write).with(data: [data])
end end
end end
...@@ -147,6 +150,7 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -147,6 +150,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
it('spec', :quarantine, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {} it('spec', :quarantine, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
end end
expect(influx_write_api).to have_received(:write).once
expect(influx_write_api).to have_received(:write).with(data: [data]) expect(influx_write_api).to have_received(:write).with(data: [data])
end end
end end
...@@ -162,6 +166,7 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -162,6 +166,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
it 'exports data to influxdb with correct run type' do it 'exports data to influxdb with correct run type' do
run_spec run_spec
expect(influx_write_api).to have_received(:write).once
expect(influx_write_api).to have_received(:write).with(data: [data]) expect(influx_write_api).to have_received(:write).with(data: [data])
end end
end end
...@@ -179,6 +184,7 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -179,6 +184,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
it 'exports data to influxdb with correct run type' do it 'exports data to influxdb with correct run type' do
run_spec run_spec
expect(influx_write_api).to have_received(:write).once
expect(influx_write_api).to have_received(:write).with(data: [data]) expect(influx_write_api).to have_received(:write).with(data: [data])
end end
end end
...@@ -195,8 +201,48 @@ describe QA::Support::Formatters::TestStatsFormatter do ...@@ -195,8 +201,48 @@ describe QA::Support::Formatters::TestStatsFormatter do
it 'exports data to influxdb with fabrication times' do it 'exports data to influxdb with fabrication times' do
run_spec run_spec
expect(influx_write_api).to have_received(:write).once
expect(influx_write_api).to have_received(:write).with(data: [data]) expect(influx_write_api).to have_received(:write).with(data: [data])
end end
end end
context 'with fabrication resources' do
let(:fabrication_resources) do
{
'QA::Resource::Project' => [{
info: "with id '1'",
api_path: '/project',
fabrication_method: :api,
fabrication_time: 1,
http_method: :post
}]
}
end
let(:fabrication_data) do
{
name: 'fabrication-stats',
time: DateTime.strptime(ci_timestamp).to_time,
tags: {
resource: 'QA::Resource::Project',
fabrication_method: :api,
http_method: :post,
run_type: run_type,
merge_request: "false"
},
fields: {
fabrication_time: 1,
info: "with id '1'",
job_url: ci_job_url
}
}
end
it 'exports fabrication stats data to influxdb' do
run_spec
expect(influx_write_api).to have_received(:write).with(data: [fabrication_data])
end
end
end end
end end
...@@ -32,7 +32,7 @@ module QA ...@@ -32,7 +32,7 @@ module QA
runner.name = "qa-runner-#{Time.now.to_i}" runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{package_project.group.name}"] runner.tags = ["runner-for-#{package_project.group.name}"]
runner.executor = :docker runner.executor = :docker
runner.token = package_project.group.runners_token runner.token = package_project.group.reload!.runners_token
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe QA::Tools::TestResourceDataProcessor do RSpec.describe QA::Tools::TestResourceDataProcessor do
include QA::Support::Helpers::StubEnv
subject(:processor) { Class.new(described_class).instance }
let(:info) { 'information' } let(:info) { 'information' }
let(:api_path) { '/foo' } let(:api_response) { {} }
let(:result) { [{ info: info, api_path: api_path }] } let(:method) { :api }
let(:time) { 2 }
let(:api_path) { resource.api_delete_path }
let(:resource) { QA::Resource::Project.init { |project| project.id = 1 } }
describe '.collect' do let(:result) do
context 'when resource is not restricted' do {
let(:resource) { instance_double(QA::Resource::Project, api_delete_path: '/foo', api_response: 'foo') } 'QA::Resource::Project' => [{
info: info,
api_path: api_path,
fabrication_method: method,
fabrication_time: time,
http_method: :post
}]
}
end
it 'collects resource' do before do
expect(described_class.collect(resource, info)).to eq(result) processor.collect(resource: resource, info: info, fabrication_method: method, fabrication_time: time)
end end
describe '.collect' do
it 'collects and stores resource' do
expect(processor.resources).to eq(result)
end end
end
describe '.write_to_file' do
let(:resources_file) { Pathname.new(Faker::File.file_name(dir: 'tmp', ext: 'json')) }
context 'when resource api response is nil' do before do
let(:resource) { double(QA::Resource::Project, api_delete_path: '/foo', api_response: nil) } stub_env('QA_TEST_RESOURCES_CREATED_FILEPATH', resources_file)
it 'does not collect resource' do allow(File).to receive(:write)
expect(described_class.collect(resource, info)).to eq(nil)
end
end end
context 'when resource is restricted' do it 'writes applicable resources to file' do
let(:resource) { double(QA::Resource::Sandbox, api_delete_path: '/foo', api_response: 'foo') } processor.write_to_file
it 'does not collect resource' do expect(File).to have_received(:write).with(resources_file, JSON.pretty_generate(result))
expect(described_class.collect(resource, info)).to eq(nil)
end
end 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