#!/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()