#!/usr/bin/python # -*- coding: utf-8 -*- # This file is part of Cockpit. # # Copyright (C) 2015 Red Hat, Inc. # # Cockpit is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # Cockpit is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Cockpit; If not, see . import parent from testlib import * import os import subprocess INSTALL_RPMS = [ "empty-1-0.noarch", "cockpit-ostree-wip-0.1.noarch", "cockpit-machines-99999-2.noarch", ] REPO_LOCATION = "/var/local-repo" CHECKOUT_LOCATION = "/var/local-tree" RPM_LOCATION = "/usr/share/rpm" KEY_ID = "95A8BA1754D0E95E2B3A98A7EE15015654780CBD" def get_os_name(m): if m.image == "rhel-atomic": return "rhel-atomic-host" elif 'continuous' in m.image: return 'centos-atomic-host' else: return "fedora-atomic" def ensure_remote_http_port (m, remote="local"): remote_spec = m.execute(["ostree", "remote", "show-url", remote]) if remote_spec.startswith("http"): parts = remote_spec.strip().split(":") port = parts[-1] else: m.execute(["ostree", "remote", "delete", remote]) m.execute(["ostree", "remote", "add", remote, "http://127.0.0.1:12345", "--no-gpg-verify"]) try: m.execute(["rpm-ostree reload"]) except subprocess.CalledProcessError: m.execute("systemctl restart rpm-ostreed") port = 12345 return port def start_trivial_httpd(m, remote="local", location=REPO_LOCATION): port = ensure_remote_http_port (m, remote) script = "cd {0}\nsetsid python -m SimpleHTTPServer {1} >/dev/null 2>&1 < /dev/null &\necho $!".format(location, port) result = m.execute(script=script, environment={"PYTHONUNBUFFERED" : "1"}) m.execute(["ostree", "summary", "--repo={}".format(location), "-u"]) m.wait_for_cockpit_running(port=port) return result.strip() def stop_trivial_httpd(m, pid): if pid: m.execute(["kill", pid]) def generate_new_commit(m, pkg_to_remove): # Make one change of each type to a new rpm tree branch = m.execute("ostree refs --repo={0}".format(REPO_LOCATION)) m.upload(["verify/files/{0}.rpm".format(k) for k in INSTALL_RPMS], "/home/admin/") # move /usr/etc to /etc, makes rpm installs easier rpm_etc = os.path.join(CHECKOUT_LOCATION, "etc") usr_etc = os.path.join(CHECKOUT_LOCATION, "usr", "etc") m.execute("mv {0} {1}".format(usr_etc, rpm_etc)) # Remove a package rpm_args = [CHECKOUT_LOCATION, RPM_LOCATION, pkg_to_remove] m.execute("rpm -e --root {0} --dbpath {1} {2}".format(*rpm_args)) # Install our dummy packages, dbonly rpm_args[-1] = ' '.join(["{0}.rpm".format(os.path.join("/home/admin", x)) \ for x in INSTALL_RPMS]) m.execute("rpm -U --oldpackage --root {0} --dbpath {1} --justdb {2}".format(*rpm_args)) # move /etc back to /usr/etc to m.execute("mv {0} {1}".format(rpm_etc, usr_etc)) # Upload a signing key m.upload(["verify/files/secring.gpg", "verify/files/pubring.gpg"], "/root/") commit_args = [REPO_LOCATION, branch.strip(), CHECKOUT_LOCATION, KEY_ID] command = "ostree commit -s cockpit-tree2 --repo {0} -b {1} --add-metadata-string version=cockpit-base.2 --tree=dir={2} --gpg-sign={3} --gpg-homedir=/root/" m.execute(command.format(*commit_args)) m.execute(["ostree", "summary", "--repo={}".format(REPO_LOCATION), "-u"]) def rhsmcertd_hack(m): # HACK: https://github.com/candlepin/subscription-manager/issues/1404 m.execute("systemctl disable rhsmcertd || true") m.execute("systemctl stop rhsmcertd || true") @skipImage("No OSTree available", "centos-7", "debian-stable", "debian-testing", "fedora-24", "fedora-25", "fedora-26", "fedora-testing", "fedora-i386", "rhel-7", "rhel-7-4", "ubuntu-1604", "ubuntu-stable") class OstreeRestartCase(MachineCase): def setUp(self): # we need a static ip for this test becuase we restart MachineCase.setUp(self, macaddr='52:54:00:9e:00:F5') def switch_to_packages(self, b, sel, required_classes): b.wait_not_visible("{0} div.packages".format(sel)) b.wait_present('{0} ul'.format(sel)) b.click('{0} ul li a:contains("Packages")'.format(sel)) b.wait_visible("{0} div.packages".format(sel)) for c in required_classes: b.wait_present("{0} div.packages dl.{1}".format(sel, c)) def check_change_counts(self, b, sel): for k in ['adds', 'removes', 'updates', 'downgrades']: b.wait_present("{0} dd.{1}".format(sel, k)) b.wait_text("{0} dd.{1}".format(sel, k), "1 package") def check_sig(self, b, sel): b.wait_not_visible("{0} div.signatures".format(sel)) b.wait_present('{0} ul'.format(sel)) b.click('{0} ul li a:contains("Signature")'.format(sel)) b.wait_visible("{0} div.signatures".format(sel)) b.wait_in_text("{0} div.signatures".format(sel), KEY_ID) b.wait_in_text("{0} div.signatures".format(sel), "RSA") b.wait_in_text("{0} div.signatures".format(sel), "Cockpit Tester ") b.wait_in_text("{0} div.signatures".format(sel), "Good Signature") b.wait_in_text("{0} div.signatures".format(sel), "When") def testOstree(self): b = self.browser m = self.machine # Delete local remote so we start clean, without a file based remote ensure_remote_http_port (m) docker_pkg = m.execute("rpm -qa | grep cockpit-docker").strip() rhsmcertd_hack(m) cockpit_shell = m.execute("rpm -qa | grep cockpit-ostree").strip() cockpit_machines = m.execute("rpm -qa | grep cockpit-machines").strip() self.login_and_go("/updates") b.enter_page("/updates") name = get_os_name(m) # Check current and rollback target b.wait_present('table.listing-ct') b.wait_present('table.listing-ct tbody') b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " cockpit-base.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-check-circle-o') b.wait_present('table.listing-ct tbody:nth-child(3).active') b.wait_in_text('table.listing-ct tbody:nth-child(3) div.listing-ct-status', "Running") b.wait_not_present("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button") b.wait_visible("table.listing-ct tbody:nth-child(3) div.tree") b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.os", name) b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.version", "cockpit-base.1") self.switch_to_packages(b, "table.listing-ct tbody:nth-child(3)", ['rpms-col1', 'rpms-col2']) b.wait_in_text("table.listing-ct tbody:nth-child(3) div.packages", docker_pkg) for pkg in INSTALL_RPMS: b.wait_not_in_text("table.listing-ct tbody:nth-child(3) div.packages", pkg) b.wait_not_visible("table.listing-ct tbody:nth-child(3) div.signatures") b.wait_present('table.listing-ct tbody:nth-child(3) ul') b.click('table.listing-ct tbody:nth-child(3) ul li a:contains("Signature")') b.wait_visible("table.listing-ct tbody:nth-child(3) div.signatures") b.wait_in_text("table.listing-ct tbody:nth-child(3) div.signatures", "No signature avaliable") # Require signatures m.execute("sed -i /gpg-verify/d /etc/ostree/remotes.d/local.conf") # HACK: rpm-ostree doesn't reload remote settings properly # https://github.com/projectatomic/rpm-ostree/issues/401 m.execute("systemctl restart rpm-ostreed") b.wait_not_in_text('table.listing-ct tbody:nth-child(4) div.listing-ct-head h3', "cockpit") b.wait_present('table.listing-ct tbody:nth-child(4) i.fa-circle') b.wait_in_text('table.listing-ct tbody:nth-child(4) div.listing-ct-status', "Available") b.wait_in_text("table.listing-ct tbody:nth-child(4) div.listing-ct-actions button", "Roll Back") b.wait_in_text("table.listing-ct tbody:nth-child(4) dd.os", name) b.wait_visible("table.listing-ct tbody:nth-child(4) div.tree") b.wait_not_visible("table.listing-ct tbody:nth-child(4) div.packages") # Check for new commit, get error b.wait_present('table.listing-ct tbody:nth-child(2) i.fa-caret-up') b.wait_in_text("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button", "Check for Updates") b.wait_not_present('table.listing-ct tbody:nth-child(2) div.alert-warning') b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present('table.listing-ct tbody:nth-child(2) div.alert-warning') b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.enabled") # Serve repo server_pid = start_trivial_httpd(m) # Check for new commit b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.disabled") b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.enabled") # Generate new commit generate_new_commit(m, docker_pkg) # Check again not trusted b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present('table.listing-ct tbody:nth-child(2) div.alert-warning') b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.enabled") b.wait_in_text("table.listing-ct tbody:nth-child(2) div.alert-warning", "trusted keyring") m.upload(["verify/files/publickey.asc"], "/root/") m.execute("ostree remote gpg-import local -k /root/publickey.asc") # Check again have update data b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') b.wait_in_text('table.listing-ct tbody:nth-child(3) div.listing-ct-status', "Available") b.wait_in_text("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button", "Update") b.wait_present('table.listing-ct tbody:nth-child(4) i.fa-check-circle-o') # Check update data b.wait_visible("table.listing-ct tbody:nth-child(3) div.tree") b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.os", name) b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.version", "cockpit-base.2") self.check_change_counts(b, "table.listing-ct tbody:nth-child(3)") self.switch_to_packages(b, "table.listing-ct tbody:nth-child(3)", ['upgrades', 'downgrades', 'additions', 'removals']) b.wait_text("table.listing-ct tbody:nth-child(3) dl.upgrades dd", "cockpit-machines-99999-2.noarch") b.wait_text("table.listing-ct tbody:nth-child(3) dl.downgrades dd", "cockpit-ostree-wip-0.1.noarch") b.wait_text("table.listing-ct tbody:nth-child(3) dl.additions dd", "empty-1-0.noarch") b.wait_text("table.listing-ct tbody:nth-child(3) dl.removals dd", docker_pkg) # Check signatures self.check_sig (b, "table.listing-ct tbody:nth-child(3)") # Force an error stop_trivial_httpd(m, server_pid) b.wait_not_present('table.listing-ct tbody:nth-child(3) div.listing-ct-error') b.click("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button.disabled") b.wait_present("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button.enabled") b.wait_present('table.listing-ct tbody:nth-child(3) div.listing-ct-error') server_pid = start_trivial_httpd(m) # Apply update b.click("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(3) div.ostree-progress") b.wait_not_present('table.listing-ct tbody:nth-child(3) div.listing-ct-error') b.switch_to_top() with b.wait_timeout(120): b.wait_visible(".curtains-ct") b.wait_in_text(".curtains-ct h1", "Disconnected") m.wait_reboot() m.start_cockpit() b.reload() b.login_and_go("/updates") m.reset_reboot_flag() # After reboot, check commit b.wait_present('table.listing-ct') b.wait_present('table.listing-ct tbody') b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " cockpit-base.2") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-check-circle-o') b.wait_present('table.listing-ct tbody:nth-child(3) div.listing-ct-panel,active') b.wait_in_text('table.listing-ct tbody:nth-child(3) div.listing-ct-status', "Running") b.wait_not_present("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button") self.switch_to_packages(b, "table.listing-ct tbody:nth-child(3)", ['rpms-col1', 'rpms-col2']) b.wait_not_in_text("table.listing-ct tbody:nth-child(3) div.packages", docker_pkg) for pkg in INSTALL_RPMS: b.wait_in_text("table.listing-ct tbody:nth-child(3) div.packages", pkg) # Check signatures self.check_sig (b, "table.listing-ct tbody:nth-child(3)") # Check rollback target b.wait_text('table.listing-ct tbody:nth-child(4) div.listing-ct-head h3', name + " cockpit-base.1") b.wait_present('table.listing-ct tbody:nth-child(4) i.fa-circle') b.wait_in_text('table.listing-ct tbody:nth-child(4) div.listing-ct-status', "Available") b.wait_in_text("table.listing-ct tbody:nth-child(4) div.listing-ct-actions button", "Roll Back") b.wait_in_text("table.listing-ct tbody:nth-child(4) dd.os", name) self.check_change_counts(b, "table.listing-ct tbody:nth-child(4)") self.switch_to_packages(b, "table.listing-ct tbody:nth-child(4)", ['upgrades', 'downgrades', 'additions', 'removals']) b.wait_text("table.listing-ct tbody:nth-child(4) dl.upgrades dd", cockpit_shell) b.wait_text("table.listing-ct tbody:nth-child(4) dl.downgrades dd", cockpit_machines) b.wait_text("table.listing-ct tbody:nth-child(4) dl.additions dd", docker_pkg) b.wait_text("table.listing-ct tbody:nth-child(4) dl.removals dd", "empty-1-0.noarch") # Rollback b.wait_present("button:contains('Roll Back')"); b.click("table.listing-ct tbody:nth-child(4) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(4) div.ostree-progress") b.switch_to_top() with b.wait_timeout(120): b.wait_visible(".curtains-ct") b.wait_in_text(".curtains-ct h1", "Disconnected") m.wait_reboot() m.start_cockpit() b.reload() b.login_and_go("/updates") m.reset_reboot_flag() # After reboot upgrade but no rollback target b.wait_present('table.listing-ct') b.wait_present('table.listing-ct tbody') b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') b.wait_in_text("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button", "Update") b.wait_present('table.listing-ct tbody:nth-child(4) i.fa-check-circle-o') b.wait_not_present('table.listing-ct tbody:nth-child(5)') b.wait_not_present("button:contains('Roll Back')"); self.allow_restart_journal_messages() def testRebase(self): m = self.machine b = self.browser name = get_os_name(m) start_trivial_httpd(m) branch = m.execute("ostree refs --repo={0}".format(REPO_LOCATION)).strip() # Add a new branch to the default repo m.execute(["ostree", "commit", "--repo={}".format(REPO_LOCATION), "-b", "znew-branch", "--tree=ref={}".format(branch), "--add-metadata-string", "version=branch-version"]) m.execute(["ostree", "summary", "--repo={}".format(REPO_LOCATION), "-u"]) rhsmcertd_hack(m) self.login_and_go("/updates") b.enter_page("/updates") b.wait_present('table.listing-ct tbody:nth-child(2) i.fa-caret-up') b.wait_present('#change-repo') b.wait_text("#change-repo", "local") b.wait_present("#change-branch") b.wait_in_text("#change-branch", branch) b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li") b.wait_not_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li div.alert") b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:last", "znew-branch") b.call_js_func("ph_count_check", "table.listing-ct tbody:nth-child(2) ul.dropdown-menu li", 2) b.click("#change-branch") b.click("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:last a") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " cockpit-base.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-check-circle-o') b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.origin", "local:{}".format(branch)) b.wait_in_text("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button", "Check for Updates") b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.enabled") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " branch-version") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') b.wait_in_text('table.listing-ct tbody:nth-child(3) div.listing-ct-status', "Available") b.wait_in_text("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button", "Rebase") b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.os", name) b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.origin", "local:znew-branch") b.wait_not_visible("table.listing-ct tbody:nth-child(3) div.packages") b.wait_present('table.listing-ct tbody:nth-child(3) ul') b.click('table.listing-ct tbody:nth-child(3) ul li a:contains("Packages")') b.wait_visible("table.listing-ct tbody:nth-child(3) div.packages") b.wait_in_text("table.listing-ct tbody:nth-child(3) div.packages", "contains the same packages as your currently booted") # Apply update b.click("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(3) div.ostree-progress") b.wait_not_present('table.listing-ct tbody:nth-child(3) div.listing-ct-error') b.switch_to_top() with b.wait_timeout(120): b.wait_visible(".curtains-ct") b.wait_in_text(".curtains-ct h1", "Disconnected") m.wait_reboot() m.start_cockpit() b.reload() b.login_and_go("/updates") m.reset_reboot_flag() # After reboot, check commit b.wait_present('table.listing-ct') b.wait_present('table.listing-ct tbody') b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " branch-version") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-check-circle-o') b.wait_present('table.listing-ct tbody:nth-child(3) div.listing-ct-panel,active') b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.origin", "local:znew-branch") self.allow_restart_journal_messages() @skipImage("No OSTree available", "centos-7", "debian-stable", "debian-testing", "fedora-24", "fedora-25", "fedora-26", "fedora-testing", "fedora-i386", "rhel-7", "rhel-7-4", "ubuntu-1604", "ubuntu-stable") class OstreeCase(MachineCase): def testRemoteManagement(self): m = self.machine b = self.browser name = get_os_name(m) start_trivial_httpd(m) branch = m.execute("ostree refs --repo={0}".format(REPO_LOCATION)).strip() rhsmcertd_hack(m) self.login_and_go("/updates") b.enter_page("/updates") b.wait_present('table.listing-ct tbody:nth-child(2) i.fa-caret-up') b.wait_not_present('table.listing-ct tbody:nth-child(2) div.alert-warning') b.wait_present("#change-branch") b.wait_in_text("#change-branch", branch) b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li") b.wait_not_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li div.alert") b.call_js_func("ph_count_check", "table.listing-ct tbody:nth-child(2) ul.dropdown-menu li", 1) b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li", branch) b.wait_present('#change-repo') b.wait_text("#change-repo", "local") b.click("#change-repo") b.wait_present("modal-dialog") b.wait_in_text("modal-dialog .modal-title", "Change Repository") b.wait_present("modal-dialog .modal-body .list-group") b.wait_in_text("modal-dialog .modal-body .list-group .active", "local") b.wait_in_text("modal-dialog .modal-body .list-group-item:last", "Add New Repository") b.wait_present("modal-dialog .modal-footer button.btn-primary") b.click("modal-dialog .modal-body .list-group-item:last") b.wait_present("modal-dialog .modal-footer button.disabled") b.wait_present("modal-dialog #remote-name") b.wait_present("modal-dialog #remote-url") b.wait_present("modal-dialog #gpg-verify") b.click("modal-dialog #gpg-verify") b.set_val("modal-dialog #remote-url", "http://localhost:12344") b.set_val("modal-dialog #remote-name", "zremote test") b.wait_present("modal-dialog .group-buttons button.btn-primary") b.wait_in_text("modal-dialog .group-buttons button.btn-primary", "Add") b.click("modal-dialog .group-buttons button.btn-primary") b.wait_present("modal-dialog .list-group-item:last div.dialog-error") b.set_val("modal-dialog #remote-name", "zremote-test1") b.click("modal-dialog .group-buttons button.btn-primary") b.wait_not_present ("modal-dialog #remote-name") b.wait_not_present ("modal-dialog .group-buttons") b.wait_not_present("modal-dialog .modal-footer button.disabled") b.wait_present("modal-dialog .modal-footer button.btn-primary") b.wait_in_text("modal-dialog .modal-body .list-group .active", "local") b.wait_present("modal-dialog .modal-body .list-group-item:contains('zremote-test1')") b.wait_in_text("modal-dialog .modal-body .list-group-item:last", "Add New Repository") b.click("modal-dialog .modal-body .list-group-item:contains('zremote-test1')") b.click("modal-dialog .modal-footer button.btn-primary") b.wait_not_present("modal-dialog") b.wait_present('#change-repo') b.wait_text("#change-repo", "zremote-test1") # Branch is still default b.wait_present("#change-branch") b.wait_in_text("#change-branch", branch) # But can't list b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu div.alert") b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu div.alert", "Connection refused") # Config created self.assertEqual(m.execute("cat /etc/ostree/remotes.d/zremote-test1.conf").strip(), '[remote "zremote-test1"]\nurl=http://localhost:12344\ngpg-verify=true') # No custom keyring self.assertFalse(m.execute("ls /sysroot/ostree/repo/zremote-test1.trustedkeys.gpg || true")) # Refresh goes back to default b.reload() b.enter_page("/updates") b.wait_present('table.listing-ct tbody:nth-child(2) i.fa-caret-up') b.wait_present('#change-repo') b.wait_text("#change-repo", "local") b.wait_present("#change-branch") b.wait_in_text("#change-branch", branch) b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li") b.wait_not_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu div.alert") # Create a new remote with commits, just use the rpm dir zrepo = "/var/zrepo" m.execute("mkdir -p {}".format(zrepo)) m.execute("mkdir -p /tmp/rpm-data/usr/share") m.execute("cp -r /usr/share/rpm /tmp/rpm-data/usr/share/") m.execute(["ostree", "init", "--repo", zrepo, "--mode", "archive-z2"]) m.execute(["ostree", "commit", "--repo={}".format(zrepo), "-b", "zremote-branch1", "--orphan", "--tree=dir=/tmp/rpm-data", "--add-metadata-string", "version=zremote-branch1.1"]) m.execute(["ostree", "commit", "--repo={}".format(zrepo), "-b", "zremote-branch2", "--orphan", "--tree=dir=/tmp/rpm-data", "--add-metadata-string", "version=zremote-branch2.1"]) start_trivial_httpd(m, remote="zremote-test1", location=zrepo) # Add a new branch to the default repo m.execute(["ostree", "commit", "--repo={}".format(REPO_LOCATION), "-b", branch, "--tree=ref={}".format(branch), "--add-metadata-string", "version=bad-version"]) m.execute(["ostree", "summary", "--repo={}".format(REPO_LOCATION), "-u"]) # Edit b.wait_present('#change-repo') b.click("#change-repo") b.wait_present("modal-dialog") b.wait_present("modal-dialog .modal-body .list-group") b.wait_present("modal-dialog .modal-body .list-group-item:contains('zremote-test1')") b.wait_present("modal-dialog .modal-body .list-group-item:contains('zremote-test1') .listing-ct-actions button.pficon-edit") b.click("modal-dialog .modal-body .list-group-item:contains('zremote-test1') .listing-ct-actions button.pficon-edit") b.wait_present("modal-dialog .group-buttons") b.wait_present("modal-dialog .modal-footer button.disabled") b.wait_present("modal-dialog .group-buttons button.btn-primary") b.wait_in_text("modal-dialog .group-buttons", "zremote-test1") b.wait_present("modal-dialog .form-table-ct") b.wait_in_text("modal-dialog .form-table-ct", "http://localhost:12344") b.wait_present("modal-dialog .form-table-ct #gpg-verify:checked") b.wait_not_present("modal-dialog #gpg-data") b.wait_present("modal-dialog .form-table-ct button.btn-default") b.click("modal-dialog .form-table-ct button.btn-default") b.wait_present("modal-dialog #gpg-data") b.wait_not_present("modal-dialog .form-table-ct button.btn-default") b.set_val("modal-dialog #gpg-data", "bad") b.click("modal-dialog .group-buttons button.btn-primary") b.wait_present("modal-dialog .group-buttons div.dialog-error") with open(os.path.join(TEST_DIR, "verify", "files", "publickey.asc"), 'rb') as fp: gpg_data = fp.read() b.set_val("modal-dialog #gpg-data", gpg_data) b.click("modal-dialog .group-buttons button.btn-primary") b.wait_not_present ("modal-dialog .group-buttons") b.wait_not_present("modal-dialog .form-table-ct") b.wait_not_present("modal-dialog .modal-footer button.disabled") m.execute("ls /sysroot/ostree/repo/zremote-test1.trustedkeys.gpg") b.wait_present("modal-dialog .modal-body .list-group-item:contains('zremote-test1') .listing-ct-actions button.pficon-edit") b.click("modal-dialog .modal-body .list-group-item:contains('zremote-test1') .listing-ct-actions button.pficon-edit") b.wait_present("modal-dialog .group-buttons") b.wait_present("modal-dialog .modal-footer button.disabled") b.wait_present("modal-dialog .group-buttons button.btn-primary") b.wait_present("modal-dialog .form-table-ct") b.wait_in_text("modal-dialog .form-table-ct", "http://localhost:12344") b.wait_present("modal-dialog .form-table-ct button.btn-default") b.wait_present("modal-dialog .form-table-ct #gpg-verify:checked") b.click("modal-dialog .form-table-ct #gpg-verify") b.click("modal-dialog .group-buttons button.btn-primary") b.wait_not_present("modal-dialog .form-table-ct") b.wait_not_present ("modal-dialog .group-buttons") b.wait_not_present("modal-dialog .modal-footer button.disabled") b.click("modal-dialog .modal-body .list-group-item:contains('zremote-test1')") b.click("modal-dialog .modal-footer button.btn-primary") b.wait_not_present("modal-dialog") b.wait_present('#change-repo') b.wait_text("#change-repo", "zremote-test1") b.wait_present("#change-branch") b.wait_in_text("#change-branch", "zremote-branch1") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li") b.wait_not_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu div.alert") b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:first", "zremote-branch1") b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:last", "zremote-branch2") b.call_js_func("ph_count_check", "table.listing-ct tbody:nth-child(2) ul.dropdown-menu li", 2) self.assertEqual(m.execute("cat /etc/ostree/remotes.d/zremote-test1.conf").strip(), '[remote "zremote-test1"]\nurl=http://localhost:12344\ngpg-verify = false') # Check updates display b.wait_present("table.listing-ct tbody:nth-child(3)") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " cockpit-base.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-check-circle-o') b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.origin", "local:{}".format(branch)) b.wait_in_text("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button", "Check for Updates") b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.enabled") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " zremote-branch1.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') b.wait_in_text('table.listing-ct tbody:nth-child(3) div.listing-ct-status', "Available") b.wait_in_text("table.listing-ct tbody:nth-child(3) div.listing-ct-actions button", "Rebase") b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.os", name) b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.origin", "zremote-test1:zremote-branch1") b.wait_not_visible("table.listing-ct tbody:nth-child(3) div.packages") b.wait_present('table.listing-ct tbody:nth-child(3) ul') b.click('table.listing-ct tbody:nth-child(3) ul li a:contains("Packages")') b.wait_visible("table.listing-ct tbody:nth-child(3) div.packages") b.wait_in_text("table.listing-ct tbody:nth-child(3) div.packages", "contains the same packages as your currently booted") # Switching branch hides other b.click("#change-branch") b.wait_visible("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:last", "zremote-branch2") b.click("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:last a") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " cockpit-base.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-check-circle-o') # Switching back shows pulled b.wait_present('#change-branch') b.click("#change-branch") b.wait_visible("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_in_text("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:first", "zremote-branch1") b.click("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li:first a") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " zremote-branch1.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') # Refresh, back to local, pull in update b.reload() b.enter_page("/updates") b.wait_present('table.listing-ct tbody:nth-child(2) i.fa-caret-up') b.wait_present("#change-branch") b.wait_in_text("#change-branch", branch) b.wait_in_text("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button", "Check for Updates") b.click("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button") b.wait_present("table.listing-ct tbody:nth-child(2) div.listing-ct-actions button.enabled") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " bad-version") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') # Switching to branch shows pulled b.wait_present('#change-repo') b.wait_text("#change-repo", "local") b.click("#change-repo") b.wait_present("modal-dialog") b.wait_present("modal-dialog .modal-body .list-group") b.wait_in_text("modal-dialog .modal-body .list-group-item:contains('zremote-test1')", "zremote-test1") b.click("modal-dialog .modal-body .list-group-item:contains('zremote-test1')") b.click("modal-dialog .modal-footer button.btn-primary") b.wait_not_present("modal-dialog") b.wait_present('#change-repo') b.wait_text("#change-repo", "zremote-test1") b.wait_present("#change-branch") b.wait_in_text("#change-branch", "zremote-branch1") b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " zremote-branch1.1") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') b.wait_not_in_text('table.listing-ct', name + " bad-version") # delete b.wait_present('#change-repo') b.click("#change-repo") b.wait_present("modal-dialog") b.wait_present("modal-dialog .modal-body .list-group") b.wait_in_text("modal-dialog .modal-body .list-group-item:contains('zremote-test1')", "zremote-test1") b.wait_present("modal-dialog .modal-body .list-group-item:contains('zremote-test1') .listing-ct-actions button.pficon-edit") b.click("modal-dialog .modal-body .list-group-item:contains('zremote-test1') .listing-ct-actions button.pficon-edit") b.wait_present("modal-dialog .group-buttons") b.wait_present("modal-dialog .group-buttons button.btn-danger") b.wait_present("modal-dialog .modal-footer button.disabled") b.wait_present("modal-dialog .form-table-ct") b.wait_in_text("modal-dialog .form-table-ct", "http://localhost:12344") b.wait_present("#gpg-verify") b.wait_present("modal-dialog .form-table-ct #gpg-verify:not(:checked)") b.click("modal-dialog .group-buttons button.btn-danger") b.wait_not_present("modal-dialog .form-table-ct") b.wait_not_present("modal-dialog .group-buttons") b.wait_present("modal-dialog .modal-body .list-group") b.wait_not_in_text("modal-dialog .modal-body .list-group", "zremote-test1") b.wait_in_text("modal-dialog .modal-body .list-group", "local") b.wait_not_present("modal-dialog .modal-body .list-group .active") b.wait_present("modal-dialog .modal-footer button.disabled") b.click("modal-dialog .modal-body .list-group-item:contains('local')") b.wait_present("modal-dialog .modal-body .list-group .active") b.click("modal-dialog .modal-footer button.btn-primary") b.wait_not_present("modal-dialog") b.wait_present('#change-repo') b.wait_text("#change-repo", "local") b.wait_present("#change-branch") b.wait_in_text("#change-branch", branch) b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu") b.wait_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li") b.wait_not_present("table.listing-ct tbody:nth-child(2) ul.dropdown-menu li div.alert") b.call_js_func("ph_count_check", "table.listing-ct tbody:nth-child(2) ul.dropdown-menu li", 1) b.wait_text('table.listing-ct tbody:nth-child(3) div.listing-ct-head h3', name + " bad-version") b.wait_present('table.listing-ct tbody:nth-child(3) i.fa-circle') b.wait_in_text("table.listing-ct tbody:nth-child(3) dd.origin", "local:{}".format(branch)) def testPermission(self): m = self.machine b = self.browser rhsmcertd_hack(m) # Create a user m.execute("useradd user -c 'User' || true") m.execute("echo foobar | passwd --stdin user") # login m.start_cockpit() b.open("/updates") b.wait_visible("#login") b.set_val("#login-user-input", "user") b.set_val("#login-password-input", "foobar") b.click('#login-button') b.enter_page("/updates") b.wait_present(".curtains-ct") b.wait_in_text(".curtains-ct", "Not authorized") self.assertIn("Reconnect", b.text(".blank-slate-pf-main-action button")) self.allow_authorize_journal_messages() if __name__ == "__main__": test_main()