foreman_rh_cloud 14.0.3 → 14.1.1
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/app/controllers/concerns/insights_cloud/candlepin_proxies_extensions.rb +23 -0
- data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +9 -0
- data/app/controllers/foreman_inventory_upload/accounts_controller.rb +1 -1
- data/app/controllers/foreman_inventory_upload/api/tasks_controller.rb +2 -2
- data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +9 -2
- data/app/models/concerns/rh_cloud_host.rb +35 -3
- data/app/models/insights_client_report_status.rb +9 -1
- data/app/models/inventory_sync/inventory_status.rb +16 -4
- data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +8 -2
- data/lib/foreman_rh_cloud/engine.rb +1 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/insights_cloud/async/vmaas_reposcan_sync.rb +23 -8
- data/lib/inventory_sync/async/inventory_full_sync.rb +39 -3
- data/package.json +1 -1
- data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +40 -0
- data/test/controllers/insights_cloud/candlepin_proxies_extensions_test.rb +70 -0
- data/test/jobs/insights_client_status_aging_test.rb +40 -0
- data/test/jobs/inventory_full_sync_test.rb +212 -0
- data/test/models/insights_client_report_status_test.rb +109 -0
- data/test/models/inventory_sync/inventory_status_test.rb +85 -0
- data/test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb +80 -25
- data/test/unit/rh_cloud_host_test.rb +214 -0
- data/webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js +30 -3
- data/webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js +112 -10
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonActions.js +8 -2
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +1 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/integrations.test.js +1 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Toast.js +43 -17
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/__tests__/Toast.test.js +82 -0
- data/webpack/ForemanRhCloudHelpers.js +22 -0
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +7 -4
- data/webpack/InsightsCloudSync/Components/InsightsTable/table.scss +9 -0
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +53 -12
- data/webpack/InsightsHostDetailsTab/__tests__/NewHostDetailsTab.test.js +134 -22
- metadata +7 -1
|
@@ -5,6 +5,7 @@ class InventoryFullSyncTest < ActiveSupport::TestCase
|
|
|
5
5
|
include Dynflow::Testing::Factories
|
|
6
6
|
include MockCerts
|
|
7
7
|
include KatelloCVEHelper
|
|
8
|
+
include CandlepinIsolation
|
|
8
9
|
|
|
9
10
|
setup do
|
|
10
11
|
User.current = User.find_by(login: 'secret_admin')
|
|
@@ -310,4 +311,215 @@ class InventoryFullSyncTest < ActiveSupport::TestCase
|
|
|
310
311
|
|
|
311
312
|
assert_nil InventorySync::InventoryStatus.where(host_id: @host3.id).first
|
|
312
313
|
end
|
|
314
|
+
|
|
315
|
+
test 'user-omitted hosts get USER_OMITTED status' do
|
|
316
|
+
# Add parameter to exclude host1
|
|
317
|
+
@host1.host_parameters << HostParameter.create(
|
|
318
|
+
name: 'host_registration_insights_inventory',
|
|
319
|
+
value: 'false',
|
|
320
|
+
parameter_type: 'boolean'
|
|
321
|
+
)
|
|
322
|
+
@host1.save!
|
|
323
|
+
|
|
324
|
+
setup_certs_expectation do
|
|
325
|
+
InventorySync::Async::InventoryFullSync.any_instance.stubs(:candlepin_id_cert)
|
|
326
|
+
end
|
|
327
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory)
|
|
328
|
+
FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
|
|
329
|
+
|
|
330
|
+
action = create_and_plan_action(InventorySync::Async::InventoryFullSync, @host1.organization)
|
|
331
|
+
run_action(action)
|
|
332
|
+
|
|
333
|
+
@host1.reload
|
|
334
|
+
@host2.reload
|
|
335
|
+
|
|
336
|
+
# Host1 should be USER_OMITTED
|
|
337
|
+
assert_equal InventorySync::InventoryStatus::USER_OMITTED,
|
|
338
|
+
InventorySync::InventoryStatus.where(host_id: @host1.id).first.status,
|
|
339
|
+
'Host with host_registration_insights_inventory=false should have USER_OMITTED status'
|
|
340
|
+
|
|
341
|
+
# Host2 should be SYNC
|
|
342
|
+
assert_equal InventorySync::InventoryStatus::SYNC,
|
|
343
|
+
InventorySync::InventoryStatus.where(host_id: @host2.id).first.status,
|
|
344
|
+
'Normal host should have SYNC status'
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
test 'user-omitted hosts are not marked as disconnected' do
|
|
348
|
+
# Add parameter to exclude host1
|
|
349
|
+
@host1.host_parameters << HostParameter.create(
|
|
350
|
+
name: 'host_registration_insights_inventory',
|
|
351
|
+
value: 'false',
|
|
352
|
+
parameter_type: 'boolean'
|
|
353
|
+
)
|
|
354
|
+
@host1.save!
|
|
355
|
+
|
|
356
|
+
# Host1 is not in the cloud inventory response
|
|
357
|
+
setup_certs_expectation do
|
|
358
|
+
InventorySync::Async::InventoryFullSync.any_instance.stubs(:candlepin_id_cert)
|
|
359
|
+
end
|
|
360
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory)
|
|
361
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:affected_host_ids).returns([@host1.id, @host2.id])
|
|
362
|
+
FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
|
|
363
|
+
|
|
364
|
+
action = create_and_plan_action(InventorySync::Async::InventoryFullSync, @host1.organization)
|
|
365
|
+
run_action(action)
|
|
366
|
+
|
|
367
|
+
@host1.reload
|
|
368
|
+
|
|
369
|
+
# Host1 should be USER_OMITTED, not DISCONNECT
|
|
370
|
+
assert_equal InventorySync::InventoryStatus::USER_OMITTED,
|
|
371
|
+
InventorySync::InventoryStatus.where(host_id: @host1.id).first.status,
|
|
372
|
+
'User-omitted host should have USER_OMITTED status even if not in cloud inventory'
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
test 'host_statuses output includes all three counts' do
|
|
376
|
+
# Create a mix of hosts with different statuses
|
|
377
|
+
# Host1: will be user-omitted
|
|
378
|
+
@host1.host_parameters << HostParameter.create(
|
|
379
|
+
name: 'host_registration_insights_inventory',
|
|
380
|
+
value: 'false',
|
|
381
|
+
parameter_type: 'boolean'
|
|
382
|
+
)
|
|
383
|
+
@host1.save!
|
|
384
|
+
|
|
385
|
+
# Host2: will be synced (in cloud inventory)
|
|
386
|
+
# Host3: will be disconnected (not in cloud inventory)
|
|
387
|
+
|
|
388
|
+
# Create inventory response with only host2 (exclude host1 and host3)
|
|
389
|
+
inventory_with_host2_only = @inventory.dup
|
|
390
|
+
inventory_with_host2_only['results'] = [@inventory['results'][0]] # Only host2
|
|
391
|
+
inventory_with_host2_only['total'] = 1
|
|
392
|
+
inventory_with_host2_only['count'] = 1
|
|
393
|
+
|
|
394
|
+
setup_certs_expectation do
|
|
395
|
+
InventorySync::Async::InventoryFullSync.any_instance.stubs(:candlepin_id_cert)
|
|
396
|
+
end
|
|
397
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(inventory_with_host2_only)
|
|
398
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:affected_host_ids).returns([@host1.id, @host2.id, @host3.id])
|
|
399
|
+
FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
|
|
400
|
+
|
|
401
|
+
action = create_and_plan_action(InventorySync::Async::InventoryFullSync, @host1.organization)
|
|
402
|
+
run_action(action)
|
|
403
|
+
|
|
404
|
+
# Verify the statuses were actually set correctly
|
|
405
|
+
@host1.reload
|
|
406
|
+
@host2.reload
|
|
407
|
+
@host3.reload
|
|
408
|
+
|
|
409
|
+
assert_equal InventorySync::InventoryStatus::USER_OMITTED,
|
|
410
|
+
InventorySync::InventoryStatus.where(host_id: @host1.id).first.status,
|
|
411
|
+
'Host with host_registration_insights_inventory=false should have USER_OMITTED status'
|
|
412
|
+
assert_equal InventorySync::InventoryStatus::SYNC,
|
|
413
|
+
InventorySync::InventoryStatus.where(host_id: @host2.id).first.status,
|
|
414
|
+
'Host in cloud inventory should have SYNC status'
|
|
415
|
+
assert_equal InventorySync::InventoryStatus::DISCONNECT,
|
|
416
|
+
InventorySync::InventoryStatus.where(host_id: @host3.id).first.status,
|
|
417
|
+
'Host not in cloud inventory and not user-omitted should have DISCONNECT status'
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
test 'user-omitted status respects parameter inheritance from hostgroup' do
|
|
421
|
+
# Create a hostgroup and assign it to host1
|
|
422
|
+
hostgroup = FactoryBot.create(:hostgroup)
|
|
423
|
+
hostgroup.organizations << @host1.organization
|
|
424
|
+
@host1.hostgroup = hostgroup
|
|
425
|
+
@host1.save!
|
|
426
|
+
|
|
427
|
+
# Set parameter at hostgroup level, not directly on host
|
|
428
|
+
# This verifies the fix that uses search_for instead of querying HostParameter directly
|
|
429
|
+
hostgroup.group_parameters << GroupParameter.create(
|
|
430
|
+
name: 'host_registration_insights_inventory',
|
|
431
|
+
value: 'false',
|
|
432
|
+
key_type: 'boolean'
|
|
433
|
+
)
|
|
434
|
+
hostgroup.save!
|
|
435
|
+
|
|
436
|
+
# Verify parameter is inherited (not set directly on host)
|
|
437
|
+
assert_nil @host1.parameters.find_by(name: 'host_registration_insights_inventory'),
|
|
438
|
+
'Test setup: parameter should not be set directly on host'
|
|
439
|
+
refute ::Foreman::Cast.to_bool(@host1.host_param('host_registration_insights_inventory')),
|
|
440
|
+
'Test setup: parameter should be inherited from hostgroup'
|
|
441
|
+
|
|
442
|
+
# Host2 remains normal (no parameter)
|
|
443
|
+
setup_certs_expectation do
|
|
444
|
+
InventorySync::Async::InventoryFullSync.any_instance.stubs(:candlepin_id_cert)
|
|
445
|
+
end
|
|
446
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory)
|
|
447
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:affected_host_ids).returns([@host1.id, @host2.id])
|
|
448
|
+
FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
|
|
449
|
+
|
|
450
|
+
action = create_and_plan_action(InventorySync::Async::InventoryFullSync, @host1.organization)
|
|
451
|
+
run_action(action)
|
|
452
|
+
|
|
453
|
+
@host1.reload
|
|
454
|
+
@host2.reload
|
|
455
|
+
|
|
456
|
+
# Host1 should be USER_OMITTED (inherited parameter from hostgroup)
|
|
457
|
+
host1_status = InventorySync::InventoryStatus.where(host_id: @host1.id).first
|
|
458
|
+
assert_not_nil host1_status, 'Host1 should have an inventory status'
|
|
459
|
+
assert_equal InventorySync::InventoryStatus::USER_OMITTED, host1_status.status,
|
|
460
|
+
'Host with inherited host_registration_insights_inventory=false should have USER_OMITTED status'
|
|
461
|
+
|
|
462
|
+
# Host2 should be SYNC
|
|
463
|
+
assert_equal InventorySync::InventoryStatus::SYNC,
|
|
464
|
+
InventorySync::InventoryStatus.where(host_id: @host2.id).first.status,
|
|
465
|
+
'Normal host should have SYNC status'
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
test 'user-omitted statuses are cleared before re-creating them to avoid silent create failures' do
|
|
469
|
+
# First sync: host1 is user-omitted
|
|
470
|
+
@host1.host_parameters << HostParameter.create(
|
|
471
|
+
name: 'host_registration_insights_inventory',
|
|
472
|
+
value: 'false',
|
|
473
|
+
parameter_type: 'boolean'
|
|
474
|
+
)
|
|
475
|
+
@host1.save!
|
|
476
|
+
|
|
477
|
+
setup_certs_expectation do
|
|
478
|
+
InventorySync::Async::InventoryFullSync.any_instance.stubs(:candlepin_id_cert)
|
|
479
|
+
end
|
|
480
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory).twice
|
|
481
|
+
InventorySync::Async::InventoryFullSync.any_instance.expects(:affected_host_ids).returns([@host1.id, @host2.id]).twice
|
|
482
|
+
FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
|
|
483
|
+
|
|
484
|
+
# Run first sync
|
|
485
|
+
action = create_and_plan_action(InventorySync::Async::InventoryFullSync, @host1.organization)
|
|
486
|
+
run_action(action)
|
|
487
|
+
|
|
488
|
+
@host1.reload
|
|
489
|
+
initial_status = InventorySync::InventoryStatus.where(host_id: @host1.id).first
|
|
490
|
+
assert_equal InventorySync::InventoryStatus::USER_OMITTED, initial_status.status,
|
|
491
|
+
'Initial sync: host should be USER_OMITTED'
|
|
492
|
+
initial_status_id = initial_status.id
|
|
493
|
+
|
|
494
|
+
# Verify there's only one status record for host1
|
|
495
|
+
assert_equal 1, InventorySync::InventoryStatus.where(host_id: @host1.id).count,
|
|
496
|
+
'Should have exactly one status record after first sync'
|
|
497
|
+
|
|
498
|
+
# Run second sync (parameter still false)
|
|
499
|
+
# Without clearing old user_omitted statuses, the .create would silently fail
|
|
500
|
+
# with 'Host has already been taken' due to uniqueness constraint
|
|
501
|
+
setup_certs_expectation do
|
|
502
|
+
InventorySync::Async::InventoryFullSync.any_instance.stubs(:candlepin_id_cert)
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
action2 = create_and_plan_action(InventorySync::Async::InventoryFullSync, @host1.organization)
|
|
506
|
+
run_action(action2)
|
|
507
|
+
|
|
508
|
+
@host1.reload
|
|
509
|
+
final_status = InventorySync::InventoryStatus.where(host_id: @host1.id).first
|
|
510
|
+
|
|
511
|
+
# Verify status is still USER_OMITTED (not stale from first sync)
|
|
512
|
+
assert_equal InventorySync::InventoryStatus::USER_OMITTED, final_status.status,
|
|
513
|
+
'Status should be USER_OMITTED after second sync'
|
|
514
|
+
|
|
515
|
+
# Verify there's still only one status record (old one was deleted before creating new one)
|
|
516
|
+
assert_equal 1, InventorySync::InventoryStatus.where(host_id: @host1.id).count,
|
|
517
|
+
'Should have exactly one status record (old cleared before new created)'
|
|
518
|
+
|
|
519
|
+
# Verify the old status record was actually deleted and replaced with a new one
|
|
520
|
+
refute InventorySync::InventoryStatus.exists?(initial_status_id),
|
|
521
|
+
'Old status record should have been deleted before creating new one'
|
|
522
|
+
assert_not_equal initial_status_id, final_status.id,
|
|
523
|
+
'New status record should have different ID, proving old was deleted'
|
|
524
|
+
end
|
|
313
525
|
end
|
|
@@ -72,4 +72,113 @@ class InsightsClientReportStatusTest < ActiveSupport::TestCase
|
|
|
72
72
|
|
|
73
73
|
assert_equal HostStatus::Global::ERROR, @host.global_status
|
|
74
74
|
end
|
|
75
|
+
|
|
76
|
+
test 'host with host_registration_insights parameter set to false gets USER_OMITTED status' do
|
|
77
|
+
@host.host_parameters << HostParameter.create(
|
|
78
|
+
name: 'host_registration_insights',
|
|
79
|
+
value: 'false',
|
|
80
|
+
parameter_type: 'boolean'
|
|
81
|
+
)
|
|
82
|
+
@host.save!
|
|
83
|
+
|
|
84
|
+
insights_status = @host.get_status(InsightsClientReportStatus)
|
|
85
|
+
insights_status.refresh!
|
|
86
|
+
|
|
87
|
+
assert_equal InsightsClientReportStatus::USER_OMITTED, insights_status.status
|
|
88
|
+
assert_equal HostStatus::Global::OK, insights_status.to_global
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
test 'USER_OMITTED status has correct label' do
|
|
92
|
+
insights_status = @host.get_status(InsightsClientReportStatus)
|
|
93
|
+
insights_status.status = InsightsClientReportStatus::USER_OMITTED
|
|
94
|
+
insights_status.save!
|
|
95
|
+
|
|
96
|
+
label = insights_status.to_label
|
|
97
|
+
assert_match(/host_registration_insights/, label)
|
|
98
|
+
assert_match(/false/, label)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
test 'stale scope excludes USER_OMITTED hosts' do
|
|
102
|
+
host1 = FactoryBot.create(:host, :managed)
|
|
103
|
+
host2 = FactoryBot.create(:host, :managed)
|
|
104
|
+
host3 = FactoryBot.create(:host, :managed)
|
|
105
|
+
|
|
106
|
+
# Host 1: USER_OMITTED with old reported_at (should NOT be in stale scope)
|
|
107
|
+
status1 = host1.get_status(InsightsClientReportStatus)
|
|
108
|
+
status1.status = InsightsClientReportStatus::USER_OMITTED
|
|
109
|
+
status1.reported_at = Time.zone.now - InsightsClientReportStatus::REPORT_INTERVAL - 1.day
|
|
110
|
+
status1.save!
|
|
111
|
+
|
|
112
|
+
# Host 2: REPORTING with old reported_at (should be in stale scope)
|
|
113
|
+
status2 = host2.get_status(InsightsClientReportStatus)
|
|
114
|
+
status2.status = InsightsClientReportStatus::REPORTING
|
|
115
|
+
status2.reported_at = Time.zone.now - InsightsClientReportStatus::REPORT_INTERVAL - 1.day
|
|
116
|
+
status2.save!
|
|
117
|
+
|
|
118
|
+
# Host 3: NO_REPORT with old reported_at (should be in stale scope)
|
|
119
|
+
status3 = host3.get_status(InsightsClientReportStatus)
|
|
120
|
+
status3.status = InsightsClientReportStatus::NO_REPORT
|
|
121
|
+
status3.reported_at = Time.zone.now - InsightsClientReportStatus::REPORT_INTERVAL - 1.day
|
|
122
|
+
status3.save!
|
|
123
|
+
|
|
124
|
+
stale_statuses = InsightsClientReportStatus.stale
|
|
125
|
+
stale_host_ids = stale_statuses.pluck(:host_id)
|
|
126
|
+
|
|
127
|
+
assert_not_includes stale_host_ids, host1.id, 'USER_OMITTED host should not be in stale scope'
|
|
128
|
+
assert_includes stale_host_ids, host2.id, 'REPORTING host with old report should be in stale scope'
|
|
129
|
+
assert_includes stale_host_ids, host3.id, 'NO_REPORT host with old report should be in stale scope'
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
test 'USER_OMITTED status respects parameter inheritance from hostgroup' do
|
|
133
|
+
# Create a hostgroup with parameter = false
|
|
134
|
+
hostgroup = FactoryBot.create(:hostgroup)
|
|
135
|
+
hostgroup.group_parameters << GroupParameter.create(
|
|
136
|
+
name: 'host_registration_insights',
|
|
137
|
+
value: 'false',
|
|
138
|
+
key_type: 'boolean'
|
|
139
|
+
)
|
|
140
|
+
hostgroup.save!
|
|
141
|
+
|
|
142
|
+
@host.hostgroup = hostgroup
|
|
143
|
+
@host.save!
|
|
144
|
+
|
|
145
|
+
# Verify parameter is inherited (not set directly on host)
|
|
146
|
+
assert_nil @host.parameters.find_by(name: 'host_registration_insights'),
|
|
147
|
+
'Test setup: parameter should not be set directly on host'
|
|
148
|
+
|
|
149
|
+
insights_status = @host.get_status(InsightsClientReportStatus)
|
|
150
|
+
insights_status.refresh!
|
|
151
|
+
|
|
152
|
+
assert_equal InsightsClientReportStatus::USER_OMITTED, insights_status.status,
|
|
153
|
+
'Status should be USER_OMITTED when host_registration_insights=false is inherited from hostgroup'
|
|
154
|
+
assert_equal HostStatus::Global::OK, insights_status.to_global,
|
|
155
|
+
'USER_OMITTED status should not affect global status'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
test 'host parameter overrides inherited parameter from hostgroup' do
|
|
159
|
+
# Create a hostgroup with parameter = false
|
|
160
|
+
hostgroup = FactoryBot.create(:hostgroup)
|
|
161
|
+
hostgroup.group_parameters << GroupParameter.create(
|
|
162
|
+
name: 'host_registration_insights',
|
|
163
|
+
value: 'false',
|
|
164
|
+
key_type: 'boolean'
|
|
165
|
+
)
|
|
166
|
+
hostgroup.save!
|
|
167
|
+
|
|
168
|
+
@host.hostgroup = hostgroup
|
|
169
|
+
|
|
170
|
+
# Override with host parameter = true
|
|
171
|
+
@host.host_parameters << HostParameter.create(
|
|
172
|
+
name: 'host_registration_insights',
|
|
173
|
+
value: 'true',
|
|
174
|
+
parameter_type: 'boolean'
|
|
175
|
+
)
|
|
176
|
+
@host.save!
|
|
177
|
+
|
|
178
|
+
insights_status = @host.get_status(InsightsClientReportStatus)
|
|
179
|
+
insights_status.refresh!
|
|
180
|
+
|
|
181
|
+
assert_not_equal InsightsClientReportStatus::USER_OMITTED, insights_status.status,
|
|
182
|
+
'Status should not be USER_OMITTED when host parameter overrides hostgroup parameter with true'
|
|
183
|
+
end
|
|
75
184
|
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
|
|
3
|
+
module InventorySync
|
|
4
|
+
class InventoryStatusTest < ActiveSupport::TestCase
|
|
5
|
+
setup do
|
|
6
|
+
@host = FactoryBot.create(:host, :managed)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
test 'status constants are defined correctly' do
|
|
10
|
+
assert_equal 0, InventorySync::InventoryStatus::DISCONNECT
|
|
11
|
+
assert_equal 1, InventorySync::InventoryStatus::SYNC
|
|
12
|
+
assert_equal 2, InventorySync::InventoryStatus::USER_OMITTED
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
test 'to_global returns OK for USER_OMITTED status' do
|
|
16
|
+
status = @host.get_status(InventorySync::InventoryStatus)
|
|
17
|
+
status.status = InventorySync::InventoryStatus::USER_OMITTED
|
|
18
|
+
status.save!
|
|
19
|
+
|
|
20
|
+
assert_equal HostStatus::Global::OK, status.to_global
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test 'to_global returns WARN for DISCONNECT status' do
|
|
24
|
+
status = @host.get_status(InventorySync::InventoryStatus)
|
|
25
|
+
status.status = InventorySync::InventoryStatus::DISCONNECT
|
|
26
|
+
status.save!
|
|
27
|
+
|
|
28
|
+
assert_equal HostStatus::Global::WARN, status.to_global
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
test 'to_global returns OK for SYNC status' do
|
|
32
|
+
status = @host.get_status(InventorySync::InventoryStatus)
|
|
33
|
+
status.status = InventorySync::InventoryStatus::SYNC
|
|
34
|
+
status.save!
|
|
35
|
+
|
|
36
|
+
assert_equal HostStatus::Global::OK, status.to_global
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
test 'to_label returns appropriate messages for each status' do
|
|
40
|
+
status = @host.get_status(InventorySync::InventoryStatus)
|
|
41
|
+
|
|
42
|
+
# Test DISCONNECT label
|
|
43
|
+
status.status = InventorySync::InventoryStatus::DISCONNECT
|
|
44
|
+
status.save!
|
|
45
|
+
label = status.to_label
|
|
46
|
+
assert_match(/not present/, label.downcase)
|
|
47
|
+
assert_match(/console\.redhat\.com/, label)
|
|
48
|
+
|
|
49
|
+
# Test SYNC label
|
|
50
|
+
status.status = InventorySync::InventoryStatus::SYNC
|
|
51
|
+
status.save!
|
|
52
|
+
label = status.to_label
|
|
53
|
+
assert_match(/uploaded.*present/, label.downcase)
|
|
54
|
+
assert_match(/console\.redhat\.com/, label)
|
|
55
|
+
|
|
56
|
+
# Test USER_OMITTED label
|
|
57
|
+
status.status = InventorySync::InventoryStatus::USER_OMITTED
|
|
58
|
+
status.save!
|
|
59
|
+
label = status.to_label
|
|
60
|
+
assert_match(/excluded/, label.downcase)
|
|
61
|
+
assert_match(/host parameter/, label.downcase)
|
|
62
|
+
assert_match(/console\.redhat\.com/, label)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
test 'relevant? returns true in regular (non-IoP) mode' do
|
|
66
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
67
|
+
|
|
68
|
+
status = @host.get_status(InventorySync::InventoryStatus)
|
|
69
|
+
status.status = InventorySync::InventoryStatus::SYNC
|
|
70
|
+
status.save!
|
|
71
|
+
|
|
72
|
+
assert status.relevant?, 'Inventory status should be relevant in regular mode'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
test 'relevant? returns false in IoP mode' do
|
|
76
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
77
|
+
|
|
78
|
+
status = @host.get_status(InventorySync::InventoryStatus)
|
|
79
|
+
status.status = InventorySync::InventoryStatus::SYNC
|
|
80
|
+
status.save!
|
|
81
|
+
|
|
82
|
+
refute status.relevant?, 'Inventory status should NOT be relevant in IoP mode'
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -5,19 +5,17 @@ class VmaasReposcanSyncTest < ActiveSupport::TestCase
|
|
|
5
5
|
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
|
6
6
|
|
|
7
7
|
setup do
|
|
8
|
-
@
|
|
9
|
-
|
|
10
|
-
@repo =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
distribution_version: '7.5',
|
|
15
|
-
root: @root
|
|
16
|
-
)
|
|
8
|
+
@organization = FactoryBot.create(:organization)
|
|
9
|
+
# Create a simple repository - we only need id and organization_id for the action
|
|
10
|
+
@repo = ::Katello::Repository.new(id: 1)
|
|
11
|
+
@repo.stubs(:organization_id).returns(@organization.id)
|
|
12
|
+
::Katello::Repository.stubs(:find).with(1).returns(@repo)
|
|
13
|
+
|
|
17
14
|
@repo_payload = { id: @repo.id }
|
|
18
15
|
@expected_url = 'https://example.com/api/v1/vmaas/reposcan/sync'
|
|
19
16
|
InsightsCloud.stubs(:vmaas_reposcan_sync_url).returns(@expected_url)
|
|
20
17
|
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
18
|
+
Organization.stubs(:find).with(@organization.id).returns(@organization)
|
|
21
19
|
end
|
|
22
20
|
|
|
23
21
|
teardown do
|
|
@@ -83,7 +81,7 @@ class VmaasReposcanSyncTest < ActiveSupport::TestCase
|
|
|
83
81
|
params[:url] == @expected_url &&
|
|
84
82
|
params[:headers].is_a?(Hash) &&
|
|
85
83
|
params[:headers]['Content-Type'] == 'application/json' &&
|
|
86
|
-
params[:organization] == @
|
|
84
|
+
params[:organization] == @organization
|
|
87
85
|
end
|
|
88
86
|
.returns(mock_response)
|
|
89
87
|
|
|
@@ -116,37 +114,94 @@ class VmaasReposcanSyncTest < ActiveSupport::TestCase
|
|
|
116
114
|
.stubs(:execute_cloud_request)
|
|
117
115
|
.raises(exception)
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
121
|
-
end
|
|
117
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
122
118
|
|
|
123
|
-
assert_equal 'VMaaS reposcan sync failed: 500 - Server Error',
|
|
119
|
+
assert_equal 'VMaaS reposcan sync failed: 500 - Server Error', task.output[:message]
|
|
124
120
|
end
|
|
125
121
|
|
|
126
122
|
test 'run sets error message in task output for StandardError exception' do
|
|
123
|
+
mock_logger = mock('logger')
|
|
124
|
+
mock_logger.expects(:error).with('Error triggering VMaaS reposcan sync: Network timeout')
|
|
125
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
|
|
126
|
+
|
|
127
127
|
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
|
128
128
|
.stubs(:execute_cloud_request)
|
|
129
129
|
.raises(StandardError.new('Network timeout'))
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
133
|
-
end
|
|
131
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
134
132
|
|
|
135
|
-
|
|
136
|
-
assert_match(/Error triggering VMaaS reposcan sync: Network timeout, response: /,
|
|
137
|
-
error.task.main_action.output[:message])
|
|
133
|
+
assert_equal 'Error triggering VMaaS reposcan sync: Network timeout', task.output[:message]
|
|
138
134
|
end
|
|
139
135
|
|
|
140
|
-
test 'run logs and
|
|
141
|
-
error_response = mock('error_response'
|
|
136
|
+
test 'run logs and handles error response without raising' do
|
|
137
|
+
error_response = mock('error_response')
|
|
138
|
+
error_response.stubs(:code).returns(500)
|
|
139
|
+
error_response.stubs(:body).returns('error')
|
|
142
140
|
exception = RestClient::ExceptionWithResponse.new(error_response)
|
|
143
141
|
|
|
144
142
|
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
|
145
143
|
.stubs(:execute_cloud_request)
|
|
146
144
|
.raises(exception)
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
146
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
147
|
+
|
|
148
|
+
assert_equal 'VMaaS reposcan sync failed: 500 - error', task.output[:message]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
test 'run handles 429 error with warning log level' do
|
|
152
|
+
error_response = mock('error_response')
|
|
153
|
+
error_response.stubs(:code).returns(429)
|
|
154
|
+
error_response.stubs(:body).returns('{"msg": "Another task already in progress"}')
|
|
155
|
+
exception = RestClient::ExceptionWithResponse.new(error_response)
|
|
156
|
+
|
|
157
|
+
mock_logger = mock('logger')
|
|
158
|
+
mock_logger.expects(:warn).with('VMaaS reposcan sync skipped: another sync already in progress (429)')
|
|
159
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
|
|
160
|
+
|
|
161
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
|
162
|
+
.stubs(:execute_cloud_request)
|
|
163
|
+
.raises(exception)
|
|
164
|
+
|
|
165
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
166
|
+
|
|
167
|
+
assert_equal 'VMaaS reposcan sync skipped: another sync already in progress (429)',
|
|
168
|
+
task.output[:message]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
test 'run handles non-429 errors with error log level' do
|
|
172
|
+
error_response = mock('error_response')
|
|
173
|
+
error_response.stubs(:code).returns(500)
|
|
174
|
+
error_response.stubs(:body).returns('Internal Server Error')
|
|
175
|
+
exception = RestClient::ExceptionWithResponse.new(error_response)
|
|
176
|
+
|
|
177
|
+
mock_logger = mock('logger')
|
|
178
|
+
mock_logger.expects(:error).with('VMaaS reposcan sync failed: 500 - Internal Server Error')
|
|
179
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
|
|
180
|
+
|
|
181
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
|
182
|
+
.stubs(:execute_cloud_request)
|
|
183
|
+
.raises(exception)
|
|
184
|
+
|
|
185
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
186
|
+
|
|
187
|
+
assert_equal 'VMaaS reposcan sync failed: 500 - Internal Server Error',
|
|
188
|
+
task.output[:message]
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
test 'run handles RestClient::ExceptionWithResponse with nil response' do
|
|
192
|
+
exception = RestClient::ExceptionWithResponse.new(nil)
|
|
193
|
+
|
|
194
|
+
mock_logger = mock('logger')
|
|
195
|
+
mock_logger.expects(:error).with('VMaaS reposcan sync failed: - ')
|
|
196
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
|
|
197
|
+
|
|
198
|
+
InsightsCloud::Async::VmaasReposcanSync.any_instance
|
|
199
|
+
.stubs(:execute_cloud_request)
|
|
200
|
+
.raises(exception)
|
|
201
|
+
|
|
202
|
+
task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
|
|
203
|
+
|
|
204
|
+
refute_nil task.output[:message]
|
|
205
|
+
assert_equal 'VMaaS reposcan sync failed: - ', task.output[:message]
|
|
151
206
|
end
|
|
152
207
|
end
|