test_basic.py 55.9 KB
Newer Older
1
# This Python file uses the following encoding: utf-8
2 3
import aexpect
import glob
4
import json
5
import os
6
import re
7
import shutil
8
import signal
9
import sys
10
import tempfile
11
import time
12
import xml.dom.minidom
13
import zipfile
14
import unittest
15
import psutil
16
import pkg_resources
17

18 19 20
from lxml import etree
from StringIO import StringIO

21
from avocado.core import exit_codes
22
from avocado.utils import astring
23 24
from avocado.utils import process
from avocado.utils import script
25
from avocado.utils import path as utils_path
26

27
basedir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..')
28 29
basedir = os.path.abspath(basedir)

30 31
AVOCADO = os.environ.get("UNITTEST_AVOCADO_CMD", "./scripts/avocado")

32 33 34 35
PASS_SCRIPT_CONTENTS = """#!/bin/sh
true
"""

C
Cleber Rosa 已提交
36 37
PASS_SHELL_CONTENTS = "exit 0"

38 39 40 41
FAIL_SCRIPT_CONTENTS = """#!/bin/sh
false
"""

C
Cleber Rosa 已提交
42 43
FAIL_SHELL_CONTENTS = "exit 1"

44 45 46 47 48 49 50 51 52 53 54 55 56 57
HELLO_LIB_CONTENTS = """
def hello():
    return 'Hello world'
"""

LOCAL_IMPORT_TEST_CONTENTS = '''
from avocado import Test
from mylib import hello

class LocalImportTest(Test):
    def test(self):
        self.log.info(hello())
'''

58 59 60 61 62 63
UNSUPPORTED_STATUS_TEST_CONTENTS = '''
from avocado import Test

class FakeStatusTest(Test):
    def run_avocado(self):
        super(FakeStatusTest, self).run_avocado()
64 65
        # Please do NOT ever use this, it's for unittesting only.
        self._Test__status = 'not supported'
66 67 68 69 70

    def test(self):
        pass
'''

71 72 73 74 75 76 77 78 79 80 81
INVALID_PYTHON_TEST = '''
from avocado import Test

class MyTest(Test):

    non_existing_variable_causing_crash

    def test_my_name(self):
        pass
'''

82

83 84 85 86 87 88 89 90 91 92 93 94
VALID_PYTHON_TEST_WITH_TAGS = '''
from avocado import Test

class MyTest(Test):
    def test(self):
         """
         :avocado: tags=BIG_TAG_NAME
         """
         pass
'''


95 96 97 98 99 100 101
REPORTS_STATUS_AND_HANG = '''
from avocado import Test
import time

class MyTest(Test):
    def test(self):
         self.runner_queue.put({"running": False})
102
         time.sleep(70)
103 104
'''

105

106 107 108 109 110 111 112 113 114 115 116
DIE_WITHOUT_REPORTING_STATUS = '''
from avocado import Test
import os
import signal

class MyTest(Test):
    def test(self):
         os.kill(os.getpid(), signal.SIGKILL)
'''


A
Amador Pahim 已提交
117
def probe_binary(binary):
118
    try:
A
Amador Pahim 已提交
119
        return utils_path.find_command(binary)
120
    except utils_path.CmdNotFoundError:
A
Amador Pahim 已提交
121 122
        return None

L
Lukáš Doktor 已提交
123

124
TRUE_CMD = probe_binary('true')
A
Amador Pahim 已提交
125
CC_BINARY = probe_binary('cc')
126

L
Lukáš Doktor 已提交
127
# On macOS, the default GNU core-utils installation (brew)
128 129 130 131 132
# installs the gnu utility versions with a g prefix. It still has the
# BSD versions of the core utilities installed on their expected paths
# but their behavior and flags are in most cases different.
GNU_ECHO_BINARY = probe_binary('echo')
if GNU_ECHO_BINARY is not None:
133 134 135 136
    if probe_binary('man') is not None:
        echo_manpage = process.run('man %s' % os.path.basename(GNU_ECHO_BINARY)).stdout
        if '-e' not in echo_manpage:
            GNU_ECHO_BINARY = probe_binary('gecho')
A
Amador Pahim 已提交
137 138
READ_BINARY = probe_binary('read')
SLEEP_BINARY = probe_binary('sleep')
139 140


141 142
class RunnerOperationTest(unittest.TestCase):

143
    def setUp(self):
144
        self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
145

146
    def test_show_version(self):
147
        result = process.run('%s -v' % AVOCADO, ignore_status=True)
148
        self.assertEqual(result.exit_status, 0)
C
Cleber Rosa 已提交
149 150 151
        self.assertTrue(re.match(r"^Avocado \d+\.\d+$", result.stderr),
                        "Version string does not match 'Avocado \\d\\.\\d:'\n"
                        "%r" % (result.stderr))
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    def test_alternate_config_datadir(self):
        """
        Uses the "--config" flag to check custom configuration is applied

        Even on the more complex data_dir module, which adds extra checks
        to what is set on the plain settings module.
        """
        base_dir = os.path.join(self.tmpdir, 'datadir_base')
        os.mkdir(base_dir)
        mapping = {'base_dir': base_dir,
                   'test_dir': os.path.join(base_dir, 'test'),
                   'data_dir': os.path.join(base_dir, 'data'),
                   'logs_dir': os.path.join(base_dir, 'logs')}
        config = '[datadir.paths]'
        for key, value in mapping.iteritems():
            if not os.path.isdir(value):
                os.mkdir(value)
            config += "%s = %s\n" % (key, value)
        fd, config_file = tempfile.mkstemp(dir=self.tmpdir)
        os.write(fd, config)
        os.close(fd)

        os.chdir(basedir)
176
        cmd = '%s --config %s config --datadir' % (AVOCADO, config_file)
177 178 179 180 181 182 183 184 185 186
        result = process.run(cmd)
        output = result.stdout
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertIn('    base     ' + mapping['base_dir'], result.stdout)
        self.assertIn('    data     ' + mapping['data_dir'], result.stdout)
        self.assertIn('    logs     ' + mapping['logs_dir'], result.stdout)

187 188
    def test_runner_all_ok(self):
        os.chdir(basedir)
189 190
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'passtest.py passtest.py' % (AVOCADO, self.tmpdir))
191 192
        process.run(cmd_line)

193 194
    def test_runner_failfast(self):
        os.chdir(basedir)
195 196 197
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'passtest.py failtest.py passtest.py --failfast on'
                    % (AVOCADO, self.tmpdir))
198 199 200 201 202 203 204
        result = process.run(cmd_line, ignore_status=True)
        self.assertIn('Interrupting job (failfast).', result.stdout)
        self.assertIn('PASS 1 | ERROR 0 | FAIL 1 | SKIP 1', result.stdout)
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL | exit_codes.AVOCADO_JOB_INTERRUPTED
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

A
Amador Pahim 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    def test_runner_ignore_missing_references_one_missing(self):
        os.chdir(basedir)
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'passtest.py badtest.py --ignore-missing-references on'
                    % (AVOCADO, self.tmpdir))
        result = process.run(cmd_line, ignore_status=True)
        self.assertIn("Unable to resolve reference(s) 'badtest.py'", result.stderr)
        self.assertIn('PASS 1 | ERROR 0 | FAIL 0 | SKIP 0', result.stdout)
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

    def test_runner_ignore_missing_references_all_missing(self):
        os.chdir(basedir)
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'badtest.py badtest2.py --ignore-missing-references on'
                    % (AVOCADO, self.tmpdir))
        result = process.run(cmd_line, ignore_status=True)
        self.assertIn("Unable to resolve reference(s) 'badtest.py', 'badtest2.py'",
                      result.stderr)
        self.assertEqual('', result.stdout)
        expected_rc = exit_codes.AVOCADO_JOB_FAIL
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

A
Amador Pahim 已提交
230
    @unittest.skipIf(not CC_BINARY,
231
                     "C compiler is required by the underlying datadir.py test")
232 233
    def test_datadir_alias(self):
        os.chdir(basedir)
234 235
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'datadir.py' % (AVOCADO, self.tmpdir))
236 237 238 239 240
        process.run(cmd_line)

    def test_shell_alias(self):
        """ Tests that .sh files are also executable via alias """
        os.chdir(basedir)
241 242
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'env_variables.sh' % (AVOCADO, self.tmpdir))
243 244
        process.run(cmd_line)

A
Amador Pahim 已提交
245
    @unittest.skipIf(not CC_BINARY,
246
                     "C compiler is required by the underlying datadir.py test")
247 248
    def test_datadir_noalias(self):
        os.chdir(basedir)
249 250
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s examples/tests/datadir.py '
                    'examples/tests/datadir.py' % (AVOCADO, self.tmpdir))
251 252
        process.run(cmd_line)

253 254
    def test_runner_noalias(self):
        os.chdir(basedir)
255 256
        cmd_line = ("%s run --sysinfo=off --job-results-dir %s examples/tests/passtest.py "
                    "examples/tests/passtest.py" % (AVOCADO, self.tmpdir))
257 258
        process.run(cmd_line)

259 260 261 262 263 264 265 266 267 268 269
    def test_runner_test_with_local_imports(self):
        mylib = script.TemporaryScript(
            'mylib.py',
            HELLO_LIB_CONTENTS,
            'avocado_simpletest_functional')
        mylib.save()
        mytest = script.Script(
            os.path.join(os.path.dirname(mylib.path), 'test_local_imports.py'),
            LOCAL_IMPORT_TEST_CONTENTS)
        os.chdir(basedir)
        mytest.save()
270 271
        cmd_line = ("%s run --sysinfo=off --job-results-dir %s "
                    "%s" % (AVOCADO, self.tmpdir, mytest))
272 273
        process.run(cmd_line)

274 275 276 277 278
    def test_unsupported_status(self):
        os.chdir(basedir)
        with script.TemporaryScript("fake_status.py",
                                    UNSUPPORTED_STATUS_TEST_CONTENTS,
                                    "avocado_unsupported_status") as tst:
279 280 281
            res = process.run("%s run --sysinfo=off --job-results-dir %s %s"
                              " --json -" % (AVOCADO, self.tmpdir, tst),
                              ignore_status=True)
282 283 284 285 286
            self.assertEqual(res.exit_status, exit_codes.AVOCADO_TESTS_FAIL)
            results = json.loads(res.stdout)
            self.assertEqual(results["tests"][0]["status"], "ERROR",
                             "%s != %s\n%s" % (results["tests"][0]["status"],
                                               "ERROR", res))
287
            self.assertIn("Runner error occurred: Test reports unsupported",
288 289
                          results["tests"][0]["fail_reason"])

290 291 292
    @unittest.skipIf(int(os.environ.get("AVOCADO_CHECK_LEVEL", 0)) < 1,
                     "Skipping test that take a long time to run, are "
                     "resource intensive or time sensitve")
293 294 295 296 297 298
    def test_hanged_test_with_status(self):
        """ Check that avocado handles hanged tests properly """
        os.chdir(basedir)
        with script.TemporaryScript("report_status_and_hang.py",
                                    REPORTS_STATUS_AND_HANG,
                                    "hanged_test_with_status") as tst:
299
            res = process.run("%s run --sysinfo=off --job-results-dir %s %s "
300
                              "--json - --job-timeout 1" % (AVOCADO, self.tmpdir, tst),
301
                              ignore_status=True)
302 303 304 305 306 307 308
            self.assertEqual(res.exit_status, exit_codes.AVOCADO_TESTS_FAIL)
            results = json.loads(res.stdout)
            self.assertEqual(results["tests"][0]["status"], "ERROR",
                             "%s != %s\n%s" % (results["tests"][0]["status"],
                                               "ERROR", res))
            self.assertIn("Test reported status but did not finish",
                          results["tests"][0]["fail_reason"])
309 310 311 312 313
            # Currently it should finish up to 1s after the job-timeout
            # but the prep and postprocess could take a bit longer on
            # some environments, so let's just check it does not take
            # > 60s, which is the deadline for force-finishing the test.
            self.assertLess(res.duration, 55, "Test execution took too long, "
314 315 316 317 318 319 320 321
                            "which is likely because the hanged test was not "
                            "interrupted. Results:\n%s" % res)

    def test_no_status_reported(self):
        os.chdir(basedir)
        with script.TemporaryScript("die_without_reporting_status.py",
                                    DIE_WITHOUT_REPORTING_STATUS,
                                    "no_status_reported") as tst:
322 323 324
            res = process.run("%s run --sysinfo=off --job-results-dir %s %s "
                              "--json -" % (AVOCADO, self.tmpdir, tst),
                              ignore_status=True)
325 326 327 328 329 330 331 332
            self.assertEqual(res.exit_status, exit_codes.AVOCADO_TESTS_FAIL)
            results = json.loads(res.stdout)
            self.assertEqual(results["tests"][0]["status"], "ERROR",
                             "%s != %s\n%s" % (results["tests"][0]["status"],
                                               "ERROR", res))
            self.assertIn("Test died without reporting the status",
                          results["tests"][0]["fail_reason"])

333 334
    def test_runner_tests_fail(self):
        os.chdir(basedir)
335 336
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s passtest.py '
                    'failtest.py passtest.py' % (AVOCADO, self.tmpdir))
337
        result = process.run(cmd_line, ignore_status=True)
338
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
339 340 341 342 343
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

    def test_runner_nonexistent_test(self):
        os.chdir(basedir)
344 345
        cmd_line = ('%s run --sysinfo=off --job-results-dir '
                    '%s bogustest' % (AVOCADO, self.tmpdir))
346
        result = process.run(cmd_line, ignore_status=True)
347 348
        expected_rc = exit_codes.AVOCADO_JOB_FAIL
        unexpected_rc = exit_codes.AVOCADO_FAIL
349 350 351 352 353
        self.assertNotEqual(result.exit_status, unexpected_rc,
                            "Avocado crashed (rc %d):\n%s" % (unexpected_rc, result))
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

354 355
    def test_runner_doublefail(self):
        os.chdir(basedir)
356 357
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    '--xunit - doublefail.py' % (AVOCADO, self.tmpdir))
358 359
        result = process.run(cmd_line, ignore_status=True)
        output = result.stdout
360 361
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
        unexpected_rc = exit_codes.AVOCADO_FAIL
362 363 364 365
        self.assertNotEqual(result.exit_status, unexpected_rc,
                            "Avocado crashed (rc %d):\n%s" % (unexpected_rc, result))
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))
366
        self.assertIn("TestError: Failing during tearDown. Yay!", output,
367
                      "Cleanup exception not printed to log output")
368
        self.assertIn("TestFail: This test is supposed to fail",
369
                      output,
370
                      "Test did not fail with action exception:\n%s" % output)
371

372 373
    def test_uncaught_exception(self):
        os.chdir(basedir)
374 375
        cmd_line = ("%s run --sysinfo=off --job-results-dir %s "
                    "--json - uncaught_exception.py" % (AVOCADO, self.tmpdir))
376
        result = process.run(cmd_line, ignore_status=True)
377
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
378 379 380 381 382
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc,
                                                                result))
        self.assertIn('"status": "ERROR"', result.stdout)

383
    def test_fail_on_exception(self):
384
        os.chdir(basedir)
385 386
        cmd_line = ("%s run --sysinfo=off --job-results-dir %s "
                    "--json - fail_on_exception.py" % (AVOCADO, self.tmpdir))
387
        result = process.run(cmd_line, ignore_status=True)
388
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
389 390 391 392 393
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc,
                                                                result))
        self.assertIn('"status": "FAIL"', result.stdout)

394 395
    def test_runner_timeout(self):
        os.chdir(basedir)
396 397
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    '--xunit - timeouttest.py' % (AVOCADO, self.tmpdir))
398 399
        result = process.run(cmd_line, ignore_status=True)
        output = result.stdout
400
        expected_rc = exit_codes.AVOCADO_JOB_INTERRUPTED
401
        unexpected_rc = exit_codes.AVOCADO_FAIL
402 403 404 405
        self.assertNotEqual(result.exit_status, unexpected_rc,
                            "Avocado crashed (rc %d):\n%s" % (unexpected_rc, result))
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))
406
        self.assertIn("Runner error occurred: Timeout reached", output,
407
                      "Timeout reached message not found in the output:\n%s" % output)
408 409
        # Ensure no test aborted error messages show up
        self.assertNotIn("TestAbortedError: Test aborted unexpectedly", output)
410

411
    @unittest.skipIf(int(os.environ.get("AVOCADO_CHECK_LEVEL", 0)) < 2,
412 413
                     "Skipping test that take a long time to run, are "
                     "resource intensive or time sensitve")
414 415
    def test_runner_abort(self):
        os.chdir(basedir)
416 417
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    '--xunit - abort.py' % (AVOCADO, self.tmpdir))
418
        result = process.run(cmd_line, ignore_status=True)
419
        output = result.stdout
420
        excerpt = 'Test died without reporting the status.'
421 422
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
        unexpected_rc = exit_codes.AVOCADO_FAIL
423 424 425 426
        self.assertNotEqual(result.exit_status, unexpected_rc,
                            "Avocado crashed (rc %d):\n%s" % (unexpected_rc, result))
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))
427
        self.assertIn(excerpt, output)
428

429 430
    def test_silent_output(self):
        os.chdir(basedir)
431 432
        cmd_line = ('%s --silent run --sysinfo=off --job-results-dir %s '
                    'passtest.py' % (AVOCADO, self.tmpdir))
433
        result = process.run(cmd_line, ignore_status=True)
434
        expected_rc = exit_codes.AVOCADO_ALL_OK
435 436
        expected_output = ''
        self.assertEqual(result.exit_status, expected_rc)
437
        self.assertEqual(result.stdout, expected_output)
438

439 440
    def test_empty_args_list(self):
        os.chdir(basedir)
441
        cmd_line = AVOCADO
442
        result = process.run(cmd_line, ignore_status=True)
443
        expected_rc = exit_codes.AVOCADO_FAIL
444
        expected_output = 'error: too few arguments'
445
        self.assertEqual(result.exit_status, expected_rc)
446
        self.assertIn(expected_output, result.stderr)
447

448 449
    def test_empty_test_list(self):
        os.chdir(basedir)
450 451
        cmd_line = '%s run --sysinfo=off --job-results-dir %s' % (AVOCADO,
                                                                  self.tmpdir)
452
        result = process.run(cmd_line, ignore_status=True)
453
        expected_rc = exit_codes.AVOCADO_JOB_FAIL
454 455
        expected_output = ('No test references provided nor any other '
                           'arguments resolved into tests')
456
        self.assertEqual(result.exit_status, expected_rc)
457
        self.assertIn(expected_output, result.stderr)
458

459 460
    def test_not_found(self):
        os.chdir(basedir)
461 462
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s sbrubles'
                    % (AVOCADO, self.tmpdir))
463
        result = process.run(cmd_line, ignore_status=True)
464
        expected_rc = exit_codes.AVOCADO_JOB_FAIL
465
        self.assertEqual(result.exit_status, expected_rc)
466 467
        self.assertIn('Unable to resolve reference', result.stderr)
        self.assertNotIn('Unable to resolve reference', result.stdout)
468

469
    def test_invalid_unique_id(self):
470 471
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s --force-job-id '
                    'foobar passtest.py' % (AVOCADO, self.tmpdir))
472
        result = process.run(cmd_line, ignore_status=True)
473
        self.assertNotEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK)
474
        self.assertIn('needs to be a 40 digit hex', result.stderr)
475
        self.assertNotIn('needs to be a 40 digit hex', result.stdout)
476 477

    def test_valid_unique_id(self):
478
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
479
                    '--force-job-id 975de258ac05ce5e490648dec4753657b7ccc7d1 '
480
                    'passtest.py' % (AVOCADO, self.tmpdir))
481
        result = process.run(cmd_line, ignore_status=True)
482
        self.assertEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK)
483
        self.assertNotIn('needs to be a 40 digit hex', result.stderr)
484
        self.assertIn('PASS', result.stdout)
485

486
    def test_automatic_unique_id(self):
487 488
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
                    'passtest.py --json -' % (AVOCADO, self.tmpdir))
489
        result = process.run(cmd_line, ignore_status=True)
490
        self.assertEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK)
491 492 493 494
        r = json.loads(result.stdout)
        int(r['job_id'], 16)  # it's an hex number
        self.assertEqual(len(r['job_id']), 40)

495 496 497 498 499
    def test_early_latest_result(self):
        """
        Tests that the `latest` link to the latest job results is created early
        """
        os.chdir(basedir)
500 501
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'examples/tests/passtest.py' % (AVOCADO, self.tmpdir))
502 503 504 505 506 507
        avocado_process = process.SubProcess(cmd_line)
        avocado_process.start()
        link = os.path.join(self.tmpdir, 'latest')
        for trial in xrange(0, 50):
            time.sleep(0.1)
            if os.path.exists(link) and os.path.islink(link):
508
                avocado_process.wait()
509 510 511 512
                break
        self.assertTrue(os.path.exists(link))
        self.assertTrue(os.path.islink(link))

513 514
    def test_dry_run(self):
        os.chdir(basedir)
515
        cmd = ("%s run --sysinfo=off passtest.py failtest.py "
516
               "gendata.py --json - --mux-inject foo:1 bar:2 baz:3 foo:foo:a"
517
               " foo:bar:b foo:baz:c bar:bar:bar --dry-run" % AVOCADO)
518 519 520 521 522
        result = json.loads(process.run(cmd).stdout)
        debuglog = result['debuglog']
        log = open(debuglog, 'r').read()
        # Remove the result dir
        shutil.rmtree(os.path.dirname(os.path.dirname(debuglog)))
523
        self.assertIn(tempfile.gettempdir(), debuglog)   # Use tmp dir, not default location
524 525
        self.assertEqual(result['job_id'], u'0' * 40)
        # Check if all tests were skipped
526
        self.assertEqual(result['cancel'], 4)
527
        for i in xrange(4):
528 529
            test = result['tests'][i]
            self.assertEqual(test['fail_reason'],
530
                             u'Test cancelled due to --dry-run')
531 532 533 534 535
        # Check if all params are listed
        # The "/:bar ==> 2 is in the tree, but not in any leave so inaccessible
        # from test.
        for line in ("/:foo ==> 1", "/:baz ==> 3", "/foo:foo ==> a",
                     "/foo:bar ==> b", "/foo:baz ==> c", "/bar:bar ==> bar"):
536
            self.assertEqual(log.count(line), 4)
537

538 539 540 541
    def test_invalid_python(self):
        os.chdir(basedir)
        test = script.make_script(os.path.join(self.tmpdir, 'test.py'),
                                  INVALID_PYTHON_TEST)
542 543
        cmd_line = ('%s --show test run --sysinfo=off '
                    '--job-results-dir %s %s') % (AVOCADO, self.tmpdir, test)
544 545 546 547 548
        result = process.run(cmd_line, ignore_status=True)
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
549 550
        self.assertIn('1-%s:MyTest.test_my_name -> TestError' % test,
                      result.stdout)
551

A
Amador Pahim 已提交
552
    @unittest.skipIf(not READ_BINARY, "read binary not available.")
553 554 555
    @unittest.skipIf(int(os.environ.get("AVOCADO_CHECK_LEVEL", 0)) < 1,
                     "Skipping test that take a long time to run, are "
                     "resource intensive or time sensitve")
L
Lukáš Doktor 已提交
556 557
    def test_read(self):
        os.chdir(basedir)
558
        cmd = "%s run --sysinfo=off --job-results-dir %%s %%s" % AVOCADO
559
        cmd %= (self.tmpdir, READ_BINARY)
560
        result = process.run(cmd, timeout=10, ignore_status=True)
L
Lukáš Doktor 已提交
561 562 563 564 565
        self.assertLess(result.duration, 8, "Duration longer than expected."
                        "\n%s" % result)
        self.assertEqual(result.exit_status, 1, "Expected exit status is 1\n%s"
                         % result)

566 567 568
    def tearDown(self):
        shutil.rmtree(self.tmpdir)

569

570 571 572
class RunnerHumanOutputTest(unittest.TestCase):

    def setUp(self):
573
        self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
574 575 576

    def test_output_pass(self):
        os.chdir(basedir)
577 578
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'passtest.py' % (AVOCADO, self.tmpdir))
579
        result = process.run(cmd_line, ignore_status=True)
580
        expected_rc = exit_codes.AVOCADO_ALL_OK
581 582 583 584 585 586 587
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertIn('passtest.py:PassTest.test:  PASS', result.stdout)

    def test_output_fail(self):
        os.chdir(basedir)
588 589
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'failtest.py' % (AVOCADO, self.tmpdir))
590
        result = process.run(cmd_line, ignore_status=True)
591
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
592 593 594 595 596 597 598
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertIn('failtest.py:FailTest.test:  FAIL', result.stdout)

    def test_output_error(self):
        os.chdir(basedir)
599 600
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'errortest.py' % (AVOCADO, self.tmpdir))
601
        result = process.run(cmd_line, ignore_status=True)
602
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
603 604 605 606 607
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertIn('errortest.py:ErrorTest.test:  ERROR', result.stdout)

A
Amador Pahim 已提交
608
    def test_output_cancel(self):
609
        os.chdir(basedir)
610 611
        cmd_line = ('%s run --sysinfo=off --job-results-dir %s '
                    'cancelonsetup.py' % (AVOCADO, self.tmpdir))
612
        result = process.run(cmd_line, ignore_status=True)
613
        expected_rc = exit_codes.AVOCADO_ALL_OK
614 615 616
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
A
Amador Pahim 已提交
617 618
        self.assertIn('PASS 0 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 1',
                      result.stdout)
619

620 621
    @unittest.skipIf(not GNU_ECHO_BINARY,
                     'GNU style echo binary not available')
622 623
    def test_ugly_echo_cmd(self):
        os.chdir(basedir)
624
        cmd_line = ('%s run --external-runner "%s -ne" '
625
                    '"foo\\\\\\n\\\'\\\\\\"\\\\\\nbar/baz" --job-results-dir %s'
A
Amador Pahim 已提交
626
                    ' --sysinfo=off  --show-job-log' %
627
                    (AVOCADO, GNU_ECHO_BINARY, self.tmpdir))
628 629 630 631 632
        result = process.run(cmd_line, ignore_status=True)
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %s:\n%s" %
                         (expected_rc, result))
633 634 635
        self.assertIn('[stdout] foo', result.stdout, result)
        self.assertIn('[stdout] \'"', result.stdout, result)
        self.assertIn('[stdout] bar/baz', result.stdout, result)
636 637
        self.assertIn('PASS 1-foo\\\\n\\\'\\"\\\\nbar/baz',
                      result.stdout, result)
638 639 640 641 642 643 644
        # logdir name should escape special chars (/)
        test_dirs = glob.glob(os.path.join(self.tmpdir, 'latest',
                                           'test-results', '*'))
        self.assertEqual(len(test_dirs), 1, "There are multiple directories in"
                         " test-results dir, but only one test was executed: "
                         "%s" % (test_dirs))
        self.assertEqual(os.path.basename(test_dirs[0]),
645
                         '1-foo\\\\n\\\'\\"\\\\nbar_baz')
646

647
    def test_replay_skip_skipped(self):
648 649
        cmd = ("%s run --job-results-dir %s --json - "
               "cancelonsetup.py" % (AVOCADO, self.tmpdir))
650
        result = process.run(cmd)
651
        result = json.loads(result.stdout)
652
        jobid = str(result["job_id"])
653 654
        cmd = ("%s run --job-results-dir %s --replay %s "
               "--replay-test-status PASS" % (AVOCADO, self.tmpdir, jobid))
655
        process.run(cmd)
656

657 658 659
    def tearDown(self):
        shutil.rmtree(self.tmpdir)

660

661
class RunnerSimpleTest(unittest.TestCase):
662 663

    def setUp(self):
664
        self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
665
        self.pass_script = script.TemporaryScript(
666
            'ʊʋʉʈɑ ʅʛʌ',
667
            PASS_SCRIPT_CONTENTS,
668
            'avocado_simpletest_functional')
669
        self.pass_script.save()
L
Lukáš Doktor 已提交
670 671 672 673
        self.fail_script = script.TemporaryScript('avocado_fail.sh',
                                                  FAIL_SCRIPT_CONTENTS,
                                                  'avocado_simpletest_'
                                                  'functional')
674
        self.fail_script.save()
675

676
    def test_simpletest_pass(self):
677
        os.chdir(basedir)
678 679
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off'
                    ' "%s"' % (AVOCADO, self.tmpdir, self.pass_script.path))
680
        result = process.run(cmd_line, ignore_status=True)
681
        expected_rc = exit_codes.AVOCADO_ALL_OK
682 683 684 685
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

686
    def test_simpletest_fail(self):
687
        os.chdir(basedir)
688 689
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off'
                    ' %s' % (AVOCADO, self.tmpdir, self.fail_script.path))
690
        result = process.run(cmd_line, ignore_status=True)
691
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
692 693 694 695
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

696
    @unittest.skipIf(int(os.environ.get("AVOCADO_CHECK_LEVEL", 0)) < 2,
697 698
                     "Skipping test that take a long time to run, are "
                     "resource intensive or time sensitve")
699 700
    def test_runner_onehundred_fail_timing(self):
        """
A
Amador Pahim 已提交
701
        We can be pretty sure that a failtest should return immediately. Let's
702
        run 100 of them and assure they not take more than 30 seconds to run.
703

704 705
        Notice: on a current machine this takes about 0.12s, so 30 seconds is
        considered to be pretty safe here.
706 707
        """
        os.chdir(basedir)
708
        one_hundred = 'failtest.py ' * 100
709 710
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off %s'
                    % (AVOCADO, self.tmpdir, one_hundred))
711 712 713
        initial_time = time.time()
        result = process.run(cmd_line, ignore_status=True)
        actual_time = time.time() - initial_time
714
        self.assertLess(actual_time, 30.0)
715
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
716 717 718
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

719 720 721
    @unittest.skipIf(int(os.environ.get("AVOCADO_CHECK_LEVEL", 0)) < 1,
                     "Skipping test that take a long time to run, are "
                     "resource intensive or time sensitve")
722 723 724 725 726 727
    def test_runner_sleep_fail_sleep_timing(self):
        """
        Sleeptest is supposed to take 1 second, let's make a sandwich of
        100 failtests and check the test runner timing.
        """
        os.chdir(basedir)
728 729
        sleep_fail_sleep = ('sleeptest.py ' + 'failtest.py ' * 100 +
                            'sleeptest.py')
730 731
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off %s'
                    % (AVOCADO, self.tmpdir, sleep_fail_sleep))
732 733 734
        initial_time = time.time()
        result = process.run(cmd_line, ignore_status=True)
        actual_time = time.time() - initial_time
735
        self.assertLess(actual_time, 33.0)
736
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
737 738 739
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" % (expected_rc, result))

740 741 742 743 744
    def test_simplewarning(self):
        """
        simplewarning.sh uses the avocado-bash-utils
        """
        os.chdir(basedir)
745 746 747
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
                    'examples/tests/simplewarning.sh --show-job-log'
                    % (AVOCADO, self.tmpdir))
748
        result = process.run(cmd_line, ignore_status=True)
749 750 751 752
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %s:\n%s" %
                         (expected_rc, result))
753 754
        self.assertIn('DEBUG| Debug message', result.stdout, result)
        self.assertIn('INFO | Info message', result.stdout, result)
755
        self.assertIn('WARN | Warning message (should cause this test to '
756
                      'finish with warning)', result.stdout, result)
757
        self.assertIn('ERROR| Error message (ordinary message not changing '
758
                      'the results)', result.stdout, result)
759

760 761 762 763 764 765
    def test_non_absolute_path(self):
        avocado_path = os.path.join(basedir, 'scripts', 'avocado')
        test_base_dir = os.path.dirname(self.pass_script.path)
        test_file_name = os.path.basename(self.pass_script.path)
        os.chdir(test_base_dir)
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off'
766
                    ' "%s"' % (avocado_path, self.tmpdir, test_file_name))
767 768 769 770 771 772
        result = process.run(cmd_line, ignore_status=True)
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

A
Amador Pahim 已提交
773
    @unittest.skipIf(not SLEEP_BINARY, 'sleep binary not available')
774 775 776
    @unittest.skipIf(int(os.environ.get("AVOCADO_CHECK_LEVEL", 0)) < 1,
                     "Skipping test that take a long time to run, are "
                     "resource intensive or time sensitve")
777
    def test_kill_stopped_sleep(self):
778 779 780 781
        proc = aexpect.Expect("%s run 60 --job-results-dir %s "
                              "--external-runner %s --sysinfo=off "
                              "--job-timeout 3"
                              % (AVOCADO, self.tmpdir, SLEEP_BINARY))
782 783
        proc.read_until_output_matches(["\(1/1\)"], timeout=3,
                                       internal_timeout=0.01)
784 785 786 787
        # We need pid of the avocado process, not the shell executing it
        avocado_shell = psutil.Process(proc.get_pid())
        avocado_proc = avocado_shell.children()[0]
        pid = avocado_proc.pid
788
        os.kill(pid, signal.SIGTSTP)   # This freezes the process
789
        deadline = time.time() + 9
790 791 792
        while time.time() < deadline:
            if not proc.is_alive():
                break
793
            time.sleep(0.1)
794 795
        else:
            proc.kill(signal.SIGKILL)
796
            self.fail("Avocado process still alive 5s after job-timeout:\n%s"
797 798 799 800 801 802 803
                      % proc.get_output())
        output = proc.get_output()
        self.assertIn("ctrl+z pressed, stopping test", output, "SIGTSTP "
                      "message not in the output, test was probably not "
                      "stopped.")
        self.assertIn("TIME", output, "TIME not in the output, avocado "
                      "probably died unexpectadly")
804
        self.assertEqual(proc.get_status(), 8, "Avocado did not finish with "
805
                         "1.")
806 807

        sleep_dir = astring.string_to_safe_path("1-60")
808
        debug_log = os.path.join(self.tmpdir, "latest", "test-results",
809
                                 sleep_dir, "debug.log")
810
        debug_log = open(debug_log).read()
811 812 813 814 815 816 817
        self.assertIn("Runner error occurred: Timeout reached", debug_log,
                      "Runner error occurred: Timeout reached message not "
                      "in the test's debug.log:\n%s" % debug_log)
        self.assertNotIn("Traceback (most recent", debug_log, "Traceback "
                         "present in the test's debug.log file, but it was "
                         "suppose to be stopped and unable to produce it.\n"
                         "%s" % debug_log)
818

819
    def tearDown(self):
820 821
        self.pass_script.remove()
        self.fail_script.remove()
822
        shutil.rmtree(self.tmpdir)
823 824


825
class ExternalRunnerTest(unittest.TestCase):
C
Cleber Rosa 已提交
826 827

    def setUp(self):
828
        self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
C
Cleber Rosa 已提交
829 830 831
        self.pass_script = script.TemporaryScript(
            'pass',
            PASS_SHELL_CONTENTS,
832
            'avocado_externalrunner_functional')
C
Cleber Rosa 已提交
833 834 835 836
        self.pass_script.save()
        self.fail_script = script.TemporaryScript(
            'fail',
            FAIL_SHELL_CONTENTS,
837
            'avocado_externalrunner_functional')
C
Cleber Rosa 已提交
838 839
        self.fail_script.save()

840
    def test_externalrunner_pass(self):
C
Cleber Rosa 已提交
841
        os.chdir(basedir)
842 843 844
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
                    '--external-runner=/bin/sh %s'
                    % (AVOCADO, self.tmpdir, self.pass_script.path))
C
Cleber Rosa 已提交
845
        result = process.run(cmd_line, ignore_status=True)
846
        expected_rc = exit_codes.AVOCADO_ALL_OK
C
Cleber Rosa 已提交
847 848 849 850
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

851
    def test_externalrunner_fail(self):
C
Cleber Rosa 已提交
852
        os.chdir(basedir)
853 854 855
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
                    '--external-runner=/bin/sh %s'
                    % (AVOCADO, self.tmpdir, self.fail_script.path))
C
Cleber Rosa 已提交
856
        result = process.run(cmd_line, ignore_status=True)
857
        expected_rc = exit_codes.AVOCADO_TESTS_FAIL
C
Cleber Rosa 已提交
858 859 860 861
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

862
    def test_externalrunner_chdir_no_testdir(self):
C
Cleber Rosa 已提交
863
        os.chdir(basedir)
864 865 866
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
                    '--external-runner=/bin/sh --external-runner-chdir=test %s'
                    % (AVOCADO, self.tmpdir, self.pass_script.path))
C
Cleber Rosa 已提交
867
        result = process.run(cmd_line, ignore_status=True)
868 869
        expected_output = ('Option "--external-runner-chdir=test" requires '
                           '"--external-runner-testdir" to be set')
C
Cleber Rosa 已提交
870
        self.assertIn(expected_output, result.stderr)
871
        expected_rc = exit_codes.AVOCADO_JOB_FAIL
872 873 874 875 876 877
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

    def test_externalrunner_no_url(self):
        os.chdir(basedir)
878 879
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off '
                    '--external-runner=%s' % (AVOCADO, self.tmpdir, TRUE_CMD))
880
        result = process.run(cmd_line, ignore_status=True)
881 882
        expected_output = ('No test references provided nor any other '
                           'arguments resolved into tests')
883 884
        self.assertIn(expected_output, result.stderr)
        expected_rc = exit_codes.AVOCADO_JOB_FAIL
C
Cleber Rosa 已提交
885 886 887 888 889 890 891 892 893 894
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))

    def tearDown(self):
        self.pass_script.remove()
        self.fail_script.remove()
        shutil.rmtree(self.tmpdir)


895
class AbsPluginsTest(object):
896

897
    def setUp(self):
898
        self.base_outputdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
899

900 901 902 903 904 905
    def tearDown(self):
        shutil.rmtree(self.base_outputdir)


class PluginsTest(AbsPluginsTest, unittest.TestCase):

906 907
    def test_sysinfo_plugin(self):
        os.chdir(basedir)
908
        cmd_line = '%s sysinfo %s' % (AVOCADO, self.base_outputdir)
909
        result = process.run(cmd_line, ignore_status=True)
910
        expected_rc = exit_codes.AVOCADO_ALL_OK
911 912 913 914 915 916
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        sysinfo_files = os.listdir(self.base_outputdir)
        self.assertGreater(len(sysinfo_files), 0, "Empty sysinfo files dir")

917 918
    def test_list_plugin(self):
        os.chdir(basedir)
919
        cmd_line = '%s list' % AVOCADO
920 921
        result = process.run(cmd_line, ignore_status=True)
        output = result.stdout
922
        expected_rc = exit_codes.AVOCADO_ALL_OK
923 924 925 926 927
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertNotIn('No tests were found on current tests dir', output)

928 929
    def test_list_error_output(self):
        os.chdir(basedir)
930
        cmd_line = '%s list sbrubles' % AVOCADO
931 932
        result = process.run(cmd_line, ignore_status=True)
        output = result.stderr
933
        expected_rc = exit_codes.AVOCADO_FAIL
934 935 936
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
937
        self.assertIn("Unable to resolve reference", output)
938

939 940 941 942 943 944 945 946
    def test_list_no_file_loader(self):
        os.chdir(basedir)
        cmd_line = ("%s list --loaders external --verbose -- "
                    "this-wont-be-matched" % AVOCADO)
        result = process.run(cmd_line, ignore_status=True)
        self.assertEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK,
                         "Avocado did not return rc %d:\n%s"
                         % (exit_codes.AVOCADO_ALL_OK, result))
947 948
        exp = ("Type    Test                 Tag(s)\n"
               "MISSING this-wont-be-matched \n\n"
949 950
               "TEST TYPES SUMMARY\n"
               "==================\n"
951
               "EXTERNAL: 0\n"
952 953 954 955
               "MISSING: 1\n")
        self.assertEqual(exp, result.stdout, "Stdout mismatch:\n%s\n\n%s"
                         % (exp, result))

956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
    def test_list_verbose_tags(self):
        """
        Runs list verbosely and check for tag related output
        """
        os.chdir(basedir)
        test = script.make_script(os.path.join(self.base_outputdir, 'test.py'),
                                  VALID_PYTHON_TEST_WITH_TAGS)
        cmd_line = ("%s list --loaders file --verbose %s" % (AVOCADO,
                                                             test))
        result = process.run(cmd_line, ignore_status=True)
        self.assertEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK,
                         "Avocado did not return rc %d:\n%s"
                         % (exit_codes.AVOCADO_ALL_OK, result))
        stdout_lines = result.stdout.splitlines()
        self.assertIn("Tag(s)", stdout_lines[0])
        full_test_name = "%s:MyTest.test" % test
        self.assertEquals("INSTRUMENTED %s BIG_TAG_NAME" % full_test_name,
                          stdout_lines[1])
974 975 976 977
        self.assertIn("TEST TYPES SUMMARY", stdout_lines)
        self.assertIn("INSTRUMENTED: 1", stdout_lines)
        self.assertIn("TEST TAGS SUMMARY", stdout_lines)
        self.assertEquals("BIG_TAG_NAME: 1", stdout_lines[-1])
978

979 980
    def test_plugin_list(self):
        os.chdir(basedir)
981
        cmd_line = '%s plugins' % AVOCADO
982 983
        result = process.run(cmd_line, ignore_status=True)
        output = result.stdout
984
        expected_rc = exit_codes.AVOCADO_ALL_OK
985 986 987
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
988 989
        if sys.version_info[:2] >= (2, 7, 0):
            self.assertNotIn('Disabled', output)
990

991
    def test_config_plugin(self):
992
        os.chdir(basedir)
993
        cmd_line = '%s config --paginator off' % AVOCADO
994 995
        result = process.run(cmd_line, ignore_status=True)
        output = result.stdout
996
        expected_rc = exit_codes.AVOCADO_ALL_OK
997 998 999 1000 1001 1002 1003
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertNotIn('Disabled', output)

    def test_config_plugin_datadir(self):
        os.chdir(basedir)
1004
        cmd_line = '%s config --datadir --paginator off' % AVOCADO
1005 1006
        result = process.run(cmd_line, ignore_status=True)
        output = result.stdout
1007
        expected_rc = exit_codes.AVOCADO_ALL_OK
1008 1009 1010 1011 1012
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertNotIn('Disabled', output)

1013 1014
    def test_disable_plugin(self):
        os.chdir(basedir)
1015
        cmd_line = '%s plugins' % AVOCADO
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
        result = process.run(cmd_line, ignore_status=True)
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertIn("Collect system information", result.stdout)

        config_content = "[plugins]\ndisable=['cli.cmd.sysinfo',]"
        config = script.TemporaryScript("disable_sysinfo_cmd.conf",
                                        config_content)
        with config:
1027
            cmd_line = '%s --config %s plugins' % (AVOCADO, config)
1028 1029 1030 1031 1032 1033 1034
            result = process.run(cmd_line, ignore_status=True)
            expected_rc = exit_codes.AVOCADO_ALL_OK
            self.assertEqual(result.exit_status, expected_rc,
                             "Avocado did not return rc %d:\n%s" %
                             (expected_rc, result))
            self.assertNotIn("Collect system information", result.stdout)

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    def test_plugin_order(self):
        """
        Tests plugin order by configuration file

        First it checks if html, json, xunit and zip_archive plugins are enabled.
        Then it runs a test with zip_archive running first, which means the html,
        json and xunit output files do not make into the archive.

        Then it runs with zip_archive set to run last, which means the html,
        json and xunit output files *do* make into the archive.
        """
        def run_config(config_path):
1047
            cmd = ('%s --config %s run passtest.py --archive '
1048
                   '--job-results-dir %s --sysinfo=off'
1049
                   % (AVOCADO, config_path, self.base_outputdir))
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
            result = process.run(cmd, ignore_status=True)
            expected_rc = exit_codes.AVOCADO_ALL_OK
            self.assertEqual(result.exit_status, expected_rc,
                             "Avocado did not return rc %d:\n%s" %
                             (expected_rc, result))

        result_plugins = ["json", "xunit", "zip_archive"]
        result_outputs = ["results.json", "results.xml"]
        try:
            pkg_resources.require('avocado_result_html')
            result_plugins.append("html")
            result_outputs.append("html/results.html")
        except pkg_resources.DistributionNotFound:
            pass

        os.chdir(basedir)
1066
        cmd_line = '%s plugins' % AVOCADO
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
        result = process.run(cmd_line, ignore_status=True)
        expected_rc = exit_codes.AVOCADO_ALL_OK
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        for result_plugin in result_plugins:
            self.assertIn(result_plugin, result.stdout)

        config_content_zip_first = "[plugins.result]\norder=['zip_archive']"
        config_zip_first = script.TemporaryScript("zip_first.conf",
                                                  config_content_zip_first)
        with config_zip_first:
            run_config(config_zip_first)
            archives = glob.glob(os.path.join(self.base_outputdir, '*.zip'))
            self.assertEqual(len(archives), 1, "ZIP Archive not generated")
            zip_file = zipfile.ZipFile(archives[0], 'r')
            zip_file_list = zip_file.namelist()
            for result_output in result_outputs:
                self.assertNotIn(result_output, zip_file_list)
            os.unlink(archives[0])

        config_content_zip_last = ("[plugins.result]\norder=['html', 'json',"
1089 1090
                                   "'xunit', 'non_existing_plugin_is_ignored'"
                                   ",'zip_archive']")
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
        config_zip_last = script.TemporaryScript("zip_last.conf",
                                                 config_content_zip_last)
        with config_zip_last:
            run_config(config_zip_last)
            archives = glob.glob(os.path.join(self.base_outputdir, '*.zip'))
            self.assertEqual(len(archives), 1, "ZIP Archive not generated")
            zip_file = zipfile.ZipFile(archives[0], 'r')
            zip_file_list = zip_file.namelist()
            for result_output in result_outputs:
                self.assertIn(result_output, zip_file_list)

1102 1103
    def test_Namespace_object_has_no_attribute(self):
        os.chdir(basedir)
1104
        cmd_line = '%s plugins' % AVOCADO
1105 1106
        result = process.run(cmd_line, ignore_status=True)
        output = result.stderr
1107
        expected_rc = exit_codes.AVOCADO_ALL_OK
1108 1109 1110 1111 1112
        self.assertEqual(result.exit_status, expected_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (expected_rc, result))
        self.assertNotIn("'Namespace' object has no attribute", output)

1113

1114 1115 1116 1117
class ParseXMLError(Exception):
    pass


1118
class PluginsXunitTest(AbsPluginsTest, unittest.TestCase):
1119

1120
    def setUp(self):
1121
        self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
1122 1123
        self.junit = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                     os.path.pardir, ".data", 'junit-4.xsd'))
1124 1125
        super(PluginsXunitTest, self).setUp()

1126
    def run_and_check(self, testname, e_rc, e_ntests, e_nerrors,
1127
                      e_nnotfound, e_nfailures, e_nskip):
1128
        os.chdir(basedir)
1129 1130
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off'
                    ' --xunit - %s' % (AVOCADO, self.tmpdir, testname))
1131 1132 1133 1134 1135 1136 1137
        result = process.run(cmd_line, ignore_status=True)
        xml_output = result.stdout
        self.assertEqual(result.exit_status, e_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (e_rc, result))
        try:
            xunit_doc = xml.dom.minidom.parseString(xml_output)
1138
        except Exception as detail:
1139 1140 1141
            raise ParseXMLError("Failed to parse content: %s\n%s" %
                                (detail, xml_output))

1142 1143 1144 1145 1146 1147 1148 1149
        with open(self.junit, 'r') as f:
            xmlschema = etree.XMLSchema(etree.parse(f))

        self.assertTrue(xmlschema.validate(etree.parse(StringIO(xml_output))),
                        "Failed to validate against %s, message:\n%s" %
                        (self.junit,
                         xmlschema.error_log.filter_from_errors()))

1150 1151 1152 1153
        testsuite_list = xunit_doc.getElementsByTagName('testsuite')
        self.assertEqual(len(testsuite_list), 1, 'More than one testsuite tag')

        testsuite_tag = testsuite_list[0]
1154 1155
        self.assertEqual(len(testsuite_tag.attributes), 7,
                         'The testsuite tag does not have 7 attributes. '
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
                         'XML:\n%s' % xml_output)

        n_tests = int(testsuite_tag.attributes['tests'].value)
        self.assertEqual(n_tests, e_ntests,
                         "Unexpected number of executed tests, "
                         "XML:\n%s" % xml_output)

        n_errors = int(testsuite_tag.attributes['errors'].value)
        self.assertEqual(n_errors, e_nerrors,
                         "Unexpected number of test errors, "
                         "XML:\n%s" % xml_output)

        n_failures = int(testsuite_tag.attributes['failures'].value)
        self.assertEqual(n_failures, e_nfailures,
                         "Unexpected number of test failures, "
                         "XML:\n%s" % xml_output)

1173
        n_skip = int(testsuite_tag.attributes['skipped'].value)
1174 1175 1176 1177
        self.assertEqual(n_skip, e_nskip,
                         "Unexpected number of test skips, "
                         "XML:\n%s" % xml_output)

1178
    def test_xunit_plugin_passtest(self):
1179
        self.run_and_check('passtest.py', exit_codes.AVOCADO_ALL_OK,
1180
                           1, 0, 0, 0, 0)
1181 1182

    def test_xunit_plugin_failtest(self):
1183
        self.run_and_check('failtest.py', exit_codes.AVOCADO_TESTS_FAIL,
1184
                           1, 0, 0, 1, 0)
1185

1186
    def test_xunit_plugin_skiponsetuptest(self):
A
Amador Pahim 已提交
1187
        self.run_and_check('cancelonsetup.py', exit_codes.AVOCADO_ALL_OK,
1188
                           1, 0, 0, 0, 1)
1189

1190
    def test_xunit_plugin_errortest(self):
1191
        self.run_and_check('errortest.py', exit_codes.AVOCADO_TESTS_FAIL,
1192
                           1, 1, 0, 0, 0)
1193

1194 1195 1196 1197
    def tearDown(self):
        shutil.rmtree(self.tmpdir)
        super(PluginsXunitTest, self).tearDown()

1198 1199 1200 1201 1202

class ParseJSONError(Exception):
    pass


1203
class PluginsJSONTest(AbsPluginsTest, unittest.TestCase):
1204

1205
    def setUp(self):
1206
        self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
1207 1208
        super(PluginsJSONTest, self).setUp()

1209
    def run_and_check(self, testname, e_rc, e_ntests, e_nerrors,
1210
                      e_nfailures, e_nskip, e_ncancel=0, external_runner=None):
1211
        os.chdir(basedir)
1212 1213
        cmd_line = ('%s run --job-results-dir %s --sysinfo=off --json - '
                    '--archive %s' % (AVOCADO, self.tmpdir, testname))
1214 1215
        if external_runner is not None:
            cmd_line += " --external-runner '%s'" % external_runner
1216 1217 1218 1219 1220 1221 1222
        result = process.run(cmd_line, ignore_status=True)
        json_output = result.stdout
        self.assertEqual(result.exit_status, e_rc,
                         "Avocado did not return rc %d:\n%s" %
                         (e_rc, result))
        try:
            json_data = json.loads(json_output)
1223
        except Exception as detail:
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
            raise ParseJSONError("Failed to parse content: %s\n%s" %
                                 (detail, json_output))
        self.assertTrue(json_data, "Empty JSON result:\n%s" % json_output)
        self.assertIsInstance(json_data['tests'], list,
                              "JSON result lacks 'tests' list")
        n_tests = len(json_data['tests'])
        self.assertEqual(n_tests, e_ntests,
                         "Different number of expected tests")
        n_errors = json_data['errors']
        self.assertEqual(n_errors, e_nerrors,
                         "Different number of expected tests")
        n_failures = json_data['failures']
        self.assertEqual(n_failures, e_nfailures,
                         "Different number of expected tests")
        n_skip = json_data['skip']
        self.assertEqual(n_skip, e_nskip,
                         "Different number of skipped tests")
1241 1242
        n_cancel = json_data['cancel']
        self.assertEqual(n_cancel, e_ncancel)
1243
        return json_data
1244

1245
    def test_json_plugin_passtest(self):
1246
        self.run_and_check('passtest.py', exit_codes.AVOCADO_ALL_OK,
1247
                           1, 0, 0, 0)
1248 1249

    def test_json_plugin_failtest(self):
1250
        self.run_and_check('failtest.py', exit_codes.AVOCADO_TESTS_FAIL,
1251
                           1, 0, 1, 0)
1252

1253
    def test_json_plugin_skiponsetuptest(self):
A
Amador Pahim 已提交
1254
        self.run_and_check('cancelonsetup.py', exit_codes.AVOCADO_ALL_OK,
1255
                           1, 0, 0, 0, 1)
1256

1257
    def test_json_plugin_errortest(self):
1258
        self.run_and_check('errortest.py', exit_codes.AVOCADO_TESTS_FAIL,
1259
                           1, 1, 0, 0)
1260

1261
    @unittest.skipIf(not GNU_ECHO_BINARY, 'echo binary not available')
1262
    def test_ugly_echo_cmd(self):
1263
        data = self.run_and_check('"-ne foo\\\\\\n\\\'\\\\\\"\\\\\\'
1264
                                  'nbar/baz"', exit_codes.AVOCADO_ALL_OK, 1, 0,
1265
                                  0, 0, external_runner=GNU_ECHO_BINARY)
1266 1267
        # The executed test should be this
        self.assertEqual(data['tests'][0]['url'],
1268
                         '1--ne foo\\\\n\\\'\\"\\\\nbar/baz')
1269 1270
        # logdir name should escape special chars (/)
        self.assertEqual(os.path.basename(data['tests'][0]['logdir']),
1271
                         '1--ne foo\\\\n\\\'\\"\\\\nbar_baz')
1272

1273 1274 1275 1276
    def tearDown(self):
        shutil.rmtree(self.tmpdir)
        super(PluginsJSONTest, self).tearDown()

L
Lukáš Doktor 已提交
1277

1278 1279
if __name__ == '__main__':
    unittest.main()