Merge "Test multiple boot interfaces as part of one CI job"
diff --git a/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py b/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py
index 04e2e5a..a66d7d6 100644
--- a/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py
+++ b/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py
@@ -545,6 +545,21 @@
     # The node driver to use in the test
     driver = None
 
+    # If we do not require an explicit driver to be set as a base for
+    # the test. This is useful for tests where we perform a vertical
+    # slice of drivers to test as opposed to focusing all testing
+    # around the driver itself. This allows for us to verify the
+    # driver interfaces align with the established contracts,
+    # and allows the same test to use ipmi, redfish, or some other
+    # known driver to work.
+    use_available_driver = None
+
+    # If we don't require an explicit driver, then what drivers *can* we
+    # operate with. In essence, this exists to prevent the test from failing
+    # on 3rd party drivers, and vendor specific driers which do not support
+    # the sort of itnerfaces we may be trying to test by default.
+    valid_driver_list = []
+
     # The bios interface to use by the HW type. The bios interface of the
     # node used in the test will be set to this value. If set to None, the
     # node will retain its existing bios_interface value (which may have been
@@ -601,7 +616,8 @@
     @classmethod
     def skip_checks(cls):
         super(BaremetalStandaloneScenarioTest, cls).skip_checks()
-        if (cls.driver not in CONF.baremetal.enabled_drivers
+        if (not cls.use_available_driver
+            and cls.driver not in CONF.baremetal.enabled_drivers
                 + CONF.baremetal.enabled_hardware_types):
             raise cls.skipException(
                 'The driver: %(driver)s used in test is not in the list of '
@@ -716,6 +732,12 @@
 
         # just get an available node
         cls.node = cls.get_and_reserve_node()
+        if (cls.use_available_driver
+                and not cls.driver
+                and cls.node['driver'] in cls.valid_driver_list):
+            # If we're attempting to re-use the existing driver, then
+            # lets save a value for update_node_driver to work with.
+            cls.driver = cls.node['driver']
         cls.update_node_driver(cls.node['uuid'], cls.driver, **boot_kwargs)
 
     @classmethod
diff --git a/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_basic_ops.py b/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_basic_ops.py
index fcb3746..453ccfa 100644
--- a/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_basic_ops.py
+++ b/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_basic_ops.py
@@ -700,3 +700,88 @@
             kernel_ref=CONF.baremetal.anaconda_kernel_ref,
             ramdisk_ref=CONF.baremetal.anaconda_initial_ramdisk_ref,
             stage2_ref=CONF.baremetal.anaconda_stage2_ramdisk_ref)
+
+
+class BaremetalChangeBaseBootInterface(
+        bsm.BaremetalStandaloneScenarioTest):
+
+    # NOTE(TheJulia): The resource setup class *already* auto-sets the
+    # requested boot interface. We just never tried to articulate
+    # this sort of configuration before this class.
+    # The goal: Test as many boot interfaces to ensure they are functional
+    # under the base context
+
+    api_microversion = '1.31'  # to set the boot_interface
+    driver = None
+    # This is intentionally meant to be a relatively light weight test,
+    # but one that covers the common cases, i.e. direct is most appropriate
+    # here. Ramdisk/anaconda/ansible and friends are all more specific
+    # cased.
+    deploy_interface = 'direct'
+    image_ref = CONF.baremetal.whole_disk_image_url
+    image_checksum = CONF.baremetal.whole_disk_image_checksum
+    wholedisk_image = True
+
+    # This is a special override which allows us to just use the base
+    # driver interface defined on the node, and not have to special case it
+    # and focus on the "driver".
+    use_available_driver = True
+
+    # List of valid drivers which these tests *can* attempt to utilize.
+    # Generally these should be the most commom, stock, upstream drivers.
+    valid_driver_list = ['ipmi', 'redfish']
+
+    # Bypass secondary attribute presence check as these tests don't require
+    # the driver to be set.
+    mandatory_attr = ['image_ref']
+
+
+class BaremetalPXEBootTestClass(BaremetalChangeBaseBootInterface):
+
+    boot_interface = 'pxe'
+
+    @decorators.idempotent_id('62c12d2c-8c9f-4526-b9ab-b9cd63e0ea8a')
+    @utils.services('network')
+    def test_ip_access_to_server(self):
+        self.boot_and_verify_node()
+
+
+class BaremetalIPXEBootTestClass(BaremetalChangeBaseBootInterface):
+
+    boot_interface = 'ipxe'
+
+    @decorators.idempotent_id('113acd0a-9872-4631-b3ee-54da7e3bb262')
+    @utils.services('network')
+    def test_ip_access_to_server(self):
+        self.boot_and_verify_node()
+
+
+class BaremetalHTTPBootTestClass(BaremetalChangeBaseBootInterface):
+
+    boot_interface = 'http'
+
+    @decorators.idempotent_id('782c43db-77a1-4a3a-b46e-0ce9cbb7fba5')
+    @utils.services('network')
+    def test_ip_access_to_server(self):
+        self.boot_and_verify_node()
+
+
+class BaremetalHttpIPXEBootTestClass(BaremetalChangeBaseBootInterface):
+
+    boot_interface = 'http-ipxe'
+
+    @decorators.idempotent_id('45400d8e-55a5-4ba6-81f5-935a4183ed90')
+    @utils.services('network')
+    def test_ip_access_to_server(self):
+        self.boot_and_verify_node()
+
+
+class BaremetalRedfishVmediaBootTestClass(BaremetalChangeBaseBootInterface):
+
+    boot_interface = 'redfish-virtual-media'
+    driver = 'redfish'
+
+    @decorators.idempotent_id('10535270-27e5-4616-9013-9507b1960dfa')
+    @utils.services('network')
+    def test_ip_access_to_server(self):
+        self.boot_and_verify_node()