foreman_rh_cloud 12.2.16 → 13.0.0

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_rh_cloud/locale/fr/foreman_rh_cloud.js +24 -78
  3. data/app/assets/javascripts/foreman_rh_cloud/locale/ja/foreman_rh_cloud.js +24 -78
  4. data/app/assets/javascripts/foreman_rh_cloud/locale/ka/foreman_rh_cloud.js +23 -77
  5. data/app/assets/javascripts/foreman_rh_cloud/locale/ko/foreman_rh_cloud.js +23 -77
  6. data/app/assets/javascripts/foreman_rh_cloud/locale/zh_CN/foreman_rh_cloud.js +23 -77
  7. data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +3 -5
  8. data/app/controllers/foreman_inventory_upload/accounts_controller.rb +1 -1
  9. data/app/controllers/foreman_inventory_upload/uploads_controller.rb +1 -1
  10. data/app/controllers/insights_cloud/ui_requests_controller.rb +3 -2
  11. data/app/models/concerns/rh_cloud_host.rb +0 -14
  12. data/app/models/foreman_rh_cloud/ping.rb +1 -2
  13. data/app/models/insights_hit.rb +1 -1
  14. data/app/services/foreman_rh_cloud/cert_auth.rb +3 -13
  15. data/app/services/foreman_rh_cloud/gateway_request.rb +26 -0
  16. data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +1 -3
  17. data/app/services/foreman_rh_cloud/tags_auth.rb +4 -15
  18. data/app/views/api/v2/advisor_engine/host_details.json.rabl +3 -1
  19. data/app/views/api/v2/hosts/insights/base.rabl +2 -3
  20. data/lib/foreman_inventory_upload/async/generate_report_job.rb +8 -13
  21. data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +26 -4
  22. data/lib/foreman_inventory_upload/async/upload_report_job.rb +96 -0
  23. data/lib/foreman_inventory_upload/generators/fact_helpers.rb +2 -2
  24. data/lib/foreman_inventory_upload/generators/slice.rb +3 -3
  25. data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +49 -0
  26. data/lib/foreman_inventory_upload.rb +6 -6
  27. data/lib/foreman_rh_cloud/engine.rb +15 -34
  28. data/lib/foreman_rh_cloud/plugin.rb +13 -20
  29. data/lib/foreman_rh_cloud/version.rb +1 -1
  30. data/lib/foreman_rh_cloud.rb +3 -3
  31. data/lib/insights_cloud/async/connector_playbook_execution_reporter_task.rb +3 -3
  32. data/lib/inventory_sync/async/inventory_hosts_sync.rb +2 -0
  33. data/lib/tasks/rh_cloud_inventory.rake +31 -14
  34. data/locale/foreman_rh_cloud.pot +157 -261
  35. data/locale/fr/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  36. data/locale/fr/foreman_rh_cloud.po +26 -79
  37. data/locale/ja/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  38. data/locale/ja/foreman_rh_cloud.po +26 -79
  39. data/locale/ka/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  40. data/locale/ka/foreman_rh_cloud.po +24 -77
  41. data/locale/ko/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  42. data/locale/ko/foreman_rh_cloud.po +25 -78
  43. data/locale/zh_CN/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  44. data/locale/zh_CN/foreman_rh_cloud.po +25 -78
  45. data/package.json +1 -1
  46. data/test/controllers/accounts_controller_test.rb +1 -1
  47. data/test/controllers/insights_cloud/api/advisor_engine_controller_test.rb +1 -28
  48. data/test/controllers/insights_cloud/ui_requests_controller_test.rb +0 -26
  49. data/test/controllers/uploads_controller_test.rb +1 -1
  50. data/test/factories/insights_factories.rb +0 -29
  51. data/test/jobs/cloud_connector_announce_task_test.rb +2 -3
  52. data/test/jobs/connector_playbook_execution_reporter_task_test.rb +20 -32
  53. data/test/jobs/exponential_backoff_test.rb +8 -9
  54. data/test/jobs/insights_client_status_aging_test.rb +2 -3
  55. data/test/jobs/insights_full_sync_test.rb +7 -13
  56. data/test/jobs/insights_resolutions_sync_test.rb +5 -9
  57. data/test/jobs/insights_rules_sync_test.rb +3 -5
  58. data/test/jobs/inventory_full_sync_test.rb +5 -9
  59. data/test/jobs/inventory_hosts_sync_test.rb +6 -11
  60. data/test/jobs/inventory_scheduled_sync_test.rb +6 -10
  61. data/test/jobs/inventory_self_host_sync_test.rb +1 -1
  62. data/test/jobs/remove_insights_hosts_job_test.rb +15 -14
  63. data/test/jobs/upload_report_job_test.rb +36 -0
  64. data/test/unit/fact_helpers_test.rb +0 -47
  65. data/test/unit/services/foreman_rh_cloud/tags_auth_test.rb +0 -14
  66. data/test/unit/slice_generator_test.rb +0 -57
  67. data/webpack/ForemanColumnExtensions/index.js +0 -2
  68. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.js +17 -24
  69. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageHeader.test.js +8 -178
  70. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageHeader.test.js.snap +36 -0
  71. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +1 -1
  72. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/ToolbarButtons.js +1 -3
  73. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/__tests__/ToolbarButtons.test.js +51 -69
  74. data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +1 -1
  75. data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryHelpers.test.js.snap +1 -1
  76. data/webpack/ForemanRhCloudFills.js +2 -6
  77. data/webpack/ForemanRhCloudHelpers.js +0 -4
  78. data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +3 -3
  79. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +9 -3
  80. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +4 -24
  81. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +112 -0
  82. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +2 -2
  83. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +3 -3
  84. data/webpack/InsightsCloudSync/InsightsCloudSync.js +3 -3
  85. data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +0 -10
  86. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +1 -1
  87. data/webpack/InsightsHostDetailsTab/InsightsTab.scss +0 -4
  88. data/webpack/InsightsHostDetailsTab/InsightsTotalRiskChart.js +23 -59
  89. data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +19 -6
  90. data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +2 -8
  91. data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +4 -105
  92. data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +3 -0
  93. data/webpack/__tests__/ForemanRhCloudHelpers.test.js +1 -16
  94. data/webpack/__tests__/__snapshots__/ForemanRhCloudHelpers.test.js.snap +0 -6
  95. data/webpack/common/Hooks/ConfigHooks.js +16 -3
  96. metadata +12 -31
  97. data/app/controllers/concerns/foreman_rh_cloud/registration_manager_extensions.rb +0 -39
  98. data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +0 -30
  99. data/lib/foreman_inventory_upload/async/generate_host_report.rb +0 -20
  100. data/lib/foreman_inventory_upload/async/host_inventory_report_job.rb +0 -39
  101. data/lib/foreman_inventory_upload/async/single_host_report_job.rb +0 -20
  102. data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +0 -200
  103. data/test/jobs/create_missing_insights_facets_test.rb +0 -151
  104. data/test/jobs/generate_host_report_test.rb +0 -100
  105. data/test/jobs/generate_report_job_test.rb +0 -146
  106. data/test/jobs/host_inventory_report_job_test.rb +0 -244
  107. data/test/jobs/queue_for_upload_job_test.rb +0 -54
  108. data/test/jobs/single_host_report_job_test.rb +0 -155
  109. data/test/jobs/upload_report_direct_job_test.rb +0 -399
  110. data/test/unit/foreman_rh_cloud_iop_metadata_test.rb +0 -200
  111. data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +0 -154
  112. data/test/unit/rh_cloud_host_test.rb +0 -191
  113. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTotalRiskChart.test.js +0 -194
@@ -1,39 +0,0 @@
1
- module ForemanRhCloud
2
- module RegistrationManagerExtensions
3
- include ForemanRhCloud::CertAuth
4
-
5
- def logger
6
- Rails.logger
7
- end
8
-
9
- def unregister_host(host, options = {})
10
- organization_destroy = options.fetch(:organization_destroy, false)
11
-
12
- # Reload to ensure we have fresh association data
13
- host.reload
14
-
15
- # Only delete from HBI in IoP mode (hosted mode uses async job for cleanup)
16
- hbi_host_destroy(host) if ForemanRhCloud.with_iop_smart_proxy? && !organization_destroy && host.insights_uuid.presence
17
- host.insights&.destroy!
18
- super(host, options)
19
- end
20
-
21
- def hbi_host_destroy(host)
22
- uuid = host.insights_uuid
23
- logger.debug "Unregistering host #{uuid} from HBI"
24
- execute_cloud_request(
25
- organization: host.organization,
26
- method: :delete,
27
- url: ForemanInventoryUpload.host_by_id_url(uuid),
28
- headers: {
29
- content_type: :json,
30
- }
31
- )
32
- rescue RestClient::NotFound
33
- Rails.logger.warn(_("Attempted to destroy HBI host %s, but host does not exist in HBI") % uuid)
34
- rescue StandardError => e
35
- # TODO: Improve error handling - don't break registration if HBI delete fails
36
- Rails.logger.error(format(_("Failed to destroy HBI host %s: %s"), uuid, e.message))
37
- end
38
- end
39
- end
@@ -1,30 +0,0 @@
1
- module ForemanInventoryUpload
2
- module Async
3
- class CreateMissingInsightsFacets < ::Actions::EntryAction
4
- def plan(organization_id)
5
- plan_self(organization_id: organization_id)
6
- end
7
-
8
- def run
9
- organization = ::Organization.find(input[:organization_id])
10
- hosts_without_facets = ::ForemanInventoryUpload::Generators::Queries.for_org(organization, hosts_query: 'null? insights_uuid')
11
- facet_count = 0
12
- hosts_without_facets.each do |batch|
13
- facets = batch.pluck(:id, 'katello_subscription_facets.uuid').map do |host_id, uuid|
14
- {
15
- host_id: host_id,
16
- uuid: uuid,
17
- }
18
- end
19
- # We don't need to validate the facets here as we create the necessary fields.
20
- # rubocop:disable Rails/SkipsModelValidations
21
- InsightsFacet.upsert_all(facets, unique_by: :host_id) unless facets.empty?
22
- # rubocop:enable Rails/SkipsModelValidations
23
- facet_count += facets.size
24
- end
25
- output[:result] = facet_count.zero? ? _("There were no missing Insights facets") : format(_("Missing Insights facets created: %s"), facet_count)
26
- Rails.logger.debug output[:result]
27
- end
28
- end
29
- end
30
- end
@@ -1,20 +0,0 @@
1
- module ForemanInventoryUpload
2
- module Async
3
- class GenerateHostReport < ::Actions::EntryAction
4
- def plan(base_folder, organization_id, filter)
5
- plan_self(
6
- base_folder: base_folder,
7
- organization_id: organization_id,
8
- filter: filter
9
- )
10
- input[:target] = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(input[:organization_id], input[:filter]))
11
- end
12
-
13
- def run
14
- archived_report_generator = ForemanInventoryUpload::Generators::ArchivedReport.new(input[:target])
15
- archived_report_generator.render(organization: input[:organization_id], filter: input[:filter])
16
- output[:result] = "Generated #{input[:target]} for organization id #{input[:organization_id]}"
17
- end
18
- end
19
- end
20
- end
@@ -1,39 +0,0 @@
1
- module ForemanInventoryUpload
2
- module Async
3
- class HostInventoryReportJob < ::Actions::EntryAction
4
- def plan(base_folder, organization_id, hosts_filter = "", upload = true)
5
- sequence do
6
- plan_action(
7
- GenerateHostReport,
8
- base_folder,
9
- organization_id,
10
- hosts_filter
11
- )
12
- if upload
13
- plan_action(
14
- QueueForUploadJob,
15
- base_folder,
16
- ForemanInventoryUpload.facts_archive_name(organization_id, hosts_filter),
17
- organization_id
18
- )
19
- end
20
-
21
- if ForemanRhCloud.with_iop_smart_proxy?
22
- plan_action(
23
- CreateMissingInsightsFacets,
24
- organization_id
25
- )
26
- end
27
- end
28
- end
29
-
30
- def humanized_name
31
- _("Host inventory report job")
32
- end
33
-
34
- def organization_id
35
- input[:organization_id]
36
- end
37
- end
38
- end
39
- end
@@ -1,20 +0,0 @@
1
- module ForemanInventoryUpload
2
- module Async
3
- class SingleHostReportJob < HostInventoryReportJob
4
- def plan(base_folder, organization_id, host_id)
5
- input[:host_id] = host_id
6
- super(base_folder, organization_id, "id=#{input[:host_id]}")
7
- end
8
-
9
- def hostname(host_id)
10
- host = ::Host.find_by(id: host_id)
11
- host&.name
12
- end
13
-
14
- def humanized_name
15
- hostname_result = hostname(input[:host_id])
16
- hostname_result.present? ? format(_("Single-host report job for host %s"), hostname_result) : _("Single-host report job")
17
- end
18
- end
19
- end
20
- end
@@ -1,200 +0,0 @@
1
- require 'tempfile'
2
- require 'rest-client'
3
-
4
- module ForemanInventoryUpload
5
- module Async
6
- class UploadReportDirectJob < ::Actions::EntryAction
7
- include AsyncHelpers
8
- include ::ForemanRhCloud::Async::ExponentialBackoff
9
- include ::ForemanRhCloud::CloudRequest
10
-
11
- # Wrapper class to avoid monkey-patching File for multipart uploads
12
- class FileUpload
13
- attr_reader :file, :content_type
14
-
15
- def initialize(file, content_type:)
16
- @file = file
17
- @content_type = content_type
18
- end
19
-
20
- def read(*args)
21
- @file.read(*args)
22
- end
23
-
24
- def path
25
- @file.path
26
- end
27
-
28
- def respond_to_missing?(method_name, include_private = false)
29
- @file.respond_to?(method_name, include_private) || super
30
- end
31
-
32
- def method_missing(method_name, *args, &block)
33
- if @file.respond_to?(method_name)
34
- @file.send(method_name, *args, &block)
35
- else
36
- super
37
- end
38
- end
39
- end
40
-
41
- def self.output_label(label)
42
- "upload_for_#{label}"
43
- end
44
-
45
- def plan(filename, organization_id)
46
- # NOTE: This implementation assumes a single organization will not trigger multiple
47
- # concurrent uploads. The instance_label is derived from organization_id alone, which
48
- # means concurrent uploads for the same org would share ProgressOutput storage.
49
- # This matches the pattern in GenerateReportJob. A full fix for thread-safety
50
- # requires UI changes to display multiple concurrent tasks per org (tracked for PR #2).
51
- label = UploadReportDirectJob.output_label(organization_id)
52
- clear_task_output(label)
53
- plan_self(
54
- instance_label: label,
55
- filename: filename,
56
- organization_id: organization_id
57
- )
58
- end
59
-
60
- def try_execute
61
- if content_disconnected?
62
- progress_output do |progress_output|
63
- progress_output.write_line("Report was not moved and upload was canceled because connection to Insights is not enabled. Report location: #{filename}.")
64
- progress_output.status = "Task aborted, exit 1"
65
- done!
66
- end
67
- return
68
- end
69
-
70
- unless organization.owner_details&.dig('upstreamConsumer', 'idCert')
71
- logger.info("Skipping organization '#{organization}', no candlepin certificate defined.")
72
- progress_output do |progress_output|
73
- progress_output.write_line("Skipping organization #{organization}, no candlepin certificate defined.")
74
- progress_output.status = "Task aborted, exit 1"
75
- done!
76
- end
77
- return
78
- end
79
-
80
- Tempfile.create([organization.name, '.pem']) do |cer_file|
81
- cer_file.write(certificate[:cert])
82
- cer_file.write(certificate[:key])
83
- cer_file.flush
84
- upload_report(cer_file.path)
85
- end
86
-
87
- done!
88
- end
89
-
90
- def upload_report(cer_path)
91
- progress_output do |progress_output|
92
- progress_output.write_line("Uploading report for organization #{organization.label}...")
93
- progress_output.status = "Running upload"
94
-
95
- begin
96
- upload_file(cer_path)
97
- progress_output.write_line("Upload completed successfully")
98
- move_to_done_folder
99
- progress_output.write_line("Uploaded file moved to done/ folder")
100
- progress_output.status = "pid #{Process.pid} exit 0"
101
- rescue StandardError => e
102
- progress_output.write_line("Upload failed: #{e.message}")
103
- progress_output.status = "pid #{Process.pid} exit 1"
104
- raise
105
- end
106
- end
107
- end
108
-
109
- def upload_file(cer_path)
110
- cert_content = File.read(cer_path)
111
-
112
- File.open(filename, 'rb') do |file|
113
- # Wrap file with FileUpload class for RestClient multipart handling
114
- # RestClient requires objects with :read, :path, and :content_type methods
115
- wrapped_file = FileUpload.new(file, content_type: 'application/vnd.redhat.qpc.tar+tgz')
116
-
117
- response = execute_cloud_request(
118
- method: :post,
119
- url: ForemanInventoryUpload.upload_url,
120
- payload: {
121
- multipart: true,
122
- file: wrapped_file,
123
- },
124
- headers: {
125
- 'X-Org-Id' => organization.label,
126
- },
127
- ssl_client_cert: OpenSSL::X509::Certificate.new(cert_content),
128
- ssl_client_key: OpenSSL::PKey::RSA.new(cert_content),
129
- timeout: 600,
130
- open_timeout: 60
131
- )
132
-
133
- logger.debug("Upload response code: #{response.code}")
134
- end
135
- end
136
-
137
- def move_to_done_folder
138
- FileUtils.mkdir_p(ForemanInventoryUpload.done_folder)
139
- done_file = ForemanInventoryUpload.done_file_path(File.basename(filename))
140
- FileUtils.mv(filename, done_file)
141
- logger.debug("Moved #{filename} to #{done_file}")
142
- end
143
-
144
- def certificate
145
- ForemanRhCloud.with_iop_smart_proxy? ? foreman_certificate : manifest_certificate
146
- end
147
-
148
- def manifest_certificate
149
- candlepin_id_certificate = organization.owner_details['upstreamConsumer']['idCert']
150
- {
151
- cert: candlepin_id_certificate['cert'],
152
- key: candlepin_id_certificate['key'],
153
- }
154
- end
155
-
156
- def foreman_certificate
157
- {
158
- cert: File.read(Setting[:ssl_certificate]),
159
- key: File.read(Setting[:ssl_priv_key]),
160
- }
161
- end
162
-
163
- def filename
164
- input[:filename]
165
- end
166
-
167
- def organization
168
- Organization.find(input[:organization_id])
169
- end
170
-
171
- def content_disconnected?
172
- !Setting[:subscription_connection_enabled]
173
- end
174
-
175
- def progress_output
176
- progress_output = ProgressOutput.register(instance_label)
177
- yield(progress_output)
178
- ensure
179
- progress_output.close
180
- end
181
-
182
- def instance_label
183
- input[:instance_label]
184
- end
185
-
186
- def logger
187
- Foreman::Logging.logger('background')
188
- end
189
-
190
- def rescue_strategy_for_self
191
- Dynflow::Action::Rescue::Fail
192
- end
193
-
194
- def clear_task_output(label)
195
- TaskOutputLine.where(label: label).delete_all
196
- TaskOutputStatus.where(label: label).delete_all
197
- end
198
- end
199
- end
200
- end
@@ -1,151 +0,0 @@
1
- require 'test_plugin_helper'
2
- require 'foreman_tasks/test_helpers'
3
-
4
- class CreateMissingInsightsFacetsTest < ActiveSupport::TestCase
5
- include Dynflow::Testing::Factories
6
- include KatelloCVEHelper
7
-
8
- setup do
9
- User.current = User.find_by(login: 'secret_admin')
10
- @cve = make_cve
11
- @env = @cve.lifecycle_environment
12
- @organization = @env.organization
13
-
14
- # Create a host with subscription facet but no insights facet
15
- @host_without_facet = FactoryBot.create(
16
- :host,
17
- :with_subscription,
18
- :with_content,
19
- content_view: @cve.content_view,
20
- lifecycle_environment: @env,
21
- organization: @organization
22
- )
23
-
24
- # Create a host with both subscription and insights facets
25
- @host_with_facet = FactoryBot.create(
26
- :host,
27
- :with_subscription,
28
- :with_content,
29
- content_view: @cve.content_view,
30
- lifecycle_environment: @env,
31
- organization: @organization
32
- )
33
- @host_with_facet.build_insights(uuid: @host_with_facet.subscription_facet.uuid)
34
- @host_with_facet.insights.save!
35
- end
36
-
37
- test 'creates insights facets for hosts without them' do
38
- assert_nil @host_without_facet.insights
39
-
40
- action = create_and_plan_action(
41
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
42
- @organization.id
43
- )
44
- action = run_action(action)
45
-
46
- @host_without_facet.reload
47
- assert_not_nil @host_without_facet.insights
48
- assert_equal @host_without_facet.subscription_facet.uuid, @host_without_facet.insights.uuid
49
- assert_match(/Missing Insights facets created: 1/, action.output[:result])
50
- end
51
-
52
- test 'does not create duplicate facets for hosts that already have them' do
53
- original_uuid = @host_with_facet.insights.uuid
54
- original_id = @host_with_facet.insights.id
55
-
56
- action = create_and_plan_action(
57
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
58
- @organization.id
59
- )
60
- run_action(action)
61
-
62
- @host_with_facet.reload
63
- assert_equal original_id, @host_with_facet.insights.id
64
- assert_equal original_uuid, @host_with_facet.insights.uuid
65
- end
66
-
67
- test 'handles organization with no missing facets' do
68
- # Create insights facet for the host that was missing one
69
- @host_without_facet.build_insights(uuid: @host_without_facet.subscription_facet.uuid)
70
- @host_without_facet.insights.save!
71
-
72
- action = create_and_plan_action(
73
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
74
- @organization.id
75
- )
76
- action = run_action(action)
77
-
78
- assert_match(/There were no missing Insights facets/, action.output[:result])
79
- end
80
-
81
- test 'creates multiple facets when multiple hosts are missing them' do
82
- # Remove the insights facet from the host that has one
83
- @host_with_facet.insights.destroy
84
- @host_with_facet.reload
85
-
86
- assert_nil @host_without_facet.insights
87
- assert_nil @host_with_facet.insights
88
-
89
- action = create_and_plan_action(
90
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
91
- @organization.id
92
- )
93
- action = run_action(action)
94
-
95
- @host_without_facet.reload
96
- @host_with_facet.reload
97
- assert_not_nil @host_without_facet.insights
98
- assert_not_nil @host_with_facet.insights
99
- # After the bug fix, the count should correctly show 2 hosts
100
- assert_match(/Missing Insights facets created: 2/, action.output[:result])
101
- end
102
-
103
- test 'logs result message' do
104
- Rails.logger.expects(:debug).with(regexp_matches(/Missing Insights facets created/))
105
-
106
- action = create_and_plan_action(
107
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
108
- @organization.id
109
- )
110
- run_action(action)
111
- end
112
-
113
- test 'correctly counts facets across multiple batches' do
114
- # Remove existing insights facet
115
- @host_with_facet.insights.destroy
116
- @host_with_facet.reload
117
-
118
- # Stub the batch size to force multiple batches with just 2 hosts
119
- ForemanInventoryUpload.stubs(:slice_size).returns(1)
120
-
121
- assert_nil @host_without_facet.insights
122
- assert_nil @host_with_facet.insights
123
-
124
- action = create_and_plan_action(
125
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
126
- @organization.id
127
- )
128
- action = run_action(action)
129
-
130
- @host_without_facet.reload
131
- @host_with_facet.reload
132
- assert_not_nil @host_without_facet.insights
133
- assert_not_nil @host_with_facet.insights
134
- # Count should be 2 even though processed in 2 separate batches
135
- assert_match(/Missing Insights facets created: 2/, action.output[:result])
136
- end
137
-
138
- test 'handles error when InsightsFacet.upsert_all fails' do
139
- # Stub upsert_all to raise an exception
140
- InsightsFacet.stubs(:upsert_all).raises(StandardError.new('upsert failed'))
141
-
142
- action = create_and_plan_action(
143
- ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
144
- @organization.id
145
- )
146
-
147
- assert_raises(StandardError) do
148
- run_action(action)
149
- end
150
- end
151
- end
@@ -1,100 +0,0 @@
1
- require 'test_plugin_helper'
2
- require 'foreman_tasks/test_helpers'
3
-
4
- class GenerateHostReportTest < ActiveSupport::TestCase
5
- include Dynflow::Testing::Factories
6
- include FolderIsolation
7
-
8
- let(:organization) { FactoryBot.create(:organization) }
9
- let(:base_folder) { @tmpdir }
10
- let(:filter) { '' }
11
-
12
- setup do
13
- # Stub the ArchivedReport generator
14
- @mock_generator = mock('archived_report_generator')
15
- @mock_generator.stubs(:render)
16
- ForemanInventoryUpload::Generators::ArchivedReport.stubs(:new).returns(@mock_generator)
17
- end
18
-
19
- test 'plan sets target path correctly' do
20
- expected_archive_name = ForemanInventoryUpload.facts_archive_name(organization.id, filter)
21
- expected_target = File.join(base_folder, expected_archive_name)
22
-
23
- action = create_and_plan_action(
24
- ForemanInventoryUpload::Async::GenerateHostReport,
25
- base_folder,
26
- organization.id,
27
- filter
28
- )
29
-
30
- assert_equal expected_target, action.input[:target]
31
- end
32
-
33
- test 'run generates report archive' do
34
- expected_target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization.id, filter))
35
-
36
- ForemanInventoryUpload::Generators::ArchivedReport.expects(:new).with(expected_target).returns(@mock_generator)
37
- @mock_generator.expects(:render).with(organization: organization.id, filter: filter)
38
-
39
- action = create_and_plan_action(
40
- ForemanInventoryUpload::Async::GenerateHostReport,
41
- base_folder,
42
- organization.id,
43
- filter
44
- )
45
- action = run_action(action)
46
-
47
- assert_match(/Generated #{Regexp.escape(expected_target)} for organization id #{organization.id}/, action.output[:result])
48
- end
49
-
50
- test 'generates report with filter' do
51
- filter_value = 'id=123'
52
- expected_target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization.id, filter_value))
53
-
54
- ForemanInventoryUpload::Generators::ArchivedReport.expects(:new).with(expected_target).returns(@mock_generator)
55
- @mock_generator.expects(:render).with(organization: organization.id, filter: filter_value)
56
-
57
- action = create_and_plan_action(
58
- ForemanInventoryUpload::Async::GenerateHostReport,
59
- base_folder,
60
- organization.id,
61
- filter_value
62
- )
63
- action = run_action(action)
64
-
65
- assert_match(/organization id #{organization.id}/, action.output[:result])
66
- end
67
-
68
- test 'stores organization_id and filter in input' do
69
- filter_value = 'name~test'
70
-
71
- action = create_and_plan_action(
72
- ForemanInventoryUpload::Async::GenerateHostReport,
73
- base_folder,
74
- organization.id,
75
- filter_value
76
- )
77
-
78
- assert_equal organization.id, action.input[:organization_id]
79
- assert_equal filter_value, action.input[:filter]
80
- assert_equal base_folder, action.input[:base_folder]
81
- end
82
-
83
- test 'handles ArchivedReport generator failure' do
84
- expected_target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization.id, filter))
85
-
86
- ForemanInventoryUpload::Generators::ArchivedReport.expects(:new).with(expected_target).returns(@mock_generator)
87
- @mock_generator.expects(:render).with(organization: organization.id, filter: filter).raises(StandardError.new('Report generation failed'))
88
-
89
- action = create_and_plan_action(
90
- ForemanInventoryUpload::Async::GenerateHostReport,
91
- base_folder,
92
- organization.id,
93
- filter
94
- )
95
-
96
- assert_raises(StandardError) do
97
- run_action(action)
98
- end
99
- end
100
- end