foreman_rh_cloud 14.1.2 → 14.1.3

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/lib/foreman_inventory_upload/generators/fact_helpers.rb +26 -4
  3. data/lib/foreman_inventory_upload.rb +8 -1
  4. data/lib/foreman_rh_cloud/version.rb +1 -1
  5. data/lib/foreman_rh_cloud.rb +36 -9
  6. data/lib/insights_cloud/async/insights_generate_notifications.rb +10 -1
  7. data/lib/inventory_sync/async/inventory_self_host_sync.rb +12 -2
  8. data/package.json +1 -1
  9. data/test/jobs/insights_generate_notifications_test.rb +26 -0
  10. data/test/jobs/inventory_self_host_sync_test.rb +9 -0
  11. data/test/unit/foreman_rh_cloud_self_host_test.rb +50 -2
  12. data/test/unit/metadata_generator_test.rb +24 -1
  13. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/__tests__/EmptyResults.test.js +10 -9
  14. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/EmptyState.test.js +13 -9
  15. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ErrorState/__tests__/ErrorState.test.js +20 -9
  16. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/ListItem.test.js +31 -8
  17. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/__tests__/ListItemStatus.test.js +26 -10
  18. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountList.test.js +33 -9
  19. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListReducer.test.js +55 -35
  20. data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/FileDownload.test.js +13 -9
  21. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilter.test.js +12 -15
  22. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/integration.test.js +32 -12
  23. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageTitle.test.js +14 -7
  24. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/CloudConnectorButton.test.js +47 -18
  25. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/SettingsWarning.test.js +58 -15
  26. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButton.test.js +23 -9
  27. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonSelectors.test.js +19 -17
  28. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/integrations.test.js +25 -37
  29. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/ScheduledRun.test.js +28 -8
  30. data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/StatusChart.test.js +25 -8
  31. data/webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/TabContainer.test.js +11 -9
  32. data/webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/TabFooter.test.js +11 -9
  33. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/InventoryAutoUpload.test.js +33 -12
  34. data/webpack/ForemanInventoryUpload/__tests__/ForemanInventoryHelpers.test.js +21 -8
  35. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/InsightsSettingsActions.test.js +61 -47
  36. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +48 -4
  37. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTableActions.test.js +126 -35
  38. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTableSelectors.test.js +90 -24
  39. data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +79 -21
  40. data/webpack/InsightsCloudSync/__tests__/InsightsCloudSyncActions.test.js +31 -6
  41. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js +42 -9
  42. data/webpack/__tests__/ForemanRhCloudHelpers.test.js +91 -53
  43. data/webpack/common/Switcher/__tests__/HelpLabel.test.js +25 -10
  44. data/webpack/common/Switcher/__tests__/SwitcherPF4.test.js +41 -10
  45. metadata +3 -67
  46. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/__tests__/__snapshots__/EmptyResults.test.js.snap +0 -18
  47. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/__snapshots__/EmptyState.test.js.snap +0 -25
  48. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ErrorState/__tests__/__snapshots__/ErrorState.test.js.snap +0 -20
  49. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +0 -47
  50. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/__tests__/__snapshots__/ListItemStatus.test.js.snap +0 -59
  51. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListActions.test.js +0 -34
  52. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListIntegration.test.js +0 -14
  53. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListSelectors.test.js +0 -25
  54. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountList.test.js.snap +0 -49
  55. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListActions.test.js.snap +0 -86
  56. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListReducer.test.js.snap +0 -75
  57. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListSelectors.test.js.snap +0 -46
  58. data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/__snapshots__/FileDownload.test.js.snap +0 -26
  59. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterActions.test.js +0 -14
  60. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterReducer.test.js +0 -28
  61. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterSelectors.test.js +0 -21
  62. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilter.test.js.snap +0 -21
  63. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterActions.test.js.snap +0 -17
  64. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterReducer.test.js.snap +0 -19
  65. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterSelectors.test.js.snap +0 -9
  66. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +0 -43
  67. data/webpack/ForemanInventoryUpload/Components/InventorySettings/AdvancedSetting/__tests__/AdvancedSettingActions.test.js +0 -9
  68. data/webpack/ForemanInventoryUpload/Components/InventorySettings/AdvancedSetting/__tests__/__snapshots__/AdvancedSettingActions.test.js.snap +0 -18
  69. data/webpack/ForemanInventoryUpload/Components/InventorySettings/__tests__/InventorySettingsActions.test.js +0 -14
  70. data/webpack/ForemanInventoryUpload/Components/InventorySettings/__tests__/__snapshots__/InventorySettingsActions.test.js.snap +0 -26
  71. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +0 -68
  72. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/CloudConnectorActions.test.js +0 -9
  73. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorActions.test.js.snap +0 -11
  74. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +0 -59
  75. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/__snapshots__/SettingsWarning.test.js.snap +0 -32
  76. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +0 -15
  77. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonSelectors.test.js.snap +0 -3
  78. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +0 -58
  79. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/__snapshots__/ScheduledRun.test.js.snap +0 -23
  80. data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/__snapshots__/StatusChart.test.js.snap +0 -74
  81. data/webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/__snapshots__/TabContainer.test.js.snap +0 -18
  82. data/webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/__snapshots__/TabFooter.test.js.snap +0 -12
  83. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/__snapshots__/InventoryAutoUpload.test.js.snap +0 -96
  84. data/webpack/ForemanInventoryUpload/__tests__/ForemanInventoryUpload.test.js +0 -10
  85. data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryHelpers.test.js.snap +0 -5
  86. data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryUpload.test.js.snap +0 -14
  87. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/InsightsSettingsReducer.test.js +0 -33
  88. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/InsightsSettingsSelectors.test.js +0 -21
  89. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettingsActions.test.js.snap +0 -65
  90. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettingsReducer.test.js.snap +0 -19
  91. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettingsSelectors.test.js.snap +0 -9
  92. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTableActions.test.js.snap +0 -131
  93. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTableSelectors.test.js.snap +0 -87
  94. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +0 -10
  95. data/webpack/InsightsCloudSync/__tests__/InsightsCloudSyncHelpers.test.js +0 -9
  96. data/webpack/InsightsCloudSync/__tests__/__snapshots__/InsightsCloudSyncActions.test.js.snap +0 -15
  97. data/webpack/InsightsCloudSync/__tests__/__snapshots__/InsightsCloudSyncHelpers.test.js.snap +0 -3
  98. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js +0 -19
  99. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js +0 -26
  100. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js +0 -13
  101. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap +0 -34
  102. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap +0 -56
  103. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap +0 -32
  104. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap +0 -18
  105. data/webpack/__tests__/ForemanRhCloudSelectors.test.js +0 -22
  106. data/webpack/__tests__/ForemanRhCloudTestHelpers.test.js +0 -20
  107. data/webpack/__tests__/__snapshots__/ForemanRhCloudHelpers.test.js.snap +0 -19
  108. data/webpack/__tests__/__snapshots__/ForemanRhCloudSelectors.test.js.snap +0 -25
  109. data/webpack/__tests__/__snapshots__/ForemanRhCloudTestHelpers.test.js.snap +0 -39
  110. data/webpack/common/Switcher/__tests__/__snapshots__/HelpLabel.test.js.snap +0 -16
  111. data/webpack/common/Switcher/__tests__/__snapshots__/SwitcherPF4.test.js.snap +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8561ef219578d2be3678f2576fba36e1cb3f2a91aab82b5438369aa08ddd0a05
4
- data.tar.gz: 6abcf201d049e27b6dc90fef6f5094a0f6f72d337f49aa6cdf328d8aa92e3516
3
+ metadata.gz: 89c6b782cc34fb3ffc4f13ad66c435c5729028df995e7bdba1c15e668a72fe89
4
+ data.tar.gz: 356fb55567950b341b4509f6ee39e30b24127c695b3924765070167800595f44
5
5
  SHA512:
6
- metadata.gz: cf0448da7b88a0ddca0e2726805b9c0fb6e5356651e64ac09d0a18cd16d05a393dab07f4a19c445948a39fd1a4111e17c275c8ffaf33df974cc80a9af1693ba0
7
- data.tar.gz: 7e780f06f64dc1f5042a10ec48f3c397d5b767bc5b6ac2c08ac7d9cc059518df4415ee442b37216777a471a0286d59a73a56142a6b80cb10b04213d477a9c4d7
6
+ metadata.gz: 8bdb9ff78ed0950bd67f5bcc1483a0f2568af9a3462633ef6fc25d061bf942712d416d717f43e3dcef448dddb11cc6f7b9ad1fe62d6530ad2dbf44af3a3eb4a6
7
+ data.tar.gz: f55334cb175a624ae8aeb21242b609ce8af3c49061c7e09b460b46fef3d3239cab42232c0c52eb043ed345a661b331409545344f24e89e46e3fb9a782666e1bc
@@ -106,6 +106,7 @@ module ForemanInventoryUpload
106
106
 
107
107
  def host_ips(host)
108
108
  # Determines and returns the IP addresses associated with a host, applying obfuscation if enabled.
109
+ return {} if host.nil?
109
110
 
110
111
  # If IP obfuscation is enabled for the host return a representation of obfuscated IP addresses.
111
112
  return obfuscated_ips(host) if obfuscate_ips?(host)
@@ -155,10 +156,29 @@ module ForemanInventoryUpload
155
156
 
156
157
  def hostname_match
157
158
  bash_hostname = `uname -n`.chomp
158
- foreman_hostname = ForemanRhCloud.foreman_host&.name
159
- if bash_hostname == foreman_hostname
160
- fqdn(ForemanRhCloud.foreman_host)
161
- elsif Setting[:obfuscate_inventory_hostnames]
159
+ foreman_host = ForemanRhCloud.foreman_host
160
+
161
+ # If bash hostname matches foreman_host, use fqdn
162
+ if foreman_host && bash_hostname == foreman_host.name
163
+ return fqdn(foreman_host)
164
+ end
165
+
166
+ # If no foreman_host, try foreman_host_name from Setting[:foreman_url]
167
+ unless foreman_host
168
+ foreman_hostname_from_setting = ForemanRhCloud.foreman_host_name
169
+ if foreman_hostname_from_setting
170
+ # Apply obfuscation if enabled
171
+ return obfuscate_fqdn(foreman_hostname_from_setting) if Setting[:obfuscate_inventory_hostnames]
172
+
173
+ return foreman_hostname_from_setting
174
+ end
175
+ # Otherwise fall through to bash_hostname below
176
+ # NOTE: Containerized foremanctl setups must configure Setting[:foreman_url]
177
+ # as bash hostname may not be available or meaningful in containers
178
+ end
179
+
180
+ # Fallback to bash hostname (with obfuscation if enabled)
181
+ if Setting[:obfuscate_inventory_hostnames]
162
182
  obfuscate_fqdn(bash_hostname)
163
183
  else
164
184
  bash_hostname
@@ -166,6 +186,8 @@ module ForemanInventoryUpload
166
186
  end
167
187
 
168
188
  def bios_uuid(host)
189
+ return nil if host.nil?
190
+
169
191
  value = fact_value(host, 'dmi::system::uuid') || ''
170
192
  uuid_value(value)
171
193
  end
@@ -96,7 +96,14 @@ module ForemanInventoryUpload
96
96
  end
97
97
 
98
98
  def self.inventory_self_url
99
- inventory_base_url + "?hostname_or_id=#{ForemanRhCloud.foreman_host.fqdn}"
99
+ host = ForemanRhCloud.foreman_host
100
+ hostname = host ? host.fqdn : ForemanRhCloud.foreman_host_name
101
+ if hostname.nil?
102
+ Rails.logger.warn("Cannot determine Foreman hostname for inventory sync. " \
103
+ "Please configure Setting[:foreman_url]. " \
104
+ "Containerized setups must explicitly set this.")
105
+ end
106
+ inventory_base_url + "?hostname_or_id=#{hostname}"
100
107
  end
101
108
 
102
109
  def self.host_by_id_url(host_uuid)
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '14.1.2'.freeze
2
+ VERSION = '14.1.3'.freeze
3
3
  end
@@ -84,23 +84,50 @@ module ForemanRhCloud
84
84
 
85
85
  # For testing purposes we can override the default hostname with an environment variable SATELLITE_RH_CLOUD_FOREMAN_HOST
86
86
  def self.foreman_host
87
- @foreman_host ||= begin
88
- fullname = foreman_host_name
89
- ::Host.unscoped.friendly.find(fullname)
90
- rescue ActiveRecord::RecordNotFound
91
- # fullname didn't work. Let's try shortname
87
+ return @foreman_host if defined?(@foreman_host)
88
+
89
+ fullname = foreman_host_name
90
+ return @foreman_host = nil unless fullname
91
+
92
+ # Try fullname first
93
+ host = ::Host.unscoped.friendly.where(name: fullname).first
94
+
95
+ # If not found, try shortname
96
+ if host.nil?
92
97
  shortname = /(?<shortname>[^\.]*)\.?.*/.match(fullname)[:shortname]
93
- ::Host.unscoped.friendly.find(shortname)
98
+ host = ::Host.unscoped.friendly.where(name: shortname).first
94
99
  end
100
+
101
+ @foreman_host = host
95
102
  end
96
103
 
97
104
  def self.foreman_host_name
98
- ENV['SATELLITE_RH_CLOUD_FOREMAN_HOST'] || marked_foreman_host&.name || ::SmartProxy.default_capsule.name
105
+ ENV['SATELLITE_RH_CLOUD_FOREMAN_HOST'] || marked_foreman_host&.name || foreman_url_hostname
106
+ end
107
+
108
+ def self.foreman_url_hostname
109
+ return nil unless Setting[:foreman_url]
110
+
111
+ begin
112
+ # Ensure setting is a string to avoid TypeError from URI.parse
113
+ url = Setting[:foreman_url].to_s
114
+ URI.parse(url).host
115
+ rescue URI::InvalidURIError, ArgumentError, TypeError => e
116
+ Rails.logger.warn("Invalid foreman_url setting: #{e.message}")
117
+ nil
118
+ end
99
119
  end
100
120
 
101
121
  def self.marked_foreman_host
102
- ::Host.unscoped.search_for('infrastructure_facet.foreman = true').first
103
- rescue ScopedSearch::QueryNotSupported
122
+ # Find host with infrastructure_facet.foreman_instance = true
123
+ # Facets use a special mechanism in Foreman, so we query the facet table directly
124
+ return nil unless defined?(HostFacets::InfrastructureFacet)
125
+
126
+ facet = HostFacets::InfrastructureFacet.find_by(foreman_instance: true)
127
+ facet&.host
128
+ rescue ActiveRecord::StatementInvalid => e
129
+ # Table might not exist yet during migrations
130
+ Rails.logger.debug("Could not query marked foreman host: #{e.message}")
104
131
  nil
105
132
  end
106
133
 
@@ -13,7 +13,16 @@ module InsightsCloud
13
13
  end
14
14
 
15
15
  def add_satellite_notifications
16
- hits_count = InsightsHit.where(host_id: foreman_host.id).count
16
+ host = foreman_host
17
+
18
+ # Skip if no Foreman host record exists
19
+ unless host
20
+ logger.debug("Skipping Insights notifications: no Foreman host record found")
21
+ blueprint&.notifications&.destroy_all
22
+ return
23
+ end
24
+
25
+ hits_count = InsightsHit.where(host_id: host.id).count
17
26
 
18
27
  # Remove stale notifications
19
28
  blueprint.notifications.destroy_all
@@ -4,7 +4,14 @@ module InventorySync
4
4
  set_callback :step, :around, :create_facets
5
5
 
6
6
  def plan
7
- super(ForemanRhCloud.foreman_host.organization)
7
+ host = ForemanRhCloud.foreman_host
8
+
9
+ if host.nil?
10
+ logger.warn("Skipping self-host inventory sync: no Foreman host record found.")
11
+ return
12
+ end
13
+
14
+ super(host.organization)
8
15
  end
9
16
 
10
17
  def create_facets
@@ -22,7 +29,10 @@ module InventorySync
22
29
  private
23
30
 
24
31
  def add_missing_insights_facet(uuids_hash)
25
- facet = InsightsFacet.find_or_create_by(host_id: ForemanRhCloud.foreman_host.id) do |facet|
32
+ host = ForemanRhCloud.foreman_host
33
+ return unless host # Guard against nil
34
+
35
+ facet = InsightsFacet.find_or_create_by(host_id: host.id) do |facet|
26
36
  facet.uuid = uuids_hash.values.first
27
37
  end
28
38
 
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "14.1.2",
3
+ "version": "14.1.3",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,26 @@
1
+ require 'test_plugin_helper'
2
+ require 'foreman_tasks/test_helpers'
3
+
4
+ class InsightsGenerateNotificationsTest < ActiveSupport::TestCase
5
+ include Dynflow::Testing::Factories
6
+
7
+ setup do
8
+ User.current = User.find_by(login: 'secret_admin')
9
+ end
10
+
11
+ test 'skips notifications when foreman_host is nil' do
12
+ ForemanRhCloud.stubs(:foreman_host).returns(nil)
13
+
14
+ # Ensure blueprint exists or create it
15
+ NotificationBlueprint.find_or_create_by(name: 'insights_satellite_hits') do |bp|
16
+ bp.message = 'Test message'
17
+ bp.level = 'info'
18
+ bp.expires_in = 7.days
19
+ end
20
+
21
+ plan = ForemanTasks.sync_task(InsightsCloud::Async::InsightsGenerateNotifications)
22
+
23
+ # Should not raise an error, task completes successfully
24
+ assert_includes ['success', 'stopped'], plan.state, "Task should complete without error"
25
+ end
26
+ end
@@ -106,4 +106,13 @@ class InventorySelfHostSyncTest < ActiveSupport::TestCase
106
106
 
107
107
  assert_equal @host1_inventory_id, @host1.insights.uuid
108
108
  end
109
+
110
+ test 'skips sync when foreman_host is nil' do
111
+ ForemanRhCloud.stubs(:foreman_host).returns(nil)
112
+
113
+ plan = ForemanTasks.sync_task(InventorySync::Async::InventorySelfHostSync)
114
+
115
+ # Task should be stopped (not executed) when host is nil, not failed
116
+ assert_equal 'stopped', plan.state
117
+ end
109
118
  end
@@ -2,8 +2,9 @@ require 'test_plugin_helper'
2
2
 
3
3
  class ForemanRhCloudSelfHostTest < ActiveSupport::TestCase
4
4
  setup do
5
- # reset cached value
6
- ForemanRhCloud.instance_variable_set(:@foreman_host, nil)
5
+ # reset cached value - must remove the variable entirely, not just set to nil
6
+ ForemanRhCloud.remove_instance_variable(:@foreman_host) if ForemanRhCloud.instance_variable_defined?(:@foreman_host)
7
+ ENV.delete('SATELLITE_RH_CLOUD_FOREMAN_HOST')
7
8
  end
8
9
 
9
10
  test 'finds host by fullname' do
@@ -32,4 +33,51 @@ class ForemanRhCloudSelfHostTest < ActiveSupport::TestCase
32
33
 
33
34
  assert_equal @host, actual
34
35
  end
36
+
37
+ test 'returns nil when host does not exist' do
38
+ ForemanRhCloud.expects(:foreman_host_name).returns('nonexistent.example.com')
39
+
40
+ actual = ForemanRhCloud.foreman_host
41
+
42
+ assert_nil actual
43
+ end
44
+
45
+ test 'returns nil and does not query Host when foreman_host_name is nil' do
46
+ ForemanRhCloud.stubs(:foreman_host_name).returns(nil)
47
+ ::Host.unscoped.friendly.expects(:where).never
48
+
49
+ assert_nil ForemanRhCloud.foreman_host
50
+ end
51
+
52
+ test 'caches nil value to avoid repeated lookups' do
53
+ ForemanRhCloud.expects(:foreman_host_name).once.returns('nonexistent.example.com')
54
+
55
+ 2.times { ForemanRhCloud.foreman_host }
56
+ end
57
+
58
+ test 'extracts hostname from foreman_url setting' do
59
+ Setting[:foreman_url] = 'https://satellite.example.com'
60
+
61
+ actual = ForemanRhCloud.foreman_url_hostname
62
+
63
+ assert_equal 'satellite.example.com', actual
64
+ end
65
+
66
+ test 'handles invalid foreman_url gracefully' do
67
+ # Stub Setting to return invalid URL without validation
68
+ Setting.stubs(:[]).with(:foreman_url).returns('not a valid url')
69
+
70
+ actual = ForemanRhCloud.foreman_url_hostname
71
+
72
+ assert_nil actual
73
+ end
74
+
75
+ test 'foreman_host_name uses foreman_url when marked_foreman_host is nil' do
76
+ ForemanRhCloud.expects(:marked_foreman_host).returns(nil)
77
+ ForemanRhCloud.expects(:foreman_url_hostname).returns('satellite.example.com')
78
+
79
+ actual = ForemanRhCloud.foreman_host_name
80
+
81
+ assert_equal 'satellite.example.com', actual
82
+ end
35
83
  end
@@ -2,7 +2,8 @@ require 'test_plugin_helper'
2
2
 
3
3
  class MetadataGeneratorTest < ActiveSupport::TestCase
4
4
  setup do
5
- ForemanRhCloud.instance_variable_set(:@foreman_host, nil)
5
+ # reset cached value - must remove the variable entirely, not just set to nil
6
+ ForemanRhCloud.remove_instance_variable(:@foreman_host) if ForemanRhCloud.instance_variable_defined?(:@foreman_host)
6
7
  end
7
8
 
8
9
  test 'generates an empty report' do
@@ -64,4 +65,26 @@ class MetadataGeneratorTest < ActiveSupport::TestCase
64
65
  assert_not_nil(slice = slices['test_12345'])
65
66
  assert_equal 3, slice['number_hosts']
66
67
  end
68
+
69
+ test 'generates metadata when foreman_host is nil' do
70
+ ForemanRhCloud.stubs(:foreman_host).returns(nil)
71
+ ForemanRhCloud.stubs(:foreman_host_name).returns('satellite.example.com')
72
+
73
+ generator = ForemanInventoryUpload::Generators::Metadata.new
74
+
75
+ # Should not raise an error
76
+ json_str = nil
77
+ assert_nothing_raised do
78
+ json_str = generator.render do
79
+ end
80
+ end
81
+
82
+ # Verify hostname is from foreman_host_name
83
+ actual = JSON.parse(json_str.join("\n"))
84
+ assert_equal 'satellite.example.com', actual['reporting_host_name']
85
+ # Verify IP and BIOS UUID fields are nil when host is nil
86
+ # This is acceptable per SAT-25889 - cloud services don't rely on these fields
87
+ assert_nil actual['reporting_host_ips']
88
+ assert_nil actual['reporting_host_bios_uuid']
89
+ end
67
90
  end
@@ -1,13 +1,14 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
3
  import EmptyResults from '../EmptyResults';
4
4
 
5
- const fixtures = {
6
- 'render without Props': {},
7
- /** fixtures, props for the component */
8
- };
9
-
10
5
  describe('EmptyResults', () => {
11
- describe('rendering', () =>
12
- testComponentSnapshotsWithFixtures(EmptyResults, fixtures));
6
+ it('renders the empty results message', () => {
7
+ render(<EmptyResults />);
8
+ expect(
9
+ screen.getByText(
10
+ "Oops! Couldn't find organization that matches your query"
11
+ )
12
+ ).toBeTruthy();
13
+ });
13
14
  });
@@ -1,13 +1,17 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
3
  import EmptyState from '../EmptyState';
4
4
 
5
- const fixtures = {
6
- 'render without Props': {},
7
- /** fixtures, props for the component */
8
- };
9
-
10
5
  describe('EmptyState', () => {
11
- describe('rendering', () =>
12
- testComponentSnapshotsWithFixtures(EmptyState, fixtures));
6
+ it('renders fetching data message', () => {
7
+ render(<EmptyState />);
8
+ expect(
9
+ screen.getByText('Fetching data about your accounts')
10
+ ).toBeTruthy();
11
+ });
12
+
13
+ it('renders loading indicator', () => {
14
+ render(<EmptyState />);
15
+ expect(screen.getByText('Loading...')).toBeTruthy();
16
+ });
13
17
  });
@@ -1,13 +1,24 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
3
  import ErrorState from '../ErrorState';
4
4
 
5
- const fixtures = {
6
- 'render without Props': {},
7
- /** fixtures, props for the component */
8
- };
9
-
10
5
  describe('ErrorState', () => {
11
- describe('rendering', () =>
12
- testComponentSnapshotsWithFixtures(ErrorState, fixtures));
6
+ it('renders the error message heading', () => {
7
+ render(<ErrorState error="Something went wrong" />);
8
+ expect(
9
+ screen.getByText(
10
+ 'Encountered an error while trying to access the server:'
11
+ )
12
+ ).toBeTruthy();
13
+ });
14
+
15
+ it('renders the error description', () => {
16
+ render(<ErrorState error="Connection refused" />);
17
+ expect(screen.getByText('Connection refused')).toBeTruthy();
18
+ });
19
+
20
+ it('renders with empty error by default', () => {
21
+ const { container } = render(<ErrorState />);
22
+ expect(container.querySelector('.error_description')).toBeTruthy();
23
+ });
13
24
  });
@@ -1,13 +1,36 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { Accordion } from '@patternfly/react-core';
3
4
  import ListItem from '../ListItem';
4
- import { props } from '../ListItem.fixtures';
5
5
 
6
- const fixtures = {
7
- 'render with Props': props,
8
- };
6
+ jest.mock('../../../../Dashboard', () => () => null);
7
+
8
+ const renderListItem = props =>
9
+ render(
10
+ <Accordion>
11
+ <ListItem {...props} />
12
+ </Accordion>
13
+ );
9
14
 
10
15
  describe('ListItem', () => {
11
- describe('rendering', () =>
12
- testComponentSnapshotsWithFixtures(ListItem, fixtures));
16
+ const defaultProps = {
17
+ label: 'test-org',
18
+ account: {
19
+ generated_status: 'unknown',
20
+ uploaded_status: 'unknown',
21
+ id: 1,
22
+ },
23
+ };
24
+
25
+ it('renders the account label', () => {
26
+ renderListItem(defaultProps);
27
+ expect(screen.getByText('test-org')).toBeTruthy();
28
+ });
29
+
30
+ it('renders Generated and Uploaded status labels', () => {
31
+ renderListItem(defaultProps);
32
+ expect(screen.getByText('Generated')).toBeTruthy();
33
+ expect(screen.getByText('Uploaded')).toBeTruthy();
34
+ });
35
+
13
36
  });
@@ -1,14 +1,30 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
3
  import ListItemStatus from '../ListItemStatus';
4
- import { props } from '../ListItemStatus.fixtures';
5
-
6
- const fixtures = {
7
- 'render without Props': {},
8
- 'render with Props': props,
9
- };
10
4
 
11
5
  describe('ListItemStatus', () => {
12
- describe('rendering', () =>
13
- testComponentSnapshotsWithFixtures(ListItemStatus, fixtures));
6
+ it('renders Generated and Uploaded labels', () => {
7
+ render(<ListItemStatus />);
8
+ expect(screen.getByText('Generated')).toBeTruthy();
9
+ expect(screen.getByText('Uploaded')).toBeTruthy();
10
+ });
11
+
12
+ it('shows dash placeholders for unknown status', () => {
13
+ render(
14
+ <ListItemStatus
15
+ account={{ generated_status: 'unknown', uploaded_status: 'unknown' }}
16
+ />
17
+ );
18
+ expect(screen.getAllByText('--')).toHaveLength(2);
19
+ });
20
+
21
+ it('renders with provided account statuses', () => {
22
+ render(
23
+ <ListItemStatus
24
+ account={{ generated_status: 'success', uploaded_status: 'running' }}
25
+ />
26
+ );
27
+ expect(screen.getByText('Generated')).toBeTruthy();
28
+ expect(screen.getByText('Uploaded')).toBeTruthy();
29
+ });
14
30
  });
@@ -1,14 +1,38 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
3
  import AccountList from '../AccountList';
4
- import { props } from '../AccountList.fixtures';
4
+ import { accounts } from '../AccountList.fixtures';
5
5
 
6
- const fixtures = {
7
- 'render with props': props,
8
- 'show empty results': { ...props, filterTerm: 'not_matching_term' },
9
- };
6
+ jest.mock('../Components/ListItem', () => ({ label }) => (
7
+ <div>{label}</div>
8
+ ));
10
9
 
11
10
  describe('AccountList', () => {
12
- describe('rendering', () =>
13
- testComponentSnapshotsWithFixtures(AccountList, fixtures));
11
+ it('renders account labels', () => {
12
+ render(<AccountList accounts={accounts} />);
13
+ Object.keys(accounts).forEach(label => {
14
+ expect(screen.getByText(label)).toBeTruthy();
15
+ });
16
+ });
17
+
18
+ it('shows empty results when filterTerm matches nothing', () => {
19
+ render(<AccountList accounts={accounts} filterTerm="not_matching_term" />);
20
+ expect(
21
+ screen.getByText(
22
+ "Oops! Couldn't find organization that matches your query"
23
+ )
24
+ ).toBeTruthy();
25
+ });
26
+
27
+ it('shows empty state when accounts are empty', () => {
28
+ render(<AccountList accounts={{}} />);
29
+ expect(
30
+ screen.getByText('Fetching data about your accounts')
31
+ ).toBeTruthy();
32
+ });
33
+
34
+ it('shows error state when error is present', () => {
35
+ render(<AccountList accounts={{}} error="Server error" />);
36
+ expect(screen.getByText('Server error')).toBeTruthy();
37
+ });
14
38
  });