Repository: SatelliteQE/robottelo
Pull request #18377: Convert Puppet scenario to new format
Author: login: synkd
Labels: name: Upgrades
description: Issues and PRs related to upgrades
name: CherryPick
description: PR needs CherryPick to previous branches
name: AutoMerge_Cherry_Picked
description: The cherrypicked PRs of master PR would be automerged if all checks passing
name: 6.15.z
name: 6.16.z
name: 6.17.z
Created: 2025-05-06T20:49:18Z | Merged: 2025-05-20T17:34:19Z

This PR converts the Puppet upgrade scenario to use the shared resource framework. It adds a pre-upgrade fixture to ensure that the test can be run concurrently with other upgrade scenario modules that require Puppet-enabled Satellites and adds fixtures for the Satellite, Capsule, and a Sat/Cap integration fixture that ensures Puppet is enabled on the Capsule after it has already been set up for operation with the Satellite.


Diff:
diff --git a/tests/new_upgrades/conftest.py b/tests/new_upgrades/conftest.py
index 9a40cb1bbc5..7754b6b80d1 100644
--- a/tests/new_upgrades/conftest.py
+++ b/tests/new_upgrades/conftest.py
@@ -230,3 +230,72 @@ def capsule_upgrade_integrated_sat_cap(
     setup_data.capsule = capsule_upgrade_shared_capsule
     setup_data.cap_smart_proxy = cap_smart_proxy
     return setup_data
+
+
+@pytest.fixture
+def puppet_upgrade_shared_satellite():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    sat_instance = shared_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_enable_puppet",
+            action=sat_instance.enable_puppet_satellite,
+            action_is_recoverable=True,
+        ) as enable_puppet,
+        SharedResource(
+            "puppet_upgrade_satellite",
+            shared_checkin,
+            sat_instance=sat_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        enable_puppet.ready()
+        yield sat_instance
+        test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_capsule():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    cap_instance = shared_cap_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_capsule",
+            shared_checkin,
+            sat_instance=cap_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        yield cap_instance
+        test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_integrated_sat_cap(
+    puppet_upgrade_shared_satellite, puppet_upgrade_shared_capsule
+):
+    """Return a Satellite and Capsule that have been set up"""
+    setup_data = Box(
+        {
+            "satellite": None,
+            "capsule": None,
+        }
+    )
+    with (
+        SharedResource(
+            "capsule_setup",
+            action=puppet_upgrade_shared_capsule.capsule_setup,
+            sat_host=puppet_upgrade_shared_satellite,
+        ) as cap_setup,
+        SharedResource(
+            "puppet_upgrade_enable_puppet_capsule",
+            action=puppet_upgrade_shared_capsule.enable_puppet_capsule,
+            action_is_recoverable=True,
+            satellite=puppet_upgrade_shared_satellite,
+        ) as enable_puppet,
+    ):
+        cap_setup.ready()
+        enable_puppet.ready()
+    setup_data.satellite = puppet_upgrade_shared_satellite
+    setup_data.capsule = puppet_upgrade_shared_capsule
+    return setup_data
diff --git a/tests/new_upgrades/test_puppet.py b/tests/new_upgrades/test_puppet.py
new file mode 100644
index 00000000000..37683c5eb5c
--- /dev/null
+++ b/tests/new_upgrades/test_puppet.py
@@ -0,0 +1,95 @@
+"""Test for Remote Execution related Upgrade Scenario's
+
+:Requirement: UpgradedSatellite
+
+:CaseAutomation: Automated
+
+:CaseComponent: Puppet
+
+:Team: Rocket
+
+:CaseImportance: Medium
+
+"""
+
+from box import Box
+import pytest
+
+from robottelo.config import settings
+from robottelo.utils.shared_resource import SharedResource
+
+
+@pytest.fixture
+def puppet_upgrade_setup(puppet_upgrade_integrated_sat_cap, upgrade_action):
+    satellite = puppet_upgrade_integrated_sat_cap.satellite
+    capsule = puppet_upgrade_integrated_sat_cap.capsule
+    with (
+        SharedResource(satellite.hostname, upgrade_action, target_sat=satellite) as sat_upgrade,
+        SharedResource(capsule.hostname, upgrade_action, target_sat=capsule) as cap_upgrade,
+    ):
+        test_data = Box(
+            {
+                'satellite': satellite,
+                'capsule': capsule,
+            }
+        )
+        sat_upgrade.ready()
+        satellite._swap_nailgun(f'{settings.UPGRADE.TO_VERSION}.z')
+        cap_upgrade.ready()
+        satellite._session = None
+        capsule._session = None
+        yield test_data
+
+
+@pytest.mark.puppet_upgrades
+def test_post_puppet_active(puppet_upgrade_setup):
+    """Test that puppet remains active after the upgrade on both,
+    Satellite and Capsule.
+
+    :id: postupgrade-6360e928-ba0f-41a7-9aaa-bea87cb6342d
+
+    :steps:
+        1. Check for capsule features.
+        2. Check for puppetserver status.
+
+    :expectedresults:
+        1. Puppet and Puppetca features are enabled.
+        2. Puppetserver is installed and runnning.
+
+    :parametrized: yes
+
+    """
+    satellite = puppet_upgrade_setup.satellite
+    capsule = puppet_upgrade_setup.capsule
+    for server in satellite, capsule:
+        result = server.get_features()
+        assert 'puppet' in result
+        assert 'puppetca' in result
+
+        assert server.execute('rpm -q puppetserver').status == 0
+
+        result = server.execute('systemctl status puppetserver')
+        assert 'active (running)' in result.stdout
+
+
+@pytest.mark.puppet_upgrades
+def test_post_puppet_reporting(puppet_upgrade_setup):
+    """Test that puppet is reporting to Satellite after the upgrade.
+
+    :id:   postupgrade-cdc4f6cc-23d8-4b4a-bd94-5c86b3072828
+
+    :steps:
+        1. Run puppet agent on the registered Capsule.
+        2. On Satellite, read puppet-originated Config reports for the Capsule host.
+
+    :expectedresults:
+        1. Puppet agent run succeeds.
+        2. At least one Config report exists (was created) for the Capsule.
+
+    """
+    satellite = puppet_upgrade_setup.satellite
+    capsule = puppet_upgrade_setup.capsule
+    assert capsule.execute('puppet agent -t').status == 0
+
+    result = satellite.cli.ConfigReport.list({'search': f'host={capsule.hostname},origin=Puppet'})
+    assert len(result)


Reviews:
user: login: shubhamsg199
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T15:56:43Z
user: login: shubhamsg199
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T15:57:11Z
user: login: synkd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T18:27:11Z
user: login: shubhamsg199
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T18:39:03Z
user: login: Gauravtalreja1
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T14:07:13Z
user: login: synkd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:11:56Z
user: login: Gauravtalreja1
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T17:33:39Z
user: login: Gauravtalreja1
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-20T17:34:13Z

Review comments:
diff_hunk: @@ -0,0 +1,97 @@
+"""Test for Remote Execution related Upgrade Scenario's
+
+:Requirement: UpgradedSatellite
+
+:CaseAutomation: Automated
+
+:CaseComponent: Puppet
+
+:Team: Rocket
+
+:CaseImportance: Medium
+
+"""
+
+from box import Box
+import pytest
+
+from robottelo.config import settings
+from robottelo.utils.shared_resource import SharedResource
+
+
+@pytest.fixture
+def puppet_upgrade_setup(puppet_upgrade_integrated_sat_cap, upgrade_action):
+    satellite = puppet_upgrade_integrated_sat_cap.satellite
+    capsule = puppet_upgrade_integrated_sat_cap.capsule
+    with (
+        SharedResource(satellite.hostname, upgrade_action, target_sat=satellite) as sat_upgrade,
+        SharedResource(capsule.hostname, upgrade_action, target_sat=capsule) as cap_upgrade,
+    ):
+        test_data = Box(
+            {
+                'satellite': satellite,
+                'capsule': capsule,
+            }
+        )
+        sat_upgrade.ready()
+        satellite._swap_nailgun(f'{settings.UPGRADE.TO_VERSION}.z')
+        cap_upgrade.ready()
+        satellite._session = None
+        capsule._session = None
+        yield test_data
+
+
+@pytest.mark.capsule_upgrades
path: tests/new_upgrades/test_puppet.py
user: login: shubhamsg199
body: Should we also use `pytest.mark.puppet_upgrades` marker for the test ?
created_at: 2025-05-13T15:55:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,97 @@
+"""Test for Remote Execution related Upgrade Scenario's
+
+:Requirement: UpgradedSatellite
+
+:CaseAutomation: Automated
+
+:CaseComponent: Puppet
+
+:Team: Rocket
+
+:CaseImportance: Medium
+
+"""
+
+from box import Box
+import pytest
+
+from robottelo.config import settings
+from robottelo.utils.shared_resource import SharedResource
+
+
+@pytest.fixture
+def puppet_upgrade_setup(puppet_upgrade_integrated_sat_cap, upgrade_action):
+    satellite = puppet_upgrade_integrated_sat_cap.satellite
+    capsule = puppet_upgrade_integrated_sat_cap.capsule
+    with (
+        SharedResource(satellite.hostname, upgrade_action, target_sat=satellite) as sat_upgrade,
+        SharedResource(capsule.hostname, upgrade_action, target_sat=capsule) as cap_upgrade,
+    ):
+        test_data = Box(
+            {
+                'satellite': satellite,
+                'capsule': capsule,
+            }
+        )
+        sat_upgrade.ready()
+        satellite._swap_nailgun(f'{settings.UPGRADE.TO_VERSION}.z')
+        cap_upgrade.ready()
+        satellite._session = None
+        capsule._session = None
+        yield test_data
+
+
+@pytest.mark.capsule_upgrades
+def test_post_puppet_active(puppet_upgrade_setup):
+    """Test that puppet remains active after the upgrade on both,
+    Satellite and Capsule.
+
+    :id: postupgrade-6360e928-ba0f-41a7-9aaa-bea87cb6342d
+
+    :steps:
+        1. Check for capsule features.
+        2. Check for puppetserver status.
+
+    :expectedresults:
+        1. Puppet and Puppetca features are enabled.
+        2. Puppetserver is installed and runnning.
+
+    :parametrized: yes
+
+    """
+    satellite = puppet_upgrade_setup.satellite
+    capsule = puppet_upgrade_setup.capsule
+    for server in satellite, capsule:
+        result = server.get_features()
+        assert 'puppet' in result
+        assert 'puppetca' in result
+
+        result = server.execute('rpm -q puppetserver')
+        assert result.status == 0
+
+        result = server.execute('systemctl status puppetserver')
+        assert 'active (running)' in result.stdout
+
+
+@pytest.mark.post_upgrade
+def test_post_puppet_reporting(puppet_upgrade_setup):
path: tests/new_upgrades/test_puppet.py
user: login: shubhamsg199
body: Same as https://github.com/SatelliteQE/robottelo/pull/18377/files#r2087162423
created_at: 2025-05-13T15:57:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,97 @@
+"""Test for Remote Execution related Upgrade Scenario's
+
+:Requirement: UpgradedSatellite
+
+:CaseAutomation: Automated
+
+:CaseComponent: Puppet
+
+:Team: Rocket
+
+:CaseImportance: Medium
+
+"""
+
+from box import Box
+import pytest
+
+from robottelo.config import settings
+from robottelo.utils.shared_resource import SharedResource
+
+
+@pytest.fixture
+def puppet_upgrade_setup(puppet_upgrade_integrated_sat_cap, upgrade_action):
+    satellite = puppet_upgrade_integrated_sat_cap.satellite
+    capsule = puppet_upgrade_integrated_sat_cap.capsule
+    with (
+        SharedResource(satellite.hostname, upgrade_action, target_sat=satellite) as sat_upgrade,
+        SharedResource(capsule.hostname, upgrade_action, target_sat=capsule) as cap_upgrade,
+    ):
+        test_data = Box(
+            {
+                'satellite': satellite,
+                'capsule': capsule,
+            }
+        )
+        sat_upgrade.ready()
+        satellite._swap_nailgun(f'{settings.UPGRADE.TO_VERSION}.z')
+        cap_upgrade.ready()
+        satellite._session = None
+        capsule._session = None
+        yield test_data
+
+
+@pytest.mark.capsule_upgrades
path: tests/new_upgrades/test_puppet.py
user: login: synkd
body: Good catch, yes. I'll make the change.

created_at: 2025-05-13T18:27:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -133,3 +154,72 @@ def fdi_upgrade_shared_satellite():
     ) as test_duration:
         yield sat_instance
         test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_satellite():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    sat_instance = shared_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_enable_puppet",
+            action=sat_instance.enable_puppet_satellite,
+            action_is_recoverable=True,
+        ) as enable_puppet,
+        SharedResource(
+            "puppet_upgrade_tests_satellite",
+            shared_checkin,
+            sat_instance=sat_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        enable_puppet.ready()
+        yield sat_instance
+        test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_capsule():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    cap_instance = shared_cap_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_tests_capsule",
+            shared_checkin,
+            sat_instance=cap_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        yield cap_instance
+        test_duration.ready()
path: tests/new_upgrades/conftest.py
user: login: Gauravtalreja1
body: I think it would be better to use the same fixture for cap integration as well similar to satellite, so is that possible to use the fixture to deploy, capsule_setup and then finally enable puppet?
created_at: 2025-05-20T13:58:12Z
author_association: MEMBER
diff_hunk: @@ -133,3 +154,72 @@ def fdi_upgrade_shared_satellite():
     ) as test_duration:
         yield sat_instance
         test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_satellite():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    sat_instance = shared_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_enable_puppet",
+            action=sat_instance.enable_puppet_satellite,
+            action_is_recoverable=True,
+        ) as enable_puppet,
+        SharedResource(
+            "puppet_upgrade_tests_satellite",
path: tests/new_upgrades/conftest.py
user: login: Gauravtalreja1
body: Just a nitpick comment to rename this to make it more readable?
```suggestion
            "puppet_upgrade_satellite",
```
created_at: 2025-05-20T13:58:58Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,97 @@
+"""Test for Remote Execution related Upgrade Scenario's
+
+:Requirement: UpgradedSatellite
+
+:CaseAutomation: Automated
+
+:CaseComponent: Puppet
+
+:Team: Rocket
+
+:CaseImportance: Medium
+
+"""
+
+from box import Box
+import pytest
+
+from robottelo.config import settings
+from robottelo.utils.shared_resource import SharedResource
+
+
+@pytest.fixture
+def puppet_upgrade_setup(puppet_upgrade_integrated_sat_cap, upgrade_action):
+    satellite = puppet_upgrade_integrated_sat_cap.satellite
+    capsule = puppet_upgrade_integrated_sat_cap.capsule
+    with (
+        SharedResource(satellite.hostname, upgrade_action, target_sat=satellite) as sat_upgrade,
+        SharedResource(capsule.hostname, upgrade_action, target_sat=capsule) as cap_upgrade,
+    ):
+        test_data = Box(
+            {
+                'satellite': satellite,
+                'capsule': capsule,
+            }
+        )
+        sat_upgrade.ready()
+        satellite._swap_nailgun(f'{settings.UPGRADE.TO_VERSION}.z')
+        cap_upgrade.ready()
+        satellite._session = None
+        capsule._session = None
+        yield test_data
+
+
+@pytest.mark.puppet_upgrades
+def test_post_puppet_active(puppet_upgrade_setup):
+    """Test that puppet remains active after the upgrade on both,
+    Satellite and Capsule.
+
+    :id: postupgrade-6360e928-ba0f-41a7-9aaa-bea87cb6342d
+
+    :steps:
+        1. Check for capsule features.
+        2. Check for puppetserver status.
+
+    :expectedresults:
+        1. Puppet and Puppetca features are enabled.
+        2. Puppetserver is installed and runnning.
+
+    :parametrized: yes
+
+    """
+    satellite = puppet_upgrade_setup.satellite
+    capsule = puppet_upgrade_setup.capsule
+    for server in satellite, capsule:
+        result = server.get_features()
+        assert 'puppet' in result
+        assert 'puppetca' in result
+
+        result = server.execute('rpm -q puppetserver')
+        assert result.status == 0
path: tests/new_upgrades/test_puppet.py
user: login: Gauravtalreja1
body: ```suggestion
        assert server.execute('rpm -q puppetserver').status == 0
```
created_at: 2025-05-20T14:03:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,97 @@
+"""Test for Remote Execution related Upgrade Scenario's
+
+:Requirement: UpgradedSatellite
+
+:CaseAutomation: Automated
+
+:CaseComponent: Puppet
+
+:Team: Rocket
+
+:CaseImportance: Medium
+
+"""
+
+from box import Box
+import pytest
+
+from robottelo.config import settings
+from robottelo.utils.shared_resource import SharedResource
+
+
+@pytest.fixture
+def puppet_upgrade_setup(puppet_upgrade_integrated_sat_cap, upgrade_action):
+    satellite = puppet_upgrade_integrated_sat_cap.satellite
+    capsule = puppet_upgrade_integrated_sat_cap.capsule
+    with (
+        SharedResource(satellite.hostname, upgrade_action, target_sat=satellite) as sat_upgrade,
+        SharedResource(capsule.hostname, upgrade_action, target_sat=capsule) as cap_upgrade,
+    ):
+        test_data = Box(
+            {
+                'satellite': satellite,
+                'capsule': capsule,
+            }
+        )
+        sat_upgrade.ready()
+        satellite._swap_nailgun(f'{settings.UPGRADE.TO_VERSION}.z')
+        cap_upgrade.ready()
+        satellite._session = None
+        capsule._session = None
+        yield test_data
+
+
+@pytest.mark.puppet_upgrades
+def test_post_puppet_active(puppet_upgrade_setup):
+    """Test that puppet remains active after the upgrade on both,
+    Satellite and Capsule.
+
+    :id: postupgrade-6360e928-ba0f-41a7-9aaa-bea87cb6342d
+
+    :steps:
+        1. Check for capsule features.
+        2. Check for puppetserver status.
+
+    :expectedresults:
+        1. Puppet and Puppetca features are enabled.
+        2. Puppetserver is installed and runnning.
+
+    :parametrized: yes
+
+    """
+    satellite = puppet_upgrade_setup.satellite
+    capsule = puppet_upgrade_setup.capsule
+    for server in satellite, capsule:
+        result = server.get_features()
+        assert 'puppet' in result
+        assert 'puppetca' in result
+
+        result = server.execute('rpm -q puppetserver')
+        assert result.status == 0
+
+        result = server.execute('systemctl status puppetserver')
+        assert 'active (running)' in result.stdout
+
+
+@pytest.mark.puppet_upgrades
+def test_post_puppet_reporting(puppet_upgrade_setup):
+    """Test that puppet is reporting to Satellite after the upgrade.
+
+    :id:   postupgrade-cdc4f6cc-23d8-4b4a-bd94-5c86b3072828
+
+    :steps:
+        1. Run puppet agent on the registered Capsule.
+        2. On Satellite, read puppet-originated Config reports for the Capsule host.
+
+    :expectedresults:
+        1. Puppet agent run succeeds.
+        2. At least one Config report exists (was created) for the Capsule.
+
+    """
+    satellite = puppet_upgrade_setup.satellite
+    capsule = puppet_upgrade_setup.capsule
+    result = capsule.execute('puppet agent -t')
+    assert result.status == 0
path: tests/new_upgrades/test_puppet.py
user: login: Gauravtalreja1
body: ```suggestion
    assert capsule.execute('puppet agent -t').status == 0
```
created_at: 2025-05-20T14:06:06Z
author_association: MEMBER
diff_hunk: @@ -133,3 +154,72 @@ def fdi_upgrade_shared_satellite():
     ) as test_duration:
         yield sat_instance
         test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_satellite():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    sat_instance = shared_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_enable_puppet",
+            action=sat_instance.enable_puppet_satellite,
+            action_is_recoverable=True,
+        ) as enable_puppet,
+        SharedResource(
+            "puppet_upgrade_tests_satellite",
+            shared_checkin,
+            sat_instance=sat_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        enable_puppet.ready()
+        yield sat_instance
+        test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_capsule():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    cap_instance = shared_cap_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_tests_capsule",
+            shared_checkin,
+            sat_instance=cap_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        yield cap_instance
+        test_duration.ready()
path: tests/new_upgrades/conftest.py
user: login: synkd
body: This might be possible but would require some refactoring and retesting. I personally would prefer to maintain the current setup, in which we have 1) a fixture for managing the deployment of the Satellite VM; 2) a fixture for managing the deployment of the Capsule VM; 3) a fixture for managing the integration of the Satellite and the Capsule, which inherits both of the previous fixtures and is the fixture used by the upgrade scenario tests. This matches the pattern for non-Puppet Capsules as well, which was merged in #17696.

The first two fixtures will both `yield` the Satellite and Capsule VM, then start the checkin process when the tests have completed. The third fixture will `return` the Satellite and Capsule to the test. To perform the change you requested,  I believe we would need to nest the context manager that controls the  Capsule setup and Puppet enable steps inside the Capsule deployment context manager in the same fixture function. This strikes me as significantly less readable and may be trickier to debug.

So, while it would likely be possible to do this, I would argue for keeping the current design pattern.
        
created_at: 2025-05-20T17:11:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -133,3 +154,72 @@ def fdi_upgrade_shared_satellite():
     ) as test_duration:
         yield sat_instance
         test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_satellite():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    sat_instance = shared_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_enable_puppet",
+            action=sat_instance.enable_puppet_satellite,
+            action_is_recoverable=True,
+        ) as enable_puppet,
+        SharedResource(
+            "puppet_upgrade_tests_satellite",
+            shared_checkin,
+            sat_instance=sat_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        enable_puppet.ready()
+        yield sat_instance
+        test_duration.ready()
+
+
+@pytest.fixture
+def puppet_upgrade_shared_capsule():
+    """Mark tests using this fixture with pytest.mark.puppet_upgrades"""
+    cap_instance = shared_cap_checkout("puppet_upgrade")
+    with (
+        SharedResource(
+            "puppet_upgrade_tests_capsule",
+            shared_checkin,
+            sat_instance=cap_instance,
+            action_is_recoverable=True,
+        ) as test_duration,
+    ):
+        yield cap_instance
+        test_duration.ready()
path: tests/new_upgrades/conftest.py
user: login: Gauravtalreja1
body: Not a concern at all, this was just a non-blocking suggestion. I was considering whether some optimization could help here, but I agree the impact would be minimal. I'm also in favor of maintaining consistency with the other new_upgrades fixtures :)
created_at: 2025-05-20T17:33:39Z
author_association: MEMBER

PR comments:
user: login: synkd
created_at: 2025-05-06T20:52:05Z
body: trigger: test-robottelo
pytest: -n 2 tests/new_upgrades/test_puppet.py
env:
  ROBOTTELO_server__xdist_behavior: 'run-on-one'
author_association: CONTRIBUTOR
user: login: Satellite-QE
created_at: 2025-05-06T21:55:24Z
body: **PRT Result**
```
Build Number: 11303
Build Status: SUCCESS
PRT Comment: pytest -n 2 tests/new_upgrades/test_puppet.py --external-logging
Test Result : ================= 2 passed, 22 warnings in 3450.42s (0:57:30) ==================
```
author_association: COLLABORATOR
user: login: Satellite-QE
created_at: 2025-05-06T22:04:08Z
body: **PRT Result**
```
Build Number: 11304
Build Status: SUCCESS
PRT Comment: pytest -n 2 tests/new_upgrades/test_puppet.py --external-logging
Test Result : ================= 2 passed, 22 warnings in 3695.28s (1:01:35) ==================
```
author_association: COLLABORATOR
user: login: synkd
created_at: 2025-05-07T13:29:45Z
body: ```
trigger: test-robottelo
pytest: -n 2 tests/new_upgrades/test_puppet.py
env:
  ROBOTTELO_server__xdist_behavior: 'run-on-one'
```
author_association: CONTRIBUTOR
user: login: Satellite-QE
created_at: 2025-05-07T14:35:15Z
body: **PRT Result**
```
Build Number: 11315
Build Status: SUCCESS
PRT Comment: pytest -n 2 tests/new_upgrades/test_puppet.py --external-logging
Test Result : ================= 2 passed, 23 warnings in 3451.19s (0:57:31) ==================
```
author_association: COLLABORATOR