1import random, os, logging
2from autotest_lib.client.bin import test, utils
3from autotest_lib.client.common_lib import error
4
5
6class kvmtest(test.test):
7    version = 1
8
9    def initialize(self):
10        self.job.require_gcc()
11
12
13    def setup(self, tarball = 'kvm-test.tar.gz'):
14        tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
15        utils.extract_tarball_to_dir(tarball, self.srcdir)
16        os.chdir(self.srcdir)
17        utils.system('python setup.py install')
18
19
20    def execute(self, testdir = '', args = ''):
21        dirs = []
22        results = []
23        passed = 0
24        failed = 0
25
26        # spawn vncserver if needed
27        if not os.environ.has_key('DISPLAY'):
28            logging.info("No DISPLAY set in environment, spawning vncserver...")
29            display = self.__create_vncserver(os.path.expanduser("~/.vnc"))
30            logging.info("Setting DISPLAY=%s"%(display))
31            os.environ['DISPLAY'] = display
32
33        # build a list of dirs with 'vm.log' files
34        os.path.walk(testdir, self.__has_vmlog, dirs)
35
36        for d in dirs:
37            replaydir = os.path.join(self.resultsdir, os.path.basename(d))
38            os.mkdir(replaydir)
39            logfile = replaydir + "/%s.log" %(os.path.basename(d))
40
41            os.chdir(d)
42            rv = utils.system("kvm-test-replay > %s" %(logfile), 1)
43
44            results.append((d, rv))
45            if rv != 0:
46                screenshot = self.__get_expected_file(logfile)
47                expected = "expected-%03d.png" % random.randint(0, 999)
48                dest = os.path.join(replaydir,expected)
49
50                # make a copy of the screen shot
51                utils.system("cp %s %s" % (screenshot, dest), 1)
52
53                # move the failure
54                utils.system("mv failure-*.png %s" % replaydir, 1)
55
56        # generate html output
57        self.__format_results(results)
58
59        # produce pass/fail output
60        for (x, y) in results:
61            if y != 0:
62                logging.error("FAIL: '%s' with rv %s" % (x, y))
63                failed = failed + 1
64            else:
65                logging.info("PASS: '%s' with rv %s" % (x, y))
66                passed = passed + 1
67
68        logging.info("Summary: Passed %d Failed %d" % (passed, failed))
69        # if we had any tests not passed, fail entire test
70        if failed != 0:
71            raise error.TestError('kvm-test-replay')
72
73
74    def __get_expected_file(self, logfile):
75        # pull out screeshot name from logfile
76        return filter(lambda x: "Expected" in x,
77                      open(logfile, 'r').readlines())\
78                      [0].split('{')[1].split('}')[0]
79
80
81    def __create_vncserver(self, dirname):
82        """
83        this test may run without an X connection in kvm/qemu needs
84        a DISPLAY to push the vga buffer.  If a DISPLAY is not set
85        in the environment, then attempt to spawn a vncserver, and
86        change env DISPLAY so that kvmtest can run
87        """
88        for pidfile in utils.locate("*:*.pid", dirname):
89            pid = open(pidfile, 'r').readline().strip()
90            # if the server is still active, just use it for display
91            if os.path.exists('/proc/%s/status' % pid):
92                vncdisplay = os.path.basename(pidfile)\
93                               .split(":")[1].split(".")[0]
94                logging.info("Found vncserver on port %s, using it" % vncdisplay)
95                return ':%s.0' %(vncdisplay)
96
97        # none of the vncserver were still alive, spawn our own and
98        # return the display whack existing server first, then spawn it
99        vncdisplay = "1"
100        logging.info("Spawning vncserver on port %s" % vncdisplay)
101        utils.system('vncserver :%s' % vncdisplay)
102        return ':%s.0' % vncdisplay
103
104
105    def __has_vmlog(self, arg, dirname, names):
106        if os.path.exists(os.path.join(dirname, 'vm.log')):
107            arg.append(dirname)
108
109
110    def __gen_fail_html(self, testdir):
111        # generate a failure index.html to display the expected and failure
112        # images
113        fail_dir = os.path.join(self.resultsdir, os.path.basename(testdir))
114        fail_index = os.path.join(fail_dir, "index.html")
115
116        # lambda helpers for pulling out image files
117        is_png = lambda x: x.endswith('.png')
118        failure_filter = lambda x: x.startswith('failure') and is_png(x)
119        expected_filter = lambda x: x.startswith('expected') and is_png(x)
120
121        failure_img = filter(failure_filter, os.listdir(fail_dir))[0]
122        expected_img = filter(expected_filter, os.listdir(fail_dir))[0]
123        if not failure_img or not expected_img:
124            raise "Failed to find images"
125
126        fail_buff = "<html><table border=1><tr><th>Barrier Diff</th>\n" + \
127                 "<th>Expected Barrier</th><th>Failure</th></tr><tr><td></td>\n"
128        for img in expected_img, failure_img:
129            fail_buff = fail_buff + "<td><a href=\"%s\"><img width=320 " \
130                        "height=200 src=\"%s\"></a></td>\n" % (img, img)
131
132        fail_buff = fail_buff + "</tr></table></html>\n"
133
134        fh = open(fail_index, "w+")
135        fh.write(fail_buff)
136        fh.close()
137
138    def __format_results(self, results):
139        # generate kvmtest/index.html and an index.html for each fail
140        test_index = os.path.join(self.outputdir, "index.html")
141        test_buff = "<html><table border=1><tr><th>Test</th>\n"
142
143        for (x,y) in results:
144            test_buff = test_buff + "<th>%s</th>\n" % os.path.basename(x)
145
146        test_buff = test_buff + "</tr><tr><td></td>\n"
147
148        for (x,y) in results:
149            if y != 0:
150                fail = "<td><a href=\"results/%s/\">FAIL</a></td>\n" % os.path.basename(x)
151                test_buff = test_buff + fail
152                self.__gen_fail_html(x)
153            else:
154                test_buff = test_buff + "<td>GOOD</td>\n"
155
156        test_buff = test_buff + "</tr></table></html>"
157
158        fh = open(test_index, "w+")
159        fh.write(test_buff)
160        fh.close()
161