foreman_rh_cloud 12.2.5 → 12.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +12 -7
- data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +4 -4
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +4 -4
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/insights_cloud/async/vmaas_reposcan_sync.rb +71 -0
- data/lib/insights_cloud.rb +4 -0
- data/package.json +1 -1
- data/test/jobs/queue_for_upload_job_test.rb +63 -0
- data/test/jobs/upload_report_job_test.rb +2 -1
- data/test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb +137 -0
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72c0454c0e34313e47f06f3da48616dc6030ad4e253ee09b7180ad57fb40c658
|
4
|
+
data.tar.gz: 2ba96de28fb86c571fc49bab18d0fd7449539bf0292d4d16fdf3840a91845575
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98f812e64bf664dba79c550efac4b378a079c199591d8ddf1e4dbba19315db93421c7266ee3e4c9d0c7de4e89c1622bda2de32cb987b6837822362192cf4eff6
|
7
|
+
data.tar.gz: b1894fac6ea9fee921425195313532923389b4948d90887caac55564ed71109dc21b0eafca14fbe32961bb72ee6798aa911ad48687f6321d871fb1c199b51fc5
|
@@ -14,13 +14,14 @@ module ForemanInventoryUpload
|
|
14
14
|
hosts_filter: hosts_filter
|
15
15
|
)
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
unless content_disconnected?(disconnected)
|
18
|
+
plan_action(
|
19
|
+
QueueForUploadJob,
|
20
|
+
base_folder,
|
21
|
+
ForemanInventoryUpload.facts_archive_name(organization_id, hosts_filter),
|
22
|
+
organization_id
|
23
|
+
)
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -40,6 +41,10 @@ module ForemanInventoryUpload
|
|
40
41
|
)
|
41
42
|
end
|
42
43
|
|
44
|
+
def content_disconnected?(disconnected)
|
45
|
+
disconnected || !Setting[:subscription_connection_enabled]
|
46
|
+
end
|
47
|
+
|
43
48
|
def base_folder
|
44
49
|
input[:base_folder]
|
45
50
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module ForemanInventoryUpload
|
2
2
|
module Async
|
3
3
|
class QueueForUploadJob < ::Actions::EntryAction
|
4
|
-
def plan(base_folder, report_file, organization_id
|
4
|
+
def plan(base_folder, report_file, organization_id)
|
5
5
|
enqueue_task = plan_self(base_folder: base_folder, report_file: report_file)
|
6
|
-
plan_upload_report(enqueue_task.output[:enqueued_file_name], organization_id
|
6
|
+
plan_upload_report(enqueue_task.output[:enqueued_file_name], organization_id)
|
7
7
|
end
|
8
8
|
|
9
9
|
def run
|
@@ -59,8 +59,8 @@ module ForemanInventoryUpload
|
|
59
59
|
input[:report_file]
|
60
60
|
end
|
61
61
|
|
62
|
-
def plan_upload_report(enqueued_file_name, organization_id
|
63
|
-
plan_action(UploadReportJob, enqueued_file_name, organization_id
|
62
|
+
def plan_upload_report(enqueued_file_name, organization_id)
|
63
|
+
plan_action(UploadReportJob, enqueued_file_name, organization_id)
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -7,15 +7,15 @@ module ForemanInventoryUpload
|
|
7
7
|
"upload_for_#{label}"
|
8
8
|
end
|
9
9
|
|
10
|
-
def plan(filename, organization_id
|
10
|
+
def plan(filename, organization_id)
|
11
11
|
label = UploadReportJob.output_label(organization_id)
|
12
|
-
super(label, filename: filename, organization_id: organization_id
|
12
|
+
super(label, filename: filename, organization_id: organization_id)
|
13
13
|
end
|
14
14
|
|
15
15
|
def try_execute
|
16
16
|
if content_disconnected?
|
17
17
|
progress_output do |progress_output|
|
18
|
-
progress_output.write_line(
|
18
|
+
progress_output.write_line("Report was not moved and upload was canceled because connection to Insights is not enabled. Report location: #{filename}.")
|
19
19
|
progress_output.status = "Task aborted, exit 1"
|
20
20
|
done!
|
21
21
|
end
|
@@ -89,7 +89,7 @@ module ForemanInventoryUpload
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def content_disconnected?
|
92
|
-
|
92
|
+
!Setting[:subscription_connection_enabled]
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
module InsightsCloud
|
4
|
+
module Async
|
5
|
+
# Triggers VMaaS reposcan sync via IoP gateway when repositories are synced
|
6
|
+
class VmaasReposcanSync < ::Actions::EntryAction
|
7
|
+
include ::ForemanRhCloud::CertAuth
|
8
|
+
|
9
|
+
# Subscribe to Katello repository sync hook action, if available
|
10
|
+
def self.subscribe
|
11
|
+
'Actions::Katello::Repository::SyncHook'.constantize
|
12
|
+
rescue NameError
|
13
|
+
Rails.logger.debug('VMaaS reposcan sync: Repository::SyncHook action not found')
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def plan(repo, *_args)
|
18
|
+
return unless ::ForemanRhCloud.with_iop_smart_proxy?
|
19
|
+
|
20
|
+
repo_id = repo.is_a?(Hash) ? (repo[:id] || repo['id']) : nil
|
21
|
+
unless repo_id
|
22
|
+
logger.error("VMaaS reposcan sync: missing repository id in SyncHook plan parameters: #{repo.inspect}")
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
plan_self
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
url = ::InsightsCloud.vmaas_reposcan_sync_url
|
31
|
+
|
32
|
+
response = execute_cloud_request(
|
33
|
+
method: :put,
|
34
|
+
url: url,
|
35
|
+
headers: { 'Content-Type' => 'application/json' }
|
36
|
+
)
|
37
|
+
|
38
|
+
if response.code >= 200 && response.code < 300
|
39
|
+
message = "VMaaS reposcan sync triggered successfully: #{response.code}"
|
40
|
+
logger.info(message)
|
41
|
+
else
|
42
|
+
message = "VMaaS reposcan sync failed with status: #{response.code}, body: #{response.body}"
|
43
|
+
logger.error(message)
|
44
|
+
end
|
45
|
+
output[:message] = message
|
46
|
+
|
47
|
+
response
|
48
|
+
rescue RestClient::ExceptionWithResponse => e
|
49
|
+
message = "VMaaS reposcan sync failed: #{e.response&.code} - #{e.response&.body}"
|
50
|
+
logger.error(message)
|
51
|
+
output[:message] = message
|
52
|
+
raise
|
53
|
+
rescue StandardError => e
|
54
|
+
message = "Error triggering VMaaS reposcan sync: #{e.message}, response: #{e.respond_to?(:response) ? e.response : nil}"
|
55
|
+
logger.error(message)
|
56
|
+
output[:message] = message
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
|
60
|
+
def rescue_strategy_for_self
|
61
|
+
Dynflow::Action::Rescue::Skip
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def logger
|
67
|
+
action_logger
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/insights_cloud.rb
CHANGED
data/package.json
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
require 'foreman_tasks/test_helpers'
|
3
|
+
|
4
|
+
class QueueForUploadJobTest < ActiveSupport::TestCase
|
5
|
+
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
6
|
+
include FolderIsolation
|
7
|
+
|
8
|
+
let(:organization) { FactoryBot.create(:organization) }
|
9
|
+
let(:base_folder) { @tmpdir }
|
10
|
+
let(:report_file) { 'test_report.tar.xz' }
|
11
|
+
let(:report_path) { File.join(base_folder, report_file) }
|
12
|
+
let(:uploads_folder) { ForemanInventoryUpload.uploads_folder }
|
13
|
+
subject { ForemanTasks.sync_task(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization.id) }
|
14
|
+
|
15
|
+
setup do
|
16
|
+
# Stub the script template source
|
17
|
+
script_source = File.join(ForemanRhCloud::Engine.root, 'lib/foreman_inventory_upload/scripts/uploader.sh.erb')
|
18
|
+
File.stubs(:read).with(script_source).returns('#!/bin/bash\necho "Test script"')
|
19
|
+
|
20
|
+
# Stub template rendering
|
21
|
+
Foreman::Renderer.stubs(:render).returns('#!/bin/bash\necho "Rendered script"')
|
22
|
+
|
23
|
+
# Stub additional settings that are accessed
|
24
|
+
Setting.stubs(:[]).with(:content_default_http_proxy).returns(nil)
|
25
|
+
Setting.stubs(:[]).with(:http_proxy).returns(nil)
|
26
|
+
Setting.stubs(:[]).with("foreman_tasks_sync_task_timeout").returns(120)
|
27
|
+
FileUtils.touch(report_path)
|
28
|
+
end
|
29
|
+
|
30
|
+
teardown do
|
31
|
+
FileUtils.rm_rf(uploads_folder) if Dir.exist?(uploads_folder)
|
32
|
+
end
|
33
|
+
|
34
|
+
test 'plan method sets up the job correctly and calls plan_upload_report' do
|
35
|
+
# Mock plan_upload_report to verify it's called
|
36
|
+
ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.expects(:plan_upload_report).once
|
37
|
+
|
38
|
+
assert_equal 'success', subject.result
|
39
|
+
end
|
40
|
+
|
41
|
+
test 'run method processes file and moves it to uploads folder' do
|
42
|
+
ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.stubs(:plan_upload_report)
|
43
|
+
|
44
|
+
assert_equal 'success', subject.result
|
45
|
+
|
46
|
+
# Verify the file was moved
|
47
|
+
refute File.exist?(report_path), "Original file should be moved"
|
48
|
+
assert File.exist?(File.join(uploads_folder, report_file)), "File should exist in uploads folder"
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'creates necessary folders and scripts' do
|
52
|
+
ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.stubs(:plan_upload_report)
|
53
|
+
|
54
|
+
assert_equal 'success', subject.result
|
55
|
+
|
56
|
+
# Verify the uploads folder was created
|
57
|
+
assert Dir.exist?(uploads_folder), "Uploads folder should be created"
|
58
|
+
|
59
|
+
# Verify the script file was created
|
60
|
+
script_path = File.join(uploads_folder, ForemanInventoryUpload.upload_script_file)
|
61
|
+
assert File.exist?(script_path), "Upload script should be created"
|
62
|
+
end
|
63
|
+
end
|
@@ -18,7 +18,8 @@ class UploadReportJobTest < ActiveSupport::TestCase
|
|
18
18
|
|
19
19
|
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
20
20
|
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
21
|
-
assert_match(/
|
21
|
+
assert_match(/upload was canceled because connection to Insights is not enabled/, progress_output.full_output)
|
22
|
+
assert_match(/Report location:/, progress_output.full_output)
|
22
23
|
assert_match(/exit 1/, progress_output.status)
|
23
24
|
end
|
24
25
|
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
require 'foreman_tasks/test_helpers'
|
3
|
+
|
4
|
+
class VmaasReposcanSyncTest < ActiveSupport::TestCase
|
5
|
+
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@repo_payload = { id: 123 }
|
9
|
+
@expected_url = 'https://example.com/api/v1/vmaas/reposcan/sync'
|
10
|
+
InsightsCloud.stubs(:vmaas_reposcan_sync_url).returns(@expected_url)
|
11
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Planning behavior
|
15
|
+
test 'plan plans_self when repo payload has id and IoP is available' do
|
16
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).once
|
17
|
+
|
18
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
19
|
+
end
|
20
|
+
|
21
|
+
test 'plan does not plan_self when repo payload is missing id' do
|
22
|
+
payload_without_id = {}
|
23
|
+
|
24
|
+
mock_logger = mock('logger')
|
25
|
+
mock_logger.expects(:error).with { |msg| msg =~ /missing repository id/i }
|
26
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
|
27
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
|
28
|
+
|
29
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, payload_without_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'plan does not plan_self when IoP smart proxy is not available' do
|
33
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
34
|
+
|
35
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
|
36
|
+
|
37
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'plan skips repo_id validation when IoP smart proxy is not available' do
|
41
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
42
|
+
payload_without_id = {}
|
43
|
+
|
44
|
+
# Logger should not be called since IoP check returns early
|
45
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:logger).never
|
46
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
|
47
|
+
|
48
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, payload_without_id)
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'plan does not plan_self when repository is nil' do
|
52
|
+
mock_logger = mock('logger')
|
53
|
+
mock_logger.expects(:error).with { |msg| msg =~ /missing repository id/i }
|
54
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
|
55
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
|
56
|
+
|
57
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Run behavior
|
61
|
+
test 'run triggers VMaaS reposcan sync successfully' do
|
62
|
+
mock_response = mock('response')
|
63
|
+
mock_response.stubs(:code).returns(200)
|
64
|
+
|
65
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
66
|
+
.expects(:execute_cloud_request)
|
67
|
+
.with do |params|
|
68
|
+
params[:method] == :put &&
|
69
|
+
params[:url] == @expected_url &&
|
70
|
+
params[:headers].is_a?(Hash) &&
|
71
|
+
params[:headers]['Content-Type'] == 'application/json'
|
72
|
+
end
|
73
|
+
.returns(mock_response)
|
74
|
+
|
75
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
76
|
+
|
77
|
+
assert_equal 'VMaaS reposcan sync triggered successfully: 200', task.output[:message]
|
78
|
+
end
|
79
|
+
|
80
|
+
test 'run sets error message in task output for failed response' do
|
81
|
+
mock_response = mock('response')
|
82
|
+
mock_response.stubs(:code).returns(500)
|
83
|
+
mock_response.stubs(:body).returns('Internal Server Error')
|
84
|
+
|
85
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
86
|
+
.stubs(:execute_cloud_request)
|
87
|
+
.returns(mock_response)
|
88
|
+
|
89
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
90
|
+
|
91
|
+
assert_equal 'VMaaS reposcan sync failed with status: 500, body: Internal Server Error', task.output[:message]
|
92
|
+
end
|
93
|
+
|
94
|
+
test 'run sets error message in task output for RestClient exception' do
|
95
|
+
error_response = mock('error_response')
|
96
|
+
error_response.stubs(:code).returns(500)
|
97
|
+
error_response.stubs(:body).returns('Server Error')
|
98
|
+
exception = RestClient::ExceptionWithResponse.new(error_response)
|
99
|
+
|
100
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
101
|
+
.stubs(:execute_cloud_request)
|
102
|
+
.raises(exception)
|
103
|
+
|
104
|
+
error = assert_raises(ForemanTasks::TaskError) do
|
105
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
106
|
+
end
|
107
|
+
|
108
|
+
assert_equal 'VMaaS reposcan sync failed: 500 - Server Error', error.task.output[:message]
|
109
|
+
end
|
110
|
+
|
111
|
+
test 'run sets error message in task output for StandardError exception' do
|
112
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
113
|
+
.stubs(:execute_cloud_request)
|
114
|
+
.raises(StandardError.new('Network timeout'))
|
115
|
+
|
116
|
+
error = assert_raises(ForemanTasks::TaskError) do
|
117
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
118
|
+
end
|
119
|
+
|
120
|
+
# The task is available via main_action
|
121
|
+
assert_match(/Error triggering VMaaS reposcan sync: Network timeout, response: /,
|
122
|
+
error.task.main_action.output[:message])
|
123
|
+
end
|
124
|
+
|
125
|
+
test 'run logs and re-raises when cloud request returns error response' do
|
126
|
+
error_response = mock('error_response', code: 500, body: 'error')
|
127
|
+
exception = RestClient::ExceptionWithResponse.new(error_response)
|
128
|
+
|
129
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
130
|
+
.stubs(:execute_cloud_request)
|
131
|
+
.raises(exception)
|
132
|
+
|
133
|
+
assert_raises(ForemanTasks::TaskError) do
|
134
|
+
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_rh_cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 12.2.
|
4
|
+
version: 12.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Foreman Red Hat Cloud team
|
@@ -217,6 +217,7 @@ files:
|
|
217
217
|
- lib/insights_cloud/async/insights_rules_sync.rb
|
218
218
|
- lib/insights_cloud/async/insights_scheduled_sync.rb
|
219
219
|
- lib/insights_cloud/async/rules_result.rb
|
220
|
+
- lib/insights_cloud/async/vmaas_reposcan_sync.rb
|
220
221
|
- lib/insights_cloud/generators/playbook_progress_generator.rb
|
221
222
|
- lib/insights_vulnerability.rb
|
222
223
|
- lib/inventory_sync/async/host_result.rb
|
@@ -267,6 +268,7 @@ files:
|
|
267
268
|
- test/jobs/inventory_hosts_sync_test.rb
|
268
269
|
- test/jobs/inventory_scheduled_sync_test.rb
|
269
270
|
- test/jobs/inventory_self_host_sync_test.rb
|
271
|
+
- test/jobs/queue_for_upload_job_test.rb
|
270
272
|
- test/jobs/remove_insights_hosts_job_test.rb
|
271
273
|
- test/jobs/upload_report_job_test.rb
|
272
274
|
- test/models/insights_client_report_status_test.rb
|
@@ -275,6 +277,7 @@ files:
|
|
275
277
|
- test/unit/fact_helpers_test.rb
|
276
278
|
- test/unit/foreman_rh_cloud_self_host_test.rb
|
277
279
|
- test/unit/insights_facet_test.rb
|
280
|
+
- test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb
|
278
281
|
- test/unit/metadata_generator_test.rb
|
279
282
|
- test/unit/playbook_progress_generator_test.rb
|
280
283
|
- test/unit/rh_cloud_http_proxy_test.rb
|
@@ -719,6 +722,7 @@ test_files:
|
|
719
722
|
- test/jobs/inventory_hosts_sync_test.rb
|
720
723
|
- test/jobs/inventory_scheduled_sync_test.rb
|
721
724
|
- test/jobs/inventory_self_host_sync_test.rb
|
725
|
+
- test/jobs/queue_for_upload_job_test.rb
|
722
726
|
- test/jobs/remove_insights_hosts_job_test.rb
|
723
727
|
- test/jobs/upload_report_job_test.rb
|
724
728
|
- test/models/insights_client_report_status_test.rb
|
@@ -727,6 +731,7 @@ test_files:
|
|
727
731
|
- test/unit/fact_helpers_test.rb
|
728
732
|
- test/unit/foreman_rh_cloud_self_host_test.rb
|
729
733
|
- test/unit/insights_facet_test.rb
|
734
|
+
- test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb
|
730
735
|
- test/unit/metadata_generator_test.rb
|
731
736
|
- test/unit/playbook_progress_generator_test.rb
|
732
737
|
- test/unit/rh_cloud_http_proxy_test.rb
|