Blob Blame History Raw
#!/usr/bin/python3

# checkpoint:
# 1. create supported image

import os
import unittest
import composerlib
import testlib


@testlib.nondestructive
@testlib.timeout(2400)
class TestImage(composerlib.ComposerCase):

    def testBasic(self):
        b = self.browser

        self.login_and_go("/composer", authorized=True)
        b.wait_present("#main")

        # create image wizard (no upload support)
        b.click("li[data-blueprint=httpd-server] #create-image-button")
        b.wait_text("#create-image-upload-wizard #blueprint-name", "httpd-server")
        # check ? (Process length help) button
        b.click("button[aria-label='Process length help']")
        b.wait_attr("button[aria-label='Process length help']", "aria-expanded", "true")
        b.wait_text(".pf-c-popover__body", "This process can take a while. "
                    "Images are built in the order they are started.")
        b.click(".pf-c-popover__content button")
        b.wait_attr("button[aria-label='Process length help']", "aria-expanded", "false")
        # check ? (image size help) button
        b.click("button[aria-label='Image size help']")
        b.wait_attr("button[aria-label='Image size help']", "aria-expanded", "true")
        b.wait_text(".pf-c-popover__body",
                    "Set the size that you want the image to be when instantiated. The total "
                    "package size and target destination of your image should be considered when "
                    "setting the image size.")
        b.click(".pf-c-popover__content button")
        b.wait_attr("button[aria-label='Image size help']", "aria-expanded", "false")
        # check non upload image action (Create only)
        # group actions for select from dropdown menu
        b.wait_visible("#image-type")
        test_selector = "#image-type option[value='qcow2']"
        b.wait_present(test_selector)
        value_id = b.attr(test_selector, "value")
        b.set_val("#image-type", value_id)
        b.wait_val("#image-type", value_id)
        # groups action done
        b.wait_text("#continue-button", "Create")
        # close wizard by clicking X button
        b.click(".pf-c-wizard__close")
        b.wait_not_present("#create-image-upload-wizard")

        # go to wizard again (upload support)
        b.click("li[data-blueprint=httpd-server] #create-image-button")
        # check upload image action (wizard)
        # group actions for select from dropdown menu
        b.wait_visible("#image-type")
        test_selector = "#image-type option[value='ami']"
        b.wait_present(test_selector)
        value_id = b.attr(test_selector, "value")
        b.set_val("#image-type", value_id)
        b.wait_val("#image-type", value_id)
        # groups action done
        # still keep Create if upload image not selected
        b.wait_text("#continue-button", "Create")
        # default size = 6GB for ami image
        b.wait_val("#create-image-size", 6)
        # change to 1GB = error
        b.focus("#create-image-size")
        # delete 6 and input 1
        b.key_press("\b")
        b.key_press("1")
        b.wait_attr("#create-image-upload-wizard button:contains('Create')", "disabled", "")
        b.wait_attr_contains("#help-text-simple-form-name-helper", "class", "pf-m-error")
        # delete 1 and input 2001
        b.key_press("\b")
        b.key_press("2001")
        b.wait_in_text("#help-text-simple-form-name-helper",
                       "The size specified is large. We recommend that you check whether your "
                       "target destination has any restrictions on image size.")
        # delete 2001 and input 6
        b.key_press("\b\b\b\b")
        b.key_press("6")
        # b.set_val("#create-image-size", 6)
        # change to Next if upload image selected
        b.click("#aws-checkbox")
        b.click("button:contains('Next')")
        # Back button is click-able and back to last page
        b.click("button:contains('Back')")
        b.wait_text("#create-image-upload-wizard #blueprint-name", "httpd-server")
        # go to each setion by clicking link directly
        b.click("a:contains('Authentication')")
        b.click("a:contains('Destination')")
        b.click("a:contains('Review')")
        b.wait_in_text(".pf-c-alert__title",
                       "There are one or more fields that require your attention.")
        b.wait_attr("#continue-button", "disabled", "")
        b.click("button:contains('Cancel')")
        b.wait_not_present("#create-image-upload-wizard")

        # collect code coverage result
        self.check_coverage()

    def testOpenStack(self):
        b = self.browser
        m = self.machine

        self.login_and_go("/composer", authorized=True)
        b.wait_present("#main")

        # create image wizard
        b.click("li[data-blueprint=httpd-server] #create-image-button")
        b.wait_text("#create-image-upload-wizard #blueprint-name", "httpd-server")
        # group actions for select from dropdown menu
        b.wait_visible("#image-type")
        test_selector = "#image-type option[value='openstack']"
        b.wait_present(test_selector)
        value_id = b.attr(test_selector, "value")
        b.set_val("#image-type", value_id)
        b.wait_val("#image-type", value_id)
        # group actions end
        b.focus("#create-image-size")
        # delete 2 and input 4
        b.key_press("\b")
        b.key_press("4")
        b.click("#continue-button")
        b.wait_not_present("#create-image-upload-wizard")

        # toast notification
        b.wait_present("#cmpsr-toast-imageWaiting .pficon-info")
        b.click("#cmpsr-toast-imageWaiting .pficon-close")
        b.wait_not_present("#cmpsr-toast-imageWaiting .pficon-info")

        # got to images tab
        b.click("#httpd-server-name")
        # correct image name and type
        with b.wait_timeout(300):
            b.click("#blueprint-tabs-tab-images")
            b.wait_present("ul[data-list=images]")
        # get uuid as part of css selector
        uuid = m.execute("""
            composer-cli compose list | grep httpd-server | awk '{print $1}' | head -1
            """).rstrip()
        selector = "{}-compose-name".format(uuid)

        # NOTE work around a bug in osbuild-composer-11, which got the
        # capitalization wrong. This can be changed to `openstack` once we
        # depend on a newer version of osbuild-composer.
        image_type = b.attr("li[aria-labelledby={}] [data-image-type]".format(selector),
                            "data-image-type")
        self.assertEqual(image_type.lower(), "openstack")

        # image building needs more time
        with b.wait_timeout(1800):
            b.wait_text("li[aria-labelledby={}] [data-status=true]".format(selector),
                        "Image build complete")
        # image size should be 4GB
        b.wait_in_text("li[aria-labelledby={}] ".format(selector), "4 GB")
        # get image size from backend
        image_size = m.execute(
            "composer-cli compose info {} | head -1 | awk '{{print $6}}'".format(uuid)
        ).rstrip()
        self.assertEqual(int(image_size), 4 * 1024 * 1024 * 1024)
        # log should contains rpm, hostname, users stages and tar assembler
        b.click("button:contains('Logs')")
        b.wait_in_text("#{}-logs".format(uuid), "Stage org.osbuild.rpm")
        b.wait_in_text("#{}-logs".format(uuid), "Stage: org.osbuild.hostname")
        b.wait_in_text("#{}-logs".format(uuid), "Stage: org.osbuild.users")
        b.wait_in_text("#{}-logs".format(uuid), "Assembler org.osbuild.qemu")
        # close logs
        b.click("button:contains('Logs')")

        # download image
        b.click("#{}-actions".format(uuid))
        b.click("a:contains('Download')")

        # delete image cancel first always
        b.click("#{}-actions".format(uuid))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "true")
        b.click("li[aria-labelledby={}] a:contains('Delete')".format(selector))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "false")
        b.click("#cmpsr-modal-delete button:contains('Cancel')")
        b.wait_not_present("#cmpsr-modal-delete")
        # delete here
        b.click("#{}-actions".format(uuid))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "true")
        b.click("li[aria-labelledby={}] a:contains('Delete')".format(selector))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "false")
        b.click("#cmpsr-modal-delete button:contains('Delete Image')")
        b.wait_not_present("#{}".format(selector))

        # collect code coverage result
        self.check_coverage()

    @unittest.skipIf(os.environ.get("TEST_OS") == "fedora-31", "Does not support ostree image")
    def testOSTree(self):
        b = self.browser
        m = self.machine

        if (os.environ.get("TEST_OS") == "fedora-32"):
            image_type_ostree = "fedora-iot-commit"
        elif (os.environ.get("TEST_OS") == "rhel-8-3"):
            image_type_ostree = "rhel-edge-commit"

        self.login_and_go("/composer", authorized=True)
        b.wait_present("#main")

        # create image wizard
        b.click("li[data-blueprint=httpd-server] #create-image-button")
        b.wait_text("#create-image-upload-wizard #blueprint-name", "httpd-server")
        # group actions for select from dropdown menu
        b.wait_visible("#image-type")
        test_selector = "#image-type option[value='{image_type}']".format(
            image_type=image_type_ostree)
        b.wait_present(test_selector)
        value_id = b.attr(test_selector, "value")
        b.set_val("#image-type", value_id)
        b.wait_val("#image-type", value_id)
        b.click("#continue-button")
        b.wait_not_present("#create-image-upload-wizard")
        # toast notification
        b.wait_present("#cmpsr-toast-imageWaiting .pficon-info")
        b.click("#cmpsr-toast-imageWaiting .pficon-close")
        b.wait_not_present("#cmpsr-toast-imageWaiting .pficon-info")

        # got to images tab
        b.click("#httpd-server-name")
        # correct image name and type
        with b.wait_timeout(300):
            b.click("#blueprint-tabs-tab-images")
            b.wait_present("ul[data-list=images]")
        # get uuid as part of css selector
        uuid = m.execute("""
            composer-cli compose list | grep httpd-server | awk '{print $1}' | head -1
            """).rstrip()
        selector = "{}-compose-name".format(uuid)

        image_type = b.attr("li[aria-labelledby={}] [data-image-type]".format(selector),
                            "data-image-type")
        self.assertEqual(image_type, image_type_ostree)

        # image building needs more time
        with b.wait_timeout(1800):
            b.wait_text("li[aria-labelledby={}] [data-status=true]".format(selector),
                        "Image build complete")
        # log should contains rpm, hostname, users stages and tar assembler
        b.click("button:contains('Logs')")
        b.wait_in_text("#{}-logs".format(uuid), "Stage org.osbuild.rpm")
        b.wait_in_text("#{}-logs".format(uuid), "Stage: org.osbuild.rpm-ostree")
        b.wait_in_text("#{}-logs".format(uuid), "Assembler org.osbuild.ostree.commit")
        # close logs
        b.click("button:contains('Logs')")

        # download image
        b.click("#{}-actions".format(uuid))
        b.click("a:contains('Download')")

        # delete image cancel first always
        b.click("#{}-actions".format(uuid))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "true")
        b.click("li[aria-labelledby={}] a:contains('Delete')".format(selector))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "false")
        b.click("#cmpsr-modal-delete button:contains('Cancel')")
        b.wait_not_present("#cmpsr-modal-delete")
        # delete here
        b.click("#{}-actions".format(uuid))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "true")
        b.click("li[aria-labelledby={}] a:contains('Delete')".format(selector))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "false")
        b.click("#cmpsr-modal-delete button:contains('Delete Image')")
        b.wait_not_present("#{}".format(selector))
        self.allow_journal_messages(".*avc:  denied.*",
                                    ".*audit: .*seresult=denied .*")
        # collect code coverage result
        self.check_coverage()

    def testCancel(self):
        b = self.browser
        m = self.machine

        self.login_and_go("/composer", authorized=True)
        b.wait_present("#main")

        # create image wizard
        b.click("li[data-blueprint=httpd-server] #create-image-button")
        b.wait_text("#create-image-upload-wizard #blueprint-name", "httpd-server")
        # group actions for select from dropdown menu
        b.wait_visible("#image-type")
        test_selector = "#image-type option[value='openstack']"
        b.wait_present(test_selector)
        value_id = b.attr(test_selector, "value")
        b.set_val("#image-type", value_id)
        b.wait_val("#image-type", value_id)
        # group actions end
        b.click("#continue-button")
        b.wait_not_present("#create-image-upload-wizard")

        # toast notification
        b.wait_present("#cmpsr-toast-imageWaiting .pficon-info")
        b.click("#cmpsr-toast-imageWaiting .pficon-close")
        b.wait_not_present("#cmpsr-toast-imageWaiting .pficon-info")

        # got to images tab
        b.click("#httpd-server-name")
        # correct image name and type
        with b.wait_timeout(300):
            b.click("#blueprint-tabs-tab-images")
            b.wait_present("ul[data-list=images]")
        # get uuid as part of css selector
        uuid = m.execute("""
            composer-cli compose list | grep httpd-server | awk '{print $1}' | head -1
            """).rstrip()
        selector = "{}-compose-name".format(uuid)
        # stop image build
        b.click("#{}-actions".format(uuid))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "true")
        b.click("li[aria-labelledby={}] a:contains('Stop')".format(selector))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "false")
        b.click("#cmpsr-modal-delete button:contains('Stop Build')")
        b.wait_not_present("#cmpsr-modal-delete")
        # delete canceled image build
        b.click("#{}-actions".format(uuid))
        b.wait_attr("#{}-actions".format(uuid), "aria-expanded", "true")
        b.click("li[aria-labelledby={}] a:contains('Remove')".format(selector))
        b.wait_not_present("#{}".format(selector))

        # collect code coverage result
        self.check_coverage()


if __name__ == '__main__':
    testlib.test_main()