Squashed 'yocto-poky/' content from commit ea562de

git-subtree-dir: yocto-poky
git-subtree-split: ea562de57590c966cd5a75fda8defecd397e6436
diff --git a/meta/lib/oeqa/runtime/parselogs.py b/meta/lib/oeqa/runtime/parselogs.py
new file mode 100644
index 0000000..e20947b
--- /dev/null
+++ b/meta/lib/oeqa/runtime/parselogs.py
@@ -0,0 +1,257 @@
+import os
+import unittest
+import subprocess
+from oeqa.oetest import oeRuntimeTest
+from oeqa.utils.decorators import *
+
+#in the future these lists could be moved outside of module
+errors = ["error", "cannot", "can\'t", "failed"]
+
+common_errors = [
+    "(WW) warning, (EE) error, (NI) not implemented, (??) unknown.",
+    "dma timeout",
+    "can\'t add hid device:",
+    "usbhid: probe of ",
+    "_OSC failed (AE_ERROR)",
+    "_OSC failed (AE_SUPPORT)",
+    "AE_ALREADY_EXISTS",
+    "ACPI _OSC request failed (AE_SUPPORT)",
+    "can\'t disable ASPM",
+    "Failed to load module \"vesa\"",
+    "Failed to load module vesa",
+    "Failed to load module \"modesetting\"",
+    "Failed to load module modesetting",
+    "Failed to load module \"glx\"",
+    "Failed to load module \"fbdev\"",
+    "Failed to load module fbdev",
+    "Failed to load module glx",
+    "[drm] Cannot find any crtc or sizes - going 1024x768",
+    "_OSC failed (AE_NOT_FOUND); disabling ASPM",
+    "Open ACPI failed (/var/run/acpid.socket) (No such file or directory)",
+    "NX (Execute Disable) protection cannot be enabled: non-PAE kernel!",
+    "hd.: possibly failed opcode",
+    'NETLINK INITIALIZATION FAILED',
+    'kernel: Cannot find map file',
+    'omap_hwmod: debugss: _wait_target_disable failed',
+    'VGA arbiter: cannot open kernel arbiter, no multi-card support',
+    'Failed to find URL:http://ipv4.connman.net/online/status.html',
+    'Online check failed for',
+    ]
+
+x86_common = [
+    '[drm:psb_do_init] *ERROR* Debug is',
+    'wrong ELF class',
+    'Could not enable PowerButton event',
+    'probe of LNXPWRBN:00 failed with error -22',
+] + common_errors
+
+qemux86_common = [
+    'Fast TSC calibration', 
+    'wrong ELF class',
+    "fail to add MMCONFIG information, can't access extended PCI configuration space under this bridge.",
+    "can't claim BAR ",
+] + common_errors
+
+ignore_errors = { 
+    'default' : common_errors,
+    'qemux86' : [
+        'Failed to access perfctr msr (MSR',
+        ] + qemux86_common,
+    'qemux86-64' : qemux86_common,
+    'qemumips' : [
+        'Failed to load module "glx"',
+        'pci 0000:00:00.0: [Firmware Bug]: reg 0x..: invalid BAR (can\'t size)',
+        ] + common_errors,
+    'qemumips64' : [
+        'pci 0000:00:00.0: [Firmware Bug]: reg 0x..: invalid BAR (can\'t size)',
+         ] + common_errors,
+    'qemuppc' : [
+        'PCI 0000:00 Cannot reserve Legacy IO [io  0x0000-0x0fff]',
+        'host side 80-wire cable detection failed, limiting max speed',
+        'mode "640x480" test failed',
+        'Failed to load module "glx"',
+        ] + common_errors,
+    'qemuarm' : [
+        'mmci-pl18x: probe of fpga:05 failed with error -22',
+        'mmci-pl18x: probe of fpga:0b failed with error -22',
+        'Failed to load module "glx"'
+        ] + common_errors,
+    'qemuarm64' : [
+        'Fatal server error:',
+        '(EE) Server terminated with error (1). Closing log file.',
+        ] + common_errors,
+    'emenlow' : [
+        '[Firmware Bug]: ACPI: No _BQC method, cannot determine initial brightness',
+        '(EE) Failed to load module "psb"',
+        '(EE) Failed to load module psb',
+        '(EE) Failed to load module "psbdrv"',
+        '(EE) Failed to load module psbdrv',
+        '(EE) open /dev/fb0: No such file or directory',
+        '(EE) AIGLX: reverting to software rendering',
+        ] + x86_common,
+    'core2_32' : [
+        'ACPI: No _BQC method, cannot determine initial brightness',
+        '[Firmware Bug]: ACPI: No _BQC method, cannot determine initial brightness',
+        '(EE) Failed to load module "psb"',
+        '(EE) Failed to load module psb',
+        '(EE) Failed to load module "psbdrv"',
+        '(EE) Failed to load module psbdrv',
+        '(EE) open /dev/fb0: No such file or directory',
+        '(EE) AIGLX: reverting to software rendering',
+        ] + x86_common,
+    'intel-corei7-64' : [
+        "controller can't do DEVSLP, turning off",
+        ] + common_errors,
+    'crownbay' : x86_common,
+    'genericx86' : x86_common,
+    'genericx86-64' : x86_common,
+    'edgerouter' : [
+        'Fatal server error:',
+        ] + common_errors,
+    'minnow' : [
+        'netlink init failed',
+        ] + common_errors,
+    'jasperforest' : [
+        'Activated service \'org.bluez\' failed:',
+        'Unable to find NFC netlink family',
+        'netlink init failed',
+        ] + common_errors,
+}
+
+log_locations = ["/var/log/","/var/log/dmesg", "/tmp/dmesg_output.log"]
+
+class ParseLogsTest(oeRuntimeTest):
+
+    @classmethod
+    def setUpClass(self):
+        self.errors = errors
+        self.ignore_errors = ignore_errors
+        self.log_locations = log_locations
+        self.msg = ""
+
+    def getMachine(self):
+        return oeRuntimeTest.tc.d.getVar("MACHINE", True)
+
+    #get some information on the CPU of the machine to display at the beginning of the output. This info might be useful in some cases.
+    def getHardwareInfo(self):
+        hwi = ""
+        (status, cpu_name) = self.target.run("cat /proc/cpuinfo | grep \"model name\" | head -n1 | awk 'BEGIN{FS=\":\"}{print $2}'")
+        (status, cpu_physical_cores) = self.target.run("cat /proc/cpuinfo | grep \"cpu cores\" | head -n1 | awk {'print $4'}")
+        (status, cpu_logical_cores) = self.target.run("cat /proc/cpuinfo | grep \"processor\" | wc -l")
+        (status, cpu_arch) = self.target.run("uname -m")
+        hwi += "Machine information: \n"
+        hwi += "*******************************\n"
+        hwi += "Machine name: "+self.getMachine()+"\n"
+        hwi += "CPU: "+str(cpu_name)+"\n"
+        hwi += "Arch: "+str(cpu_arch)+"\n"
+        hwi += "Physical cores: "+str(cpu_physical_cores)+"\n"
+        hwi += "Logical cores: "+str(cpu_logical_cores)+"\n"
+        hwi += "*******************************\n"
+        return hwi
+
+    #go through the log locations provided and if it's a folder create a list with all the .log files in it, if it's a file just add 
+    #it to that list
+    def getLogList(self, log_locations):
+        logs = []
+        for location in log_locations:
+            (status, output) = self.target.run("test -f "+str(location))
+            if (status == 0):
+                logs.append(str(location))
+            else:
+                (status, output) = self.target.run("test -d "+str(location))
+                if (status == 0):
+                    (status, output) = self.target.run("find "+str(location)+"/*.log -maxdepth 1 -type f")
+                    if (status == 0):
+                        output = output.splitlines()
+                        for logfile in output:
+                            logs.append(os.path.join(location,str(logfile)))
+        return logs
+
+    #copy the log files to be parsed locally
+    def transfer_logs(self, log_list):
+        target_logs = 'target_logs'
+        if not os.path.exists(target_logs):
+            os.makedirs(target_logs)
+        for f in log_list:
+            self.target.copy_from(f, target_logs)
+
+    #get the local list of logs
+    def get_local_log_list(self, log_locations):
+        self.transfer_logs(self.getLogList(log_locations))
+        logs = [ os.path.join('target_logs',f) for f in os.listdir('target_logs') if os.path.isfile(os.path.join('target_logs',f)) ]
+        return logs
+
+    #build the grep command to be used with filters and exclusions
+    def build_grepcmd(self, errors, ignore_errors, log):
+        grepcmd = "grep "
+        grepcmd +="-Ei \""
+        for error in errors:
+            grepcmd += error+"|"
+        grepcmd = grepcmd[:-1]
+        grepcmd += "\" "+str(log)+" | grep -Eiv \'"
+        try:
+            errorlist = ignore_errors[self.getMachine()]
+        except KeyError:
+            self.msg += "No ignore list found for this machine, using default\n"
+            errorlist = ignore_errors['default']
+        for ignore_error in errorlist:
+            ignore_error = ignore_error.replace("(", "\(")
+            ignore_error = ignore_error.replace(")", "\)")
+            ignore_error = ignore_error.replace("'", ".")
+            ignore_error = ignore_error.replace("?", "\?")
+            ignore_error = ignore_error.replace("[", "\[")
+            ignore_error = ignore_error.replace("]", "\]")
+            ignore_error = ignore_error.replace("*", "\*")
+            grepcmd += ignore_error+"|"
+        grepcmd = grepcmd[:-1]
+        grepcmd += "\'"
+        return grepcmd
+
+    #grep only the errors so that their context could be collected. Default context is 10 lines before and after the error itself
+    def parse_logs(self, errors, ignore_errors, logs, lines_before = 10, lines_after = 10):
+        results = {}
+        rez = []
+        grep_output = ''
+        for log in logs:
+            result = None
+            thegrep = self.build_grepcmd(errors, ignore_errors, log)
+            try:
+                result = subprocess.check_output(thegrep, shell=True)
+            except:
+                pass
+            if (result is not None):
+                results[log.replace('target_logs/','')] = {}
+                rez = result.splitlines()
+                for xrez in rez:
+                    command = "grep \"\\"+str(xrez)+"\" -B "+str(lines_before)+" -A "+str(lines_after)+" "+str(log)
+                    try:
+                        grep_output = subprocess.check_output(command, shell=True)
+                    except:
+                        pass
+                    results[log.replace('target_logs/','')][xrez]=grep_output
+        return results
+
+    #get the output of dmesg and write it in a file. This file is added to log_locations.
+    def write_dmesg(self):
+        (status, dmesg) = self.target.run("dmesg")
+        (status, dmesg2) = self.target.run("echo \""+str(dmesg)+"\" > /tmp/dmesg_output.log")
+
+    @testcase(1059)
+    @skipUnlessPassed('test_ssh')
+    def test_parselogs(self):
+        self.write_dmesg()
+        log_list = self.get_local_log_list(self.log_locations)
+        result = self.parse_logs(self.errors, self.ignore_errors, log_list)
+        print self.getHardwareInfo()
+        errcount = 0
+        for log in result:
+            self.msg += "Log: "+log+"\n"
+            self.msg += "-----------------------\n"
+            for error in result[log]:
+                errcount += 1
+                self.msg += "Central error: "+str(error)+"\n"
+                self.msg +=  "***********************\n"
+                self.msg +=  result[str(log)][str(error)]+"\n"
+                self.msg +=  "***********************\n"
+        self.msg += "%s errors found in logs." % errcount
+        self.assertEqual(errcount, 0, msg=self.msg)