foreman_rh_cloud 13.0.11 → 13.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3cd43b3c072653346cba58fc50735fe1a91534d5e62260d0808be259f88b621
4
- data.tar.gz: afe8d3c292de19def85bc357dbe6c320968f8b51ddd1b5aff9f5d01cbf378b50
3
+ metadata.gz: 972f28c475749451f2833bc918cfe95601eec5db19e024aec0d550a6f8844ad8
4
+ data.tar.gz: cf12bf0072e5596db8b10fd7901e8c600482bfd0799426da0d7193a7ddd8d1bb
5
5
  SHA512:
6
- metadata.gz: ff518b50470965cdbed1097e72dabaac4dd9a8c07eb6859ddaea0c071965c7b05853c125f624e99c856ee6898d58692dcd2dd499da9e389ec0b3881432c49f2b
7
- data.tar.gz: 6ca347f830741453325dbfe725ab6118be6e211094b1797345abb9fa27fa25e538b13cbc76dab45d2d31b77543434894445137565d486b879372dc09d11bd3e1
6
+ metadata.gz: fe0c825977e36641a874663dc97ba5efcb80ba3dd130123e445739e8ae72c5aff3b2e40859f9e73f3b82ae2be863307d190adf80cc544c4eef52171959bdbd73
7
+ data.tar.gz: d1f9c3d4ef5dd131b9e28a3725ebd6f6bb3bab01e5e30e1970954085264bdaa632449bc4e4ff32ccfbeb5aaa126a4f854d57d2b11fbddc272a89526185fd3811
@@ -13,13 +13,13 @@ module ForemanRhCloud
13
13
  host.reload
14
14
 
15
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_facet&.uuid&.presence
16
+ hbi_host_destroy(host) if ForemanRhCloud.with_iop_smart_proxy? && !organization_destroy && host.insights_uuid.presence
17
17
  host.insights&.destroy!
18
18
  super(host, options)
19
19
  end
20
20
 
21
21
  def hbi_host_destroy(host)
22
- uuid = host.insights_facet.uuid
22
+ uuid = host.insights_uuid
23
23
  logger.debug "Unregistering host #{uuid} from HBI"
24
24
  execute_cloud_request(
25
25
  organization: host.organization,
@@ -21,6 +21,9 @@ module InsightsCloud
21
21
  @host.id
22
22
  )
23
23
 
24
+ # Ensure insights UUID matches subscription UUID (only runs in IoP mode per method guard above)
25
+ @host.ensure_iop_insights_uuid
26
+
24
27
  # in IoP case, the hosts are identified by the sub-man ID, and we can assume they already
25
28
  # exist in the local inventory. This will also handle facet creation for new hosts.
26
29
  return if @host.insights
@@ -26,5 +26,19 @@ module RhCloudHost
26
26
  def insights_facet
27
27
  insights
28
28
  end
29
+
30
+ # In IoP, read directly from the subscription facet to avoid stale data (see comment on ensure_iop_insights_uuid)
31
+ def insights_uuid
32
+ ForemanRhCloud.with_iop_smart_proxy? ? subscription_facet&.uuid : insights_facet&.uuid
33
+ end
34
+
35
+ # In non-IoP, insights_facet uuids are assigned by Hosted.
36
+ # In IoP, insights_facet uuids must match Katello subscription_facet uuids.
37
+ # If the host was previously registered to hosted Insights,
38
+ # we need to correct its uuid.
39
+ def ensure_iop_insights_uuid
40
+ return unless insights_facet.present? && subscription_facet.present? && insights_facet.uuid != subscription_facet.uuid
41
+ insights_facet.update!(uuid: subscription_facet.uuid)
42
+ end
29
43
  end
30
44
  end
@@ -7,7 +7,7 @@ module ForemanRhCloud
7
7
  include ForemanRhCloud::CertAuth
8
8
 
9
9
  def iop_smart_proxy_url
10
- @iop_smart_proxy_url ||= ForemanRhCloud.iop_smart_proxy.url
10
+ ForemanRhCloud.iop_smart_proxy&.url
11
11
  end
12
12
 
13
13
  def service_urls
@@ -33,6 +33,7 @@ module ForemanRhCloud
33
33
  end
34
34
 
35
35
  def ping
36
+ return {} unless ForemanRhCloud.with_iop_smart_proxy?
36
37
  ping_services
37
38
  end
38
39
 
@@ -1,9 +1,7 @@
1
1
  collection @hosts
2
2
 
3
3
  attributes :name
4
- node :insights_uuid do |host|
5
- host.insights_facet&.uuid
6
- end
4
+ node :insights_uuid, &:insights_uuid
7
5
  node :insights_hit_details do |host|
8
6
  host&.facts('insights::hit_details')&.values&.first
9
7
  end
@@ -1,5 +1,6 @@
1
- attributes :uuid
2
-
1
+ node :uuid do |facet|
2
+ facet&.host&.insights_uuid
3
+ end
3
4
  node :insights_hit_details do |facet|
4
5
  facet&.host&.facts('insights::hit_details')&.values&.first
5
6
  end
@@ -118,14 +118,17 @@ module ForemanRhCloud
118
118
  end
119
119
  end
120
120
 
121
+ # Preload insights facet to avoid N+1 queries when rendering host list with facets
122
+ add_controller_action_scope('Api::V2::HostsController', :index) do |base_scope|
123
+ base_scope.preload(:insights)
124
+ end
125
+
121
126
  register_global_js_file 'global'
122
127
 
123
128
  register_custom_status InventorySync::InventoryStatus
124
129
  register_custom_status InsightsClientReportStatus
125
- if ForemanRhCloud.with_iop_smart_proxy?
126
- register_ping_extension { ForemanRhCloud::Ping.ping }
127
- register_status_extension { ForemanRhCloud::Ping.status }
128
- end
130
+ register_ping_extension { ForemanRhCloud::Ping.ping }
131
+ register_status_extension { ForemanRhCloud::Ping.status }
129
132
 
130
133
  describe_host do
131
134
  overview_buttons_provider :insights_host_overview_buttons
@@ -148,7 +151,7 @@ module ForemanRhCloud
148
151
  end
149
152
 
150
153
  ::Foreman::Plugin.app_metadata_registry.register(:foreman_rh_cloud, {
151
- iop: ForemanRhCloud.with_iop_smart_proxy?,
154
+ iop: -> { ForemanRhCloud.with_iop_smart_proxy? },
152
155
  })
153
156
 
154
157
  extend_template_helpers ForemanRhCloud::TemplateRendererHelper
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '13.0.11'.freeze
2
+ VERSION = '13.0.12'.freeze
3
3
  end
@@ -14,15 +14,15 @@ module ForemanRhCloud
14
14
 
15
15
  def self.base_url
16
16
  # for testing set ENV to 'https://ci.cloud.redhat.com'
17
- @base_url ||= env_or_on_premise_url('SATELLITE_RH_CLOUD_URL') || 'https://cloud.redhat.com'
17
+ env_or_on_premise_url('SATELLITE_RH_CLOUD_URL') || 'https://cloud.redhat.com'
18
18
  end
19
19
 
20
20
  def self.cert_base_url
21
- @cert_base_url ||= env_or_on_premise_url('SATELLITE_CERT_RH_CLOUD_URL') || 'https://cert.cloud.redhat.com'
21
+ env_or_on_premise_url('SATELLITE_CERT_RH_CLOUD_URL') || 'https://cert.cloud.redhat.com'
22
22
  end
23
23
 
24
24
  def self.legacy_insights_url
25
- @legacy_insights_url ||= env_or_on_premise_url('SATELLITE_LEGACY_INSIGHTS_URL') || 'https://cert-api.access.redhat.com'
25
+ env_or_on_premise_url('SATELLITE_LEGACY_INSIGHTS_URL') || 'https://cert-api.access.redhat.com'
26
26
  end
27
27
 
28
28
  def self.verify_ssl_method
@@ -126,10 +126,10 @@ module InsightsCloud
126
126
 
127
127
  def invocation_status
128
128
  hosts_state = Hash[job_invocation.targeting.hosts.map do |host|
129
- next unless host.insights&.uuid
129
+ next unless host.insights_uuid
130
130
  [
131
- host.insights.uuid,
132
- task_status(job_invocation.sub_task_for_host(host), host.insights.uuid),
131
+ host.insights_uuid,
132
+ task_status(job_invocation.sub_task_for_host(host), host.insights_uuid),
133
133
  ]
134
134
  end.compact]
135
135
 
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "13.0.11",
3
+ "version": "13.0.12",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -13,7 +13,7 @@ module InsightsCloud
13
13
  end
14
14
 
15
15
  test 'shows hosts with uuids' do
16
- uuids = [@host1.insights.uuid, @host2.insights.uuid]
16
+ uuids = [@host1.insights_uuid, @host2.insights_uuid]
17
17
  get :host_details, params: { organization_id: @test_org.id, host_uuids: uuids }
18
18
  assert_response :success
19
19
  assert_template 'api/v2/advisor_engine/host_details'
@@ -21,6 +21,33 @@ module InsightsCloud
21
21
  refute_equal @test_org.hosts.count, assigns(:hosts).count
22
22
  end
23
23
 
24
+ test 'in IoP mode host_details uses subscription uuid when insights uuid is stale' do
25
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
26
+
27
+ stale_insights_uuid = 'stale-insights-uuid-123'
28
+ subscription_uuid = 'subscription-uuid-456'
29
+
30
+ # Create host with diverging facet UUIDs
31
+ host = FactoryBot.create(:host, :with_subscription, organization: @test_org)
32
+ host.subscription_facet.update!(uuid: subscription_uuid)
33
+ host.insights = FactoryBot.create(:insights_facet, host_id: host.id, uuid: stale_insights_uuid)
34
+ host.save!
35
+
36
+ # Query using the stale insights UUID
37
+ get :host_details, params: {
38
+ organization_id: @test_org.id,
39
+ host_uuids: [stale_insights_uuid],
40
+ }
41
+
42
+ assert_response :success
43
+ body = JSON.parse(response.body)
44
+
45
+ # Should return the subscription UUID, not the stale insights UUID
46
+ insights_uuids = body.map { |h| h['insights_uuid'] }
47
+ assert_includes insights_uuids, subscription_uuid, "Should use subscription UUID in IoP mode"
48
+ refute_includes insights_uuids, stale_insights_uuid, "Should not use stale insights UUID"
49
+ end
50
+
24
51
  test 'shows error when no hosts found' do
25
52
  get :host_details, params: { organization_id: @test_org.id, host_uuids: ['nonexistentuuid'] }
26
53
  assert_response :not_found
@@ -58,5 +58,34 @@ FactoryBot.modify do
58
58
  host.insights = FactoryBot.create(:insights_facet, :with_hits, host_id: host.id)
59
59
  end
60
60
  end
61
+
62
+ trait :with_mismatched_insights_uuid do
63
+ # Simulates host previously registered to cloud with stale UUID
64
+ # Requires :with_subscription trait to be used together
65
+ after(:create) do |host, _evaluator|
66
+ raise "subscription_facet required for :with_mismatched_insights_uuid trait" unless host.subscription_facet&.uuid
67
+
68
+ host.insights = FactoryBot.create(
69
+ :insights_facet,
70
+ host_id: host.id,
71
+ uuid: 'stale-cloud-uuid' # Different from subscription_facet
72
+ )
73
+ end
74
+ end
75
+
76
+ trait :with_synced_insights_uuid do
77
+ # Ideal state: insights_facet UUID matches subscription_facet UUID
78
+ # Requires :with_subscription trait to be used together
79
+ after(:create) do |host, _evaluator|
80
+ raise "subscription_facet required for :with_synced_insights_uuid trait" unless host.subscription_facet&.uuid
81
+
82
+ subscription_uuid = host.subscription_facet.uuid
83
+ host.insights = FactoryBot.create(
84
+ :insights_facet,
85
+ host_id: host.id,
86
+ uuid: subscription_uuid # Same as subscription_facet
87
+ )
88
+ end
89
+ end
61
90
  end
62
91
  end
@@ -0,0 +1,200 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class ForemanRhCloudIopMetadataTest < ActiveSupport::TestCase
4
+ setup do
5
+ # Clean up any existing IoP smart proxies
6
+ SmartProxy.unscoped.with_features('iop').destroy_all
7
+ end
8
+
9
+ teardown do
10
+ # Clean up
11
+ SmartProxy.unscoped.with_features('iop').destroy_all
12
+ end
13
+
14
+ def create_iop_proxy(url: 'https://iop.example.com')
15
+ feature = Feature.find_or_create_by(name: 'iop')
16
+ proxy = FactoryBot.create(:smart_proxy, :url => url)
17
+ # Clear any existing associations for this feature
18
+ feature.reload
19
+ feature.smart_proxies.clear
20
+ proxy.features << feature
21
+ proxy
22
+ end
23
+
24
+ describe 'plugin metadata' do
25
+ test 'iop metadata is false when no IoP smart proxy exists' do
26
+ # Ensure no IoP proxy exists
27
+ refute ForemanRhCloud.with_iop_smart_proxy?
28
+
29
+ # Plugin metadata should reflect this
30
+ metadata = ::Foreman::Plugin.app_metadata_registry.all_plugin_metadata[:foreman_rh_cloud]
31
+
32
+ # The value is a lambda, so we need to call it
33
+ assert_kind_of Proc, metadata[:iop]
34
+ refute metadata[:iop].call
35
+ end
36
+
37
+ test 'iop metadata is true when IoP smart proxy exists' do
38
+ # Create an IoP smart proxy
39
+ create_iop_proxy
40
+
41
+ # Verify proxy exists
42
+ assert ForemanRhCloud.with_iop_smart_proxy?
43
+
44
+ # Plugin metadata should reflect this
45
+ metadata = ::Foreman::Plugin.app_metadata_registry.all_plugin_metadata[:foreman_rh_cloud]
46
+
47
+ # The value is a lambda, so we need to call it
48
+ assert_kind_of Proc, metadata[:iop]
49
+ assert metadata[:iop].call
50
+ end
51
+
52
+ test 'iop metadata updates when IoP smart proxy is created' do
53
+ # Initially no IoP proxy
54
+ metadata = ::Foreman::Plugin.app_metadata_registry.all_plugin_metadata[:foreman_rh_cloud]
55
+ refute metadata[:iop].call
56
+
57
+ # Create an IoP smart proxy
58
+ create_iop_proxy
59
+
60
+ # Metadata should now return true
61
+ assert metadata[:iop].call
62
+ end
63
+
64
+ test 'iop metadata updates when IoP smart proxy is destroyed' do
65
+ # Create an IoP smart proxy
66
+ proxy = create_iop_proxy
67
+
68
+ metadata = ::Foreman::Plugin.app_metadata_registry.all_plugin_metadata[:foreman_rh_cloud]
69
+ assert metadata[:iop].call
70
+
71
+ # Destroy the proxy
72
+ proxy.destroy
73
+
74
+ # Metadata should now return false
75
+ refute metadata[:iop].call
76
+ end
77
+ end
78
+
79
+ describe 'URL methods' do
80
+ test 'base_url returns cloud URL when no IoP smart proxy exists' do
81
+ assert_equal 'https://cloud.redhat.com', ForemanRhCloud.base_url
82
+ end
83
+
84
+ test 'cert_base_url returns cloud URL when no IoP smart proxy exists' do
85
+ assert_equal 'https://cert.cloud.redhat.com', ForemanRhCloud.cert_base_url
86
+ end
87
+
88
+ test 'legacy_insights_url returns cloud URL when no IoP smart proxy exists' do
89
+ assert_equal 'https://cert-api.access.redhat.com', ForemanRhCloud.legacy_insights_url
90
+ end
91
+
92
+ test 'base_url returns IoP URL when IoP smart proxy exists' do
93
+ create_iop_proxy
94
+
95
+ assert_equal 'https://iop.example.com', ForemanRhCloud.base_url
96
+ end
97
+
98
+ test 'cert_base_url returns IoP URL when IoP smart proxy exists' do
99
+ create_iop_proxy
100
+
101
+ assert_equal 'https://iop.example.com', ForemanRhCloud.cert_base_url
102
+ end
103
+
104
+ test 'legacy_insights_url returns IoP URL when IoP smart proxy exists' do
105
+ create_iop_proxy
106
+
107
+ assert_equal 'https://iop.example.com', ForemanRhCloud.legacy_insights_url
108
+ end
109
+
110
+ test 'base_url returns ENV var when set' do
111
+ ENV['SATELLITE_RH_CLOUD_URL'] = 'https://custom.example.com'
112
+
113
+ assert_equal 'https://custom.example.com', ForemanRhCloud.base_url
114
+ ensure
115
+ ENV.delete('SATELLITE_RH_CLOUD_URL')
116
+ end
117
+
118
+ test 'cert_base_url returns ENV var when set' do
119
+ ENV['SATELLITE_CERT_RH_CLOUD_URL'] = 'https://env-cert.cloud.test'
120
+
121
+ assert_equal 'https://env-cert.cloud.test', ForemanRhCloud.cert_base_url
122
+ ensure
123
+ ENV.delete('SATELLITE_CERT_RH_CLOUD_URL')
124
+ end
125
+
126
+ test 'legacy_insights_url returns ENV var when set' do
127
+ ENV['SATELLITE_LEGACY_INSIGHTS_URL'] = 'https://env-legacy.insights.test'
128
+
129
+ assert_equal 'https://env-legacy.insights.test', ForemanRhCloud.legacy_insights_url
130
+ ensure
131
+ ENV.delete('SATELLITE_LEGACY_INSIGHTS_URL')
132
+ end
133
+
134
+ test 'base_url prefers IoP URL over ENV var' do
135
+ ENV['SATELLITE_RH_CLOUD_URL'] = 'https://custom.example.com'
136
+
137
+ create_iop_proxy
138
+
139
+ # IoP URL should take precedence
140
+ assert_equal 'https://iop.example.com', ForemanRhCloud.base_url
141
+ ensure
142
+ ENV.delete('SATELLITE_RH_CLOUD_URL')
143
+ end
144
+
145
+ test 'cert_base_url prefers IoP URL over ENV var' do
146
+ ENV['SATELLITE_CERT_RH_CLOUD_URL'] = 'https://env-cert.cloud.test'
147
+
148
+ create_iop_proxy
149
+
150
+ # IoP URL should take precedence
151
+ assert_equal 'https://iop.example.com', ForemanRhCloud.cert_base_url
152
+ ensure
153
+ ENV.delete('SATELLITE_CERT_RH_CLOUD_URL')
154
+ end
155
+
156
+ test 'legacy_insights_url prefers IoP URL over ENV var' do
157
+ ENV['SATELLITE_LEGACY_INSIGHTS_URL'] = 'https://env-legacy.insights.test'
158
+
159
+ create_iop_proxy
160
+
161
+ # IoP URL should take precedence
162
+ assert_equal 'https://iop.example.com', ForemanRhCloud.legacy_insights_url
163
+ ensure
164
+ ENV.delete('SATELLITE_LEGACY_INSIGHTS_URL')
165
+ end
166
+
167
+ test 'URL methods update when IoP smart proxy is created' do
168
+ # Initially returns cloud URLs
169
+ assert_equal 'https://cloud.redhat.com', ForemanRhCloud.base_url
170
+ assert_equal 'https://cert.cloud.redhat.com', ForemanRhCloud.cert_base_url
171
+ assert_equal 'https://cert-api.access.redhat.com', ForemanRhCloud.legacy_insights_url
172
+
173
+ # Create an IoP smart proxy
174
+ create_iop_proxy
175
+
176
+ # Should now return IoP URL for all helpers
177
+ assert_equal 'https://iop.example.com', ForemanRhCloud.base_url
178
+ assert_equal 'https://iop.example.com', ForemanRhCloud.cert_base_url
179
+ assert_equal 'https://iop.example.com', ForemanRhCloud.legacy_insights_url
180
+ end
181
+
182
+ test 'URL methods update when IoP smart proxy is destroyed' do
183
+ # Create an IoP smart proxy
184
+ proxy = create_iop_proxy
185
+
186
+ # Initially returns IoP URL for all helpers
187
+ assert_equal 'https://iop.example.com', ForemanRhCloud.base_url
188
+ assert_equal 'https://iop.example.com', ForemanRhCloud.cert_base_url
189
+ assert_equal 'https://iop.example.com', ForemanRhCloud.legacy_insights_url
190
+
191
+ # Destroy the proxy
192
+ proxy.destroy
193
+
194
+ # Should now return cloud URLs again
195
+ assert_equal 'https://cloud.redhat.com', ForemanRhCloud.base_url
196
+ assert_equal 'https://cert.cloud.redhat.com', ForemanRhCloud.cert_base_url
197
+ assert_equal 'https://cert-api.access.redhat.com', ForemanRhCloud.legacy_insights_url
198
+ end
199
+ end
200
+ end
@@ -4,8 +4,8 @@ module ForemanRhCloud
4
4
  class RegistrationManagerExtensionsTest < ActiveSupport::TestCase
5
5
  setup do
6
6
  @org = FactoryBot.create(:organization)
7
- @host = FactoryBot.create(:host, :managed, organization: @org)
8
- @insights_facet = ::InsightsFacet.create!(host: @host, uuid: 'test-uuid-123')
7
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
8
+ @insights_facet = ::InsightsFacet.create!(host: @host, uuid: @host.subscription_facet.uuid)
9
9
 
10
10
  # Stub Candlepin interaction (from Katello)
11
11
  ::Katello::Resources::Candlepin::Consumer.stubs(:destroy)
@@ -15,9 +15,9 @@ module ForemanRhCloud
15
15
  end
16
16
 
17
17
  context 'unregister_host' do
18
- test 'should call HBI delete in IoP mode when host has insights facet with UUID' do
18
+ test 'should call HBI delete in IoP mode when host has insights UUID' do
19
19
  ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
20
- expected_url = ForemanInventoryUpload.host_by_id_url('test-uuid-123')
20
+ expected_url = ForemanInventoryUpload.host_by_id_url(@host.subscription_facet.uuid)
21
21
 
22
22
  # Expect the cloud request to be made
23
23
  Katello::RegistrationManager.expects(:execute_cloud_request).with do |params|
@@ -45,44 +45,6 @@ module ForemanRhCloud
45
45
  assert_nil InsightsFacet.find_by(id: @insights_facet.id)
46
46
  end
47
47
 
48
- test 'should NOT call HBI delete when host has no insights_facet' do
49
- host_without_facet = FactoryBot.create(:host, :managed, organization: @org)
50
- ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
51
-
52
- Katello::RegistrationManager.expects(:execute_cloud_request).never
53
-
54
- assert_nothing_raised do
55
- Katello::RegistrationManager.unregister_host(host_without_facet, unregistering: true)
56
- end
57
- end
58
-
59
- test 'should NOT call HBI delete when host has insights_facet with empty UUID' do
60
- host_with_empty_uuid_facet = FactoryBot.create(:host, :managed, organization: @org)
61
- empty_uuid_facet = InsightsFacet.create!(host: host_with_empty_uuid_facet, uuid: '')
62
- ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
63
-
64
- Katello::RegistrationManager.expects(:execute_cloud_request).never
65
-
66
- assert_nothing_raised do
67
- Katello::RegistrationManager.unregister_host(host_with_empty_uuid_facet, unregistering: true)
68
- end
69
-
70
- assert_nil InsightsFacet.find_by(id: empty_uuid_facet.id)
71
- end
72
-
73
- test 'should NOT call HBI delete when insights_facet has no UUID' do
74
- facet_id = @insights_facet.id
75
- @insights_facet.update(uuid: nil)
76
- ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
77
-
78
- Katello::RegistrationManager.expects(:execute_cloud_request).never
79
-
80
- Katello::RegistrationManager.unregister_host(@host, unregistering: true)
81
-
82
- # Verify facet was still destroyed
83
- assert_nil InsightsFacet.find_by(id: facet_id)
84
- end
85
-
86
48
  test 'should always destroy insights_facet regardless of IoP mode' do
87
49
  facet_id = @insights_facet.id
88
50
  ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
@@ -0,0 +1,191 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class RhCloudHostTest < ActiveSupport::TestCase
4
+ setup do
5
+ @org = FactoryBot.create(:organization)
6
+ end
7
+
8
+ teardown do
9
+ ForemanRhCloud.unstub(:with_iop_smart_proxy?)
10
+ end
11
+
12
+ context 'insights_uuid method' do
13
+ test 'returns insights_facet uuid in non-IoP mode' do
14
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
15
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
16
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-123')
17
+
18
+ assert_equal 'insights-123', @host.insights_uuid
19
+ assert_not_equal @host.subscription_facet.uuid, @host.insights_uuid
20
+ end
21
+
22
+ test 'returns subscription_facet uuid in IoP mode' do
23
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
24
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
25
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-456')
26
+
27
+ assert_equal @host.subscription_facet.uuid, @host.insights_uuid
28
+ assert_not_equal 'insights-456', @host.insights_uuid
29
+ end
30
+
31
+ test 'returns nil when insights_facet missing in non-IoP mode' do
32
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
33
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
34
+
35
+ assert_nil @host.insights_uuid
36
+ end
37
+
38
+ test 'returns nil when subscription_facet missing in IoP mode' do
39
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
40
+ @host = FactoryBot.create(:host, :managed, organization: @org)
41
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-789')
42
+
43
+ assert_nil @host.insights_uuid
44
+ end
45
+
46
+ test 'returns nil when both facets missing' do
47
+ @host = FactoryBot.create(:host, :managed, organization: @org)
48
+
49
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
50
+ assert_nil @host.insights_uuid
51
+
52
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
53
+ assert_nil @host.insights_uuid
54
+ end
55
+
56
+ test 'never returns stale insights_facet uuid in IoP mode' do
57
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
58
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
59
+ current_uuid = @host.subscription_facet.uuid
60
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'stale-456')
61
+
62
+ # Should return subscription_facet UUID, never the stale insights_facet UUID
63
+ assert_equal current_uuid, @host.insights_uuid
64
+ assert_not_equal 'stale-456', @host.insights_uuid
65
+
66
+ # Verify multiple calls always return subscription_facet UUID
67
+ 3.times do
68
+ assert_equal current_uuid, @host.insights_uuid
69
+ end
70
+ end
71
+
72
+ test 'dynamically responds to IoP mode changes' do
73
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
74
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-123')
75
+ subscription_uuid = @host.subscription_facet.uuid
76
+
77
+ # Non-IoP mode: should return insights_facet UUID
78
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
79
+ assert_equal 'insights-123', @host.insights_uuid
80
+
81
+ # IoP mode: should return subscription_facet UUID
82
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
83
+ assert_equal subscription_uuid, @host.insights_uuid
84
+
85
+ # Toggle back to non-IoP mode
86
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
87
+ assert_equal 'insights-123', @host.insights_uuid
88
+ end
89
+ end
90
+
91
+ context 'ensure_iop_insights_uuid method' do
92
+ test 'updates insights_facet uuid when different from subscription_facet' do
93
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
94
+ correct_uuid = @host.subscription_facet.uuid
95
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'wrong-456')
96
+
97
+ assert_equal 'wrong-456', @host.insights_facet.uuid
98
+
99
+ @host.ensure_iop_insights_uuid
100
+
101
+ assert_equal correct_uuid, @host.insights_facet.reload.uuid
102
+ end
103
+
104
+ test 'does nothing when uuids already match' do
105
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
106
+ matching_uuid = @host.subscription_facet.uuid
107
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: matching_uuid)
108
+
109
+ # Expect no update call since UUIDs already match
110
+ @host.insights_facet.expects(:update!).never
111
+
112
+ @host.ensure_iop_insights_uuid
113
+
114
+ assert_equal matching_uuid, @host.insights_facet.uuid
115
+ end
116
+
117
+ test 'does nothing when insights_facet missing' do
118
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
119
+
120
+ assert_nothing_raised do
121
+ @host.ensure_iop_insights_uuid
122
+ end
123
+ end
124
+
125
+ test 'does nothing when subscription_facet missing' do
126
+ @host = FactoryBot.create(:host, :managed, organization: @org)
127
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-999')
128
+ original_uuid = @host.insights_facet.uuid
129
+
130
+ assert_nothing_raised do
131
+ @host.ensure_iop_insights_uuid
132
+ end
133
+
134
+ assert_equal original_uuid, @host.insights_facet.uuid
135
+ end
136
+
137
+ test 'does nothing when both facets missing' do
138
+ @host = FactoryBot.create(:host, :managed, organization: @org)
139
+
140
+ assert_nothing_raised do
141
+ @host.ensure_iop_insights_uuid
142
+ end
143
+ end
144
+
145
+ test 'handles nil uuids gracefully' do
146
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
147
+
148
+ # Scenario 1: subscription_facet uuid is nil (shouldn't happen but test gracefully)
149
+ @host.subscription_facet.update(uuid: nil)
150
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'some-uuid')
151
+
152
+ assert_nothing_raised do
153
+ @host.ensure_iop_insights_uuid
154
+ end
155
+
156
+ # Scenario 2: insights_facet uuid is nil
157
+ @host.subscription_facet.update(uuid: 'valid-uuid')
158
+ @host.insights_facet.update(uuid: nil)
159
+
160
+ assert_nothing_raised do
161
+ @host.ensure_iop_insights_uuid
162
+ end
163
+
164
+ # Should update to match subscription_facet
165
+ assert_equal 'valid-uuid', @host.insights_facet.reload.uuid
166
+ end
167
+
168
+ test 'corrects stale uuid after cloud registration' do
169
+ # Simulate a host that was previously registered to cloud with cloud-assigned UUID
170
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
171
+ local_uuid = @host.subscription_facet.uuid
172
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'cloud-456')
173
+
174
+ # Before sync: insights_facet has stale cloud UUID
175
+ assert_equal 'cloud-456', @host.insights_facet.uuid
176
+
177
+ # In IoP mode, insights_uuid should return subscription_facet UUID (not stale)
178
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
179
+ assert_equal local_uuid, @host.insights_uuid
180
+
181
+ # Call sync to correct the stale UUID
182
+ @host.ensure_iop_insights_uuid
183
+
184
+ # After sync: insights_facet UUID should match subscription_facet UUID
185
+ assert_equal local_uuid, @host.insights_facet.reload.uuid
186
+
187
+ # Verify insights_uuid still returns correct value
188
+ assert_equal local_uuid, @host.insights_uuid
189
+ end
190
+ end
191
+ 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: 13.0.11
4
+ version: 13.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
@@ -277,12 +277,14 @@ files:
277
277
  - test/test_plugin_helper.rb
278
278
  - test/unit/archived_report_generator_test.rb
279
279
  - test/unit/fact_helpers_test.rb
280
+ - test/unit/foreman_rh_cloud_iop_metadata_test.rb
280
281
  - test/unit/foreman_rh_cloud_self_host_test.rb
281
282
  - test/unit/insights_facet_test.rb
282
283
  - test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb
283
284
  - test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb
284
285
  - test/unit/metadata_generator_test.rb
285
286
  - test/unit/playbook_progress_generator_test.rb
287
+ - test/unit/rh_cloud_host_test.rb
286
288
  - test/unit/rh_cloud_http_proxy_test.rb
287
289
  - test/unit/rh_cloud_permissions_test.rb
288
290
  - test/unit/services/foreman_rh_cloud/branch_info_test.rb
@@ -691,12 +693,14 @@ test_files:
691
693
  - test/test_plugin_helper.rb
692
694
  - test/unit/archived_report_generator_test.rb
693
695
  - test/unit/fact_helpers_test.rb
696
+ - test/unit/foreman_rh_cloud_iop_metadata_test.rb
694
697
  - test/unit/foreman_rh_cloud_self_host_test.rb
695
698
  - test/unit/insights_facet_test.rb
696
699
  - test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb
697
700
  - test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb
698
701
  - test/unit/metadata_generator_test.rb
699
702
  - test/unit/playbook_progress_generator_test.rb
703
+ - test/unit/rh_cloud_host_test.rb
700
704
  - test/unit/rh_cloud_http_proxy_test.rb
701
705
  - test/unit/rh_cloud_permissions_test.rb
702
706
  - test/unit/services/foreman_rh_cloud/branch_info_test.rb