1#!/usr/bin/python
2#
3# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Unit tests for server/cros/dynamic_suite/dynamic_suite.py."""
8
9import os
10import signal
11import unittest
12
13import mox
14import mock
15
16import common
17from autotest_lib.client.common_lib import base_job, error
18from autotest_lib.server.cros import provision
19from autotest_lib.server.cros.dynamic_suite import dynamic_suite
20from autotest_lib.server.cros.dynamic_suite.suite import Suite
21
22
23class DynamicSuiteTest(mox.MoxTestBase):
24    """Unit tests for dynamic_suite module methods.
25
26    @var _DARGS: default args to vet.
27    """
28
29    _DEVSERVER_HOST = 'http://devserver1'
30    _BUILDS = {provision.CROS_VERSION_PREFIX: 'build_1',
31               provision.FW_RW_VERSION_PREFIX:'fwrw_build_1'}
32
33    def setUp(self):
34
35        super(DynamicSuiteTest, self).setUp()
36        self._DARGS = {'name': 'name',
37                       'builds': self._BUILDS,
38                       'board': 'board',
39                       'job': self.mox.CreateMock(base_job.base_job),
40                       'pool': 'pool',
41                       'check_hosts': False,
42                       'add_experimental': False,
43                       'suite_dependencies': ['test_dep'],
44                       'devserver_url': self._DEVSERVER_HOST}
45
46
47
48    def testVetRequiredReimageAndRunArgs(self):
49        """Should verify only that required args are present and correct."""
50        spec = dynamic_suite._SuiteSpec(**self._DARGS)
51        self.assertEquals(spec.builds, self._DARGS['builds'])
52        self.assertEquals(spec.board, 'board:' + self._DARGS['board'])
53        self.assertEquals(spec.name, self._DARGS['name'])
54        self.assertEquals(spec.job, self._DARGS['job'])
55
56
57    def testVetReimageAndRunBuildArgFail(self):
58        """Should fail verification if both |builds| and |build| are not set.
59        """
60        self._DARGS['builds'] = None
61        self.assertRaises(error.SuiteArgumentException,
62                          dynamic_suite._SuiteSpec,
63                          **self._DARGS)
64
65
66    def testVetReimageAndRunBoardArgFail(self):
67        """Should fail verification because |board| arg is bad."""
68        self._DARGS['board'] = None
69        self.assertRaises(error.SuiteArgumentException,
70                          dynamic_suite._SuiteSpec,
71                          **self._DARGS)
72
73
74    def testVetReimageAndRunNameArgFail(self):
75        """Should fail verification because |name| arg is bad."""
76        self._DARGS['name'] = None
77        self.assertRaises(error.SuiteArgumentException,
78                          dynamic_suite._SuiteSpec,
79                          **self._DARGS)
80
81
82    def testVetReimageAndRunJobArgFail(self):
83        """Should fail verification because |job| arg is bad."""
84        self._DARGS['job'] = None
85        self.assertRaises(error.SuiteArgumentException,
86                          dynamic_suite._SuiteSpec,
87                          **self._DARGS)
88
89
90    def testOverrideOptionalReimageAndRunArgs(self):
91        """Should verify that optional args can be overridden."""
92        spec = dynamic_suite._SuiteSpec(**self._DARGS)
93        self.assertEquals(spec.pool, 'pool:' + self._DARGS['pool'])
94        self.assertEquals(spec.check_hosts, self._DARGS['check_hosts'])
95        self.assertEquals(spec.add_experimental,
96                          self._DARGS['add_experimental'])
97        self.assertEquals(spec.suite_dependencies,
98                          self._DARGS['suite_dependencies'])
99
100
101    def testDefaultOptionalReimageAndRunArgs(self):
102        """Should verify that optional args get defaults."""
103        del(self._DARGS['pool'])
104        del(self._DARGS['check_hosts'])
105        del(self._DARGS['add_experimental'])
106        del(self._DARGS['suite_dependencies'])
107
108        spec = dynamic_suite._SuiteSpec(**self._DARGS)
109        self.assertEquals(spec.pool, None)
110        self.assertEquals(spec.check_hosts, True)
111        self.assertEquals(spec.add_experimental, True)
112        self.assertEquals(
113                spec.suite_dependencies,
114                ['cros-version:build_1', 'fwrw-version:fwrw_build_1'])
115
116
117    def testReimageAndSIGTERM(self):
118        """Should reimage_and_run that causes a SIGTERM and fails cleanly."""
119        def suicide(*_, **__):
120            """Send SIGTERM to current process to exit.
121
122            @param _: Ignored.
123            @param __: Ignored.
124            """
125            os.kill(os.getpid(), signal.SIGTERM)
126
127        # Mox doesn't play well with SIGTERM, but it does play well with
128        # with exceptions, so here we're using an exception to simulate
129        # execution being interrupted by a signal.
130        class UnhandledSIGTERM(Exception):
131            """Exception to be raised when SIGTERM is received."""
132            pass
133
134        def handler(signal_number, frame):
135            """Handler for receiving a signal.
136
137            @param signal_number: signal number.
138            @param frame: stack frame object.
139            """
140            raise UnhandledSIGTERM()
141
142        signal.signal(signal.SIGTERM, handler)
143        spec = mock.MagicMock()
144        spec.builds = self._BUILDS
145        spec.test_source_build = Suite.get_test_source_build(self._BUILDS)
146        spec.devserver.stage_artifacts.side_effect = suicide
147        spec.run_prod_code = False
148
149        self.assertRaises(UnhandledSIGTERM,
150                          dynamic_suite._perform_reimage_and_run,
151                          spec, None, None, None)
152
153
154if __name__ == '__main__':
155    unittest.main()
156