def setup(self): state = self.get_state() self.label = re.sub('.py$', '', os.path.basename(state['name'])) self.browser = Browser("localhost", self.label) self.journal_start = re.sub( '.*cursor: ', '', subprocess.check_output( "journalctl --show-cursor -n0 -o cat || true", shell=True))
def setUp(self): # state = self.get_state() self.label = ("avocado") self.browser = Browser("localhost", self.label) self.journal_start = re.sub( '.*cursor: ', '', subprocess.check_output( "journalctl --show-cursor -n0 -o cat || true", shell=True))
class Test(test.Test): def __init__(self, **args): test.Test.__init__(self, **args) self.cleanup_funcs = [] self.environment = imp.load_source( "", os.path.dirname(__file__) + "/lib/var.env") def atcleanup(self, func): self.cleanup_funcs.append(func) def run_shell_command(self, cmd, cleanup_cmd): self.atcleanup(lambda: process.run(cleanup_cmd, shell=True)) process.run(cmd, shell=True) def replace_file(self, file, content): def restore(): shutil.copyfile(file + ".cockpitsave", file) os.remove(file + ".cockpitsave") shutil.copyfile(file, file + ".cockpitsave") self.atcleanup(restore) with open(file, 'w') as f: f.write(content) def setup(self): state = self.get_state() self.label = re.sub('.py$', '', os.path.basename(state['name'])) self.browser = Browser("localhost", self.label) self.journal_start = re.sub( '.*cursor: ', '', subprocess.check_output( "journalctl --show-cursor -n0 -o cat || true", shell=True)) def action(self): process.run("systemctl start cockpit-testing.socket", shell=True) self.test() self.check_journal_messages() def cleanup(self): state = self.get_state() # Make a final screenshot and save the journal for the test run. # # TODO: Do this only when the test has failed. # self.browser.snapshot("DONE") process.run("journalctl >'%s.journal' -c'%s'" % (self.label, self.journal_start), shell=True) # If this is a remote run, copy all screenshots and journals # to the results directory so that they get copied out of the # virtual machine. # # The status of "cp" is ignored because it will fail when # there are no screenshots or journals, but that is not really # an error. # # TODO: Do this only once after running all tests. # if not state['job_logdir'].startswith("/tmp/"): process.run("cp -v *.png *.journal '%s'" % state['job_logdir'], shell=True, ignore_status=True) for f in self.cleanup_funcs: f() process.run( "systemctl stop cockpit-testing.socket cockpit-testing.service", shell=True) allowed_messages = [ # This is a failed login, which happens every time "Returning error-response 401 with reason `Sorry'", # Reboots are ok "-- Reboot --", # Sometimes D-Bus goes away before us during shutdown "Lost the name com.redhat.Cockpit on the session message bus", "GLib-GIO:ERROR:gdbusobjectmanagerserver\\.c:.*:g_dbus_object_manager_server_emit_interfaces_.*: assertion failed \\(error == NULL\\): The connection is closed \\(g-io-error-quark, 18\\)", "Error sending message: The connection is closed", # Will go away with glib 2.43.2 ".*: couldn't write web output: Error sending data: Connection reset by peer", ## Bugs # https://bugs.freedesktop.org/show_bug.cgi?id=70540 ".*ActUserManager: user .* has no username.*", # https://github.com/cockpit-project/cockpit/issues/48 "Failed to load '.*': Key file does not have group 'Unit'", # https://github.com/cockpit-project/cockpit/issues/115 "cockpit-testing\\.service: main process exited, code=exited, status=1/FAILURE", "Unit cockpit-testing\\.service entered failed state\\.", # https://bugs.freedesktop.org/show_bug.cgi?id=71092 "logind\\.KillUser failed \\(Input/output error\\), trying systemd\\.KillUnit", # SELinux messages to ignore "(audit: )?type=1403 audit.*", "(audit: )?type=1404 audit.*", # Hmm "request timed out, closing", "(audit: )?type=1400 .* name=\"machine-info\".*", "pam_lastlog\\(cockpit:session\\): unable to open /var/log/lastlog: No such file or directory" ] def allow_journal_messages(self, *patterns): """Don't fail if the journal containes a entry matching the given regexp""" for p in patterns: self.allowed_messages.append(p) def allow_restart_journal_messages(self): self.allow_journal_messages( "Error receiving data: Connection reset by peer", "g_dbus_connection_real_closed: Remote peer vanished with error: Underlying GIOStream returned 0 bytes on an async read \\(g-io-error-quark, 0\\). Exiting.", "g_dbus_connection_real_closed: Remote peer vanished with error: Error sending message: Broken pipe \\(g-io-error-quark, 44\\). Exiting.", # HACK: https://bugzilla.redhat.com/show_bug.cgi?id=1141137 "localhost: bridge program failed: Child process killed by signal 9" ) def journal_messages(self, syslog_ids, log_level): """Return interesting journal messages""" # Journald does not always set trusted fields like # _SYSTEMD_UNIT or _EXE correctly for the last few messages of # a dying process, so we filter by the untrusted but reliable # SYSLOG_IDENTIFIER instead matches = " ".join( map(lambda id: "SYSLOG_IDENTIFIER=" + id, syslog_ids)) # Some versions of journalctl terminate unsuccessfully when # the output is empty. We work around this by ignoring the # exit status and including error messages from journalctl # itself in the returned messages. cmd = "journalctl 2>&1 -c'%s' -o cat -p %d %s" % (self.journal_start, log_level, matches) out = process.run(cmd, shell=True, ignore_status=True) messages = out.stdout.splitlines() if len(messages ) == 1 and "Cannot assign requested address" in messages[0]: # No messages return [] else: return messages def audit_messages(self, type_pref): cmd = "journalctl -c'%s' -o cat SYSLOG_IDENTIFIER=kernel 2>&1 | grep 'type=%s.*audit' || true" % ( self.journal_start, type_pref) out = process.run(cmd, shell=True) messages = out.stdout.splitlines() if len(messages ) == 1 and "Cannot assign requested address" in messages[0]: messages = [] return messages def check_journal_messages(self): """Check for unexpected journal entries.""" syslog_ids = ["cockpit-wrapper", "cockpit-ws", "cockpit-session"] messages = self.journal_messages(syslog_ids, 5) messages += self.audit_messages("14") # 14xx is selinux all_found = True for m in messages: found = False for p in self.allowed_messages: match = re.match(p, m) if match and match.group(0) == m: found = True break if not found: self.log.info("Unexpected journal message '%s'" % m) all_found = False self.assertTrue(all_found, msg="There were unexpected journal messages")
def setup(self): state = self.get_state() self.label = re.sub('.py$', '', os.path.basename(state['name'])) self.browser = Browser("localhost", self.label) self.journal_start = re.sub('.*cursor: ', '', subprocess.check_output("journalctl --show-cursor -n0 -o cat || true", shell=True))
class Test(test.Test): def __init__(self, **args): test.Test.__init__(self, **args) self.cleanup_funcs = [ ] self.environment = imp.load_source("", os.path.dirname(__file__) + "/lib/var.env") def atcleanup(self, func): self.cleanup_funcs.append(func) def run_shell_command(self, cmd, cleanup_cmd): self.atcleanup(lambda: process.run(cleanup_cmd, shell=True)) process.run(cmd, shell=True) def replace_file(self, file, content): def restore(): shutil.copyfile(file + ".cockpitsave", file) os.remove(file + ".cockpitsave") shutil.copyfile(file, file + ".cockpitsave") self.atcleanup(restore) with open(file, 'w') as f: f.write(content) def setup(self): state = self.get_state() self.label = re.sub('.py$', '', os.path.basename(state['name'])) self.browser = Browser("localhost", self.label) self.journal_start = re.sub('.*cursor: ', '', subprocess.check_output("journalctl --show-cursor -n0 -o cat || true", shell=True)) def action(self): process.run("systemctl start cockpit-testing.socket", shell=True) self.test() self.check_journal_messages() def cleanup(self): state = self.get_state() # Make a final screenshot and save the journal for the test run. # # TODO: Do this only when the test has failed. # self.browser.snapshot("DONE") process.run("journalctl >'%s.journal' -c'%s'" % (self.label, self.journal_start), shell=True) # If this is a remote run, copy all screenshots and journals # to the results directory so that they get copied out of the # virtual machine. # # The status of "cp" is ignored because it will fail when # there are no screenshots or journals, but that is not really # an error. # # TODO: Do this only once after running all tests. # if not state['job_logdir'].startswith("/tmp/"): process.run("cp -v *.png *.journal '%s'" % state['job_logdir'], shell=True, ignore_status=True) for f in self.cleanup_funcs: f() process.run("systemctl stop cockpit-testing.socket cockpit-testing.service", shell=True) allowed_messages = [ # This is a failed login, which happens every time "Returning error-response 401 with reason `Sorry'", # Reboots are ok "-- Reboot --", # Sometimes D-Bus goes away before us during shutdown "Lost the name com.redhat.Cockpit on the session message bus", "GLib-GIO:ERROR:gdbusobjectmanagerserver\\.c:.*:g_dbus_object_manager_server_emit_interfaces_.*: assertion failed \\(error == NULL\\): The connection is closed \\(g-io-error-quark, 18\\)", "Error sending message: The connection is closed", # Will go away with glib 2.43.2 ".*: couldn't write web output: Error sending data: Connection reset by peer", ## Bugs # https://bugs.freedesktop.org/show_bug.cgi?id=70540 ".*ActUserManager: user .* has no username.*", # https://github.com/cockpit-project/cockpit/issues/48 "Failed to load '.*': Key file does not have group 'Unit'", # https://github.com/cockpit-project/cockpit/issues/115 "cockpit-testing\\.service: main process exited, code=exited, status=1/FAILURE", "Unit cockpit-testing\\.service entered failed state\\.", # https://bugs.freedesktop.org/show_bug.cgi?id=71092 "logind\\.KillUser failed \\(Input/output error\\), trying systemd\\.KillUnit", # SELinux messages to ignore "(audit: )?type=1403 audit.*", "(audit: )?type=1404 audit.*", # Hmm "request timed out, closing", "(audit: )?type=1400 .* name=\"machine-info\".*", "pam_lastlog\\(cockpit:session\\): unable to open /var/log/lastlog: No such file or directory" ] def allow_journal_messages(self, *patterns): """Don't fail if the journal containes a entry matching the given regexp""" for p in patterns: self.allowed_messages.append(p) def allow_restart_journal_messages(self): self.allow_journal_messages("Error receiving data: Connection reset by peer", "g_dbus_connection_real_closed: Remote peer vanished with error: Underlying GIOStream returned 0 bytes on an async read \\(g-io-error-quark, 0\\). Exiting.", "g_dbus_connection_real_closed: Remote peer vanished with error: Error sending message: Broken pipe \\(g-io-error-quark, 44\\). Exiting.", # HACK: https://bugzilla.redhat.com/show_bug.cgi?id=1141137 "localhost: bridge program failed: Child process killed by signal 9") def journal_messages(self, syslog_ids, log_level): """Return interesting journal messages""" # Journald does not always set trusted fields like # _SYSTEMD_UNIT or _EXE correctly for the last few messages of # a dying process, so we filter by the untrusted but reliable # SYSLOG_IDENTIFIER instead matches = " ".join(map(lambda id: "SYSLOG_IDENTIFIER=" + id, syslog_ids)) # Some versions of journalctl terminate unsuccessfully when # the output is empty. We work around this by ignoring the # exit status and including error messages from journalctl # itself in the returned messages. cmd = "journalctl 2>&1 -c'%s' -o cat -p %d %s" % (self.journal_start, log_level, matches) out = process.run(cmd, shell=True, ignore_status=True) messages = out.stdout.splitlines() if len(messages) == 1 and "Cannot assign requested address" in messages[0]: # No messages return [ ] else: return messages def audit_messages(self, type_pref): cmd = "journalctl -c'%s' -o cat SYSLOG_IDENTIFIER=kernel 2>&1 | grep 'type=%s.*audit' || true" % (self.journal_start, type_pref) out = process.run(cmd, shell=True) messages = out.stdout.splitlines() if len(messages) == 1 and "Cannot assign requested address" in messages[0]: messages = [ ] return messages def check_journal_messages(self): """Check for unexpected journal entries.""" syslog_ids = [ "cockpit-wrapper", "cockpit-ws", "cockpit-session" ] messages = self.journal_messages(syslog_ids, 5) messages += self.audit_messages("14") # 14xx is selinux all_found = True for m in messages: found = False for p in self.allowed_messages: match = re.match(p, m) if match and match.group(0) == m: found = True break if not found: self.log.info("Unexpected journal message '%s'" % m) all_found = False self.assertTrue(all_found, msg="There were unexpected journal messages")