16fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone#!/usr/bin/python
26fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone#
3ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
46fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone# Use of this source code is governed by a BSD-style license that can be
56fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone# found in the LICENSE file.
66fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone
7b493555db2d43e79d96e793cae9d1ffb822dd6c1Chris Masone"""Unit tests for server/cros/dynamic_suite/dynamic_suite.py."""
86fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone
96fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masoneimport mox
107a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Millerimport os
117a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Millerimport signal
1236cfd831af781eed114337efa5b90c103a49b502Dan Shiimport unittest
136fed646ae4c833b537ea24b6161b81e0f50c0e32Chris Masone
1444e4d6ce5a7c38451c25d35b307b35338606091fChris Masonefrom autotest_lib.client.common_lib import base_job, error
1524b3a027291ff030bb74482818106fa91bcc911dChris Sosafrom autotest_lib.client.common_lib.cros import dev_server
1636cfd831af781eed114337efa5b90c103a49b502Dan Shifrom autotest_lib.server.cros import provision
17b493555db2d43e79d96e793cae9d1ffb822dd6c1Chris Masonefrom autotest_lib.server.cros.dynamic_suite import dynamic_suite
1836cfd831af781eed114337efa5b90c103a49b502Dan Shifrom autotest_lib.server.cros.dynamic_suite.suite import Suite
19f63576d7e89fd933475c1dc123c60aa9c2cee1c0Chris Masone
20f63576d7e89fd933475c1dc123c60aa9c2cee1c0Chris Masone
21ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masoneclass DynamicSuiteTest(mox.MoxTestBase):
22ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    """Unit tests for dynamic_suite module methods.
23ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
24ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    @var _DARGS: default args to vet.
25ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    """
26ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
27accb5ceaac066025592808247bfa9c97966bba97Chris Sosa    _DEVSERVER_HOST = 'http://devserver1'
280723bf5ed7ff506e15fea180547cb6a8ae9102ebDan Shi    _BUILDS = {provision.CROS_VERSION_PREFIX: 'build_1',
290723bf5ed7ff506e15fea180547cb6a8ae9102ebDan Shi               provision.FW_RW_VERSION_PREFIX:'fwrw_build_1'}
30ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
31ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def setUp(self):
32accb5ceaac066025592808247bfa9c97966bba97Chris Sosa
33ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        super(DynamicSuiteTest, self).setUp()
34ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        self._DARGS = {'name': 'name',
3536cfd831af781eed114337efa5b90c103a49b502Dan Shi                       'builds': self._BUILDS,
36ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                       'board': 'board',
37ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                       'job': self.mox.CreateMock(base_job.base_job),
38ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                       'num': 1,
39ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                       'pool': 'pool',
4062579122694934d942a4844a615bc034bc2e8aa1Chris Masone                       'check_hosts': False,
4141048e3859e1ca5c0fb0d84da1aab3b3079de27bAviv Keshet                       'add_experimental': False,
425965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi                       'suite_dependencies': ['test_dep'],
435965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi                       'devserver_url': self._DEVSERVER_HOST}
44ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
45ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
46accb5ceaac066025592808247bfa9c97966bba97Chris Sosa
47ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testVetRequiredReimageAndRunArgs(self):
48ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        """Should verify only that required args are present and correct."""
496dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        spec = dynamic_suite.SuiteSpec(**self._DARGS)
5036cfd831af781eed114337efa5b90c103a49b502Dan Shi        self.assertEquals(spec.builds, self._DARGS['builds'])
516dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.board, 'board:' + self._DARGS['board'])
526dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.name, self._DARGS['name'])
536dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.job, self._DARGS['job'])
54ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
55ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
56ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testVetReimageAndRunBuildArgFail(self):
5736cfd831af781eed114337efa5b90c103a49b502Dan Shi        """Should fail verification if both |builds| and |build| are not set.
5836cfd831af781eed114337efa5b90c103a49b502Dan Shi        """
59ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        self._DARGS['build'] = None
6036cfd831af781eed114337efa5b90c103a49b502Dan Shi        self._DARGS['builds'] = None
6136cfd831af781eed114337efa5b90c103a49b502Dan Shi        self.assertRaises(error.SuiteArgumentException,
6236cfd831af781eed114337efa5b90c103a49b502Dan Shi                          dynamic_suite.SuiteSpec,
6336cfd831af781eed114337efa5b90c103a49b502Dan Shi                          **self._DARGS)
6436cfd831af781eed114337efa5b90c103a49b502Dan Shi        self._DARGS['build'] = 'build1'
6536cfd831af781eed114337efa5b90c103a49b502Dan Shi        self._DARGS['builds'] = {'cros-version': 'build2',
6636cfd831af781eed114337efa5b90c103a49b502Dan Shi                                 'firmware-version': 'build3'}
67f8b5306840870a8ebec3a5dc4b77c0bd79a69c5bChris Masone        self.assertRaises(error.SuiteArgumentException,
686dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone                          dynamic_suite.SuiteSpec,
69ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                          **self._DARGS)
70ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
71ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
72ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testVetReimageAndRunBoardArgFail(self):
73ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        """Should fail verification because |board| arg is bad."""
74ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        self._DARGS['board'] = None
75f8b5306840870a8ebec3a5dc4b77c0bd79a69c5bChris Masone        self.assertRaises(error.SuiteArgumentException,
766dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone                          dynamic_suite.SuiteSpec,
77ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                          **self._DARGS)
78ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
79ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
80ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testVetReimageAndRunNameArgFail(self):
81ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        """Should fail verification because |name| arg is bad."""
82ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        self._DARGS['name'] = None
83f8b5306840870a8ebec3a5dc4b77c0bd79a69c5bChris Masone        self.assertRaises(error.SuiteArgumentException,
846dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone                          dynamic_suite.SuiteSpec,
85ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                          **self._DARGS)
86ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
87ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
88ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testVetReimageAndRunJobArgFail(self):
89ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        """Should fail verification because |job| arg is bad."""
90ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        self._DARGS['job'] = None
91f8b5306840870a8ebec3a5dc4b77c0bd79a69c5bChris Masone        self.assertRaises(error.SuiteArgumentException,
926dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone                          dynamic_suite.SuiteSpec,
93ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone                          **self._DARGS)
94ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
95ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
96ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testOverrideOptionalReimageAndRunArgs(self):
97ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        """Should verify that optional args can be overridden."""
986dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        spec = dynamic_suite.SuiteSpec(**self._DARGS)
996dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.pool, 'pool:' + self._DARGS['pool'])
1006dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.num, self._DARGS['num'])
1016dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.check_hosts, self._DARGS['check_hosts'])
1026dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.add_experimental,
1036dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone                          self._DARGS['add_experimental'])
10441048e3859e1ca5c0fb0d84da1aab3b3079de27bAviv Keshet        self.assertEquals(spec.suite_dependencies,
10541048e3859e1ca5c0fb0d84da1aab3b3079de27bAviv Keshet                          self._DARGS['suite_dependencies'])
106ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
107ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
108ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone    def testDefaultOptionalReimageAndRunArgs(self):
109ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        """Should verify that optional args get defaults."""
110ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        del(self._DARGS['pool'])
11162579122694934d942a4844a615bc034bc2e8aa1Chris Masone        del(self._DARGS['check_hosts'])
112ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        del(self._DARGS['add_experimental'])
113ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone        del(self._DARGS['num'])
11441048e3859e1ca5c0fb0d84da1aab3b3079de27bAviv Keshet        del(self._DARGS['suite_dependencies'])
1156dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone
1166dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        spec = dynamic_suite.SuiteSpec(**self._DARGS)
1176dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.pool, None)
1186dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.num, None)
1196dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.check_hosts, True)
1206dff243bdcb9d52b0d07e92c33f42cfa40263945Chris Masone        self.assertEquals(spec.add_experimental, True)
12147a0367b883f3429efac994047f2c921a983fd96Alex Miller        self.assertEquals(spec.suite_dependencies, [])
122ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
123ab3e7331e3f45521fef3ef2b736a82f9d5aad854Chris Masone
1247a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller    def testReimageAndSIGTERM(self):
1257a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller        """Should reimage_and_run that causes a SIGTERM and fails cleanly."""
1269a1987acc36506ceba0397ce64aeca1b39eb5b39Alex Miller        def suicide(*_):
1275965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            """Send SIGTERM to current process to exit.
1285965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi
1295965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            @param _: Ignored.
1305965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            """
1317a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller            os.kill(os.getpid(), signal.SIGTERM)
1327a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller
1338dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller        # Mox doesn't play well with SIGTERM, but it does play well with
1348dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller        # with exceptions, so here we're using an exception to simulate
1358dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller        # execution being interrupted by a signal.
1367a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller        class UnhandledSIGTERM(Exception):
1375965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            """Exception to be raised when SIGTERM is received."""
1387a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller            pass
1397a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller
1408dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller        def handler(signal_number, frame):
1415965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            """Handler for receiving a signal.
1425965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi
1435965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            @param signal_number: signal number.
1445965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            @param frame: stack frame object.
1455965c09acfcba7253f9bd4a3851f3b7fec429e2eDan Shi            """
1468dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller            raise UnhandledSIGTERM()
1478dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller
1488dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller        signal.signal(signal.SIGTERM, handler)
149accb5ceaac066025592808247bfa9c97966bba97Chris Sosa        spec = self.mox.CreateMock(dynamic_suite.SuiteSpec)
15036cfd831af781eed114337efa5b90c103a49b502Dan Shi        spec.builds = self._BUILDS
15136cfd831af781eed114337efa5b90c103a49b502Dan Shi        spec.test_source_build = Suite.get_test_source_build(self._BUILDS)
152accb5ceaac066025592808247bfa9c97966bba97Chris Sosa        spec.devserver = self.mox.CreateMock(dev_server.ImageServer)
1539a1987acc36506ceba0397ce64aeca1b39eb5b39Alex Miller        spec.devserver.stage_artifacts(
15436cfd831af781eed114337efa5b90c103a49b502Dan Shi                spec.builds[provision.CROS_VERSION_PREFIX],
15536cfd831af781eed114337efa5b90c103a49b502Dan Shi                ['control_files', 'test_suites']).WithSideEffects(suicide)
1565ace6f2e17f808efbee863a7d7dbe1bc52527a19Simran Basi        spec.run_prod_code = False
1578dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller
1587a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller        self.mox.ReplayAll()
1597a2160a31f5ca4ce41faac94aeb3c3ffc389021eAlex Miller
1608dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller        self.assertRaises(UnhandledSIGTERM,
1618dca4641f3b98181843b752e2b51b99c52541a0aAlex Miller                          dynamic_suite._perform_reimage_and_run,
1623a69adcf4b2c35fb9775c8de8091dc8d30196512Alex Miller                          spec, None, None, None)
16336cfd831af781eed114337efa5b90c103a49b502Dan Shi
16436cfd831af781eed114337efa5b90c103a49b502Dan Shi
16536cfd831af781eed114337efa5b90c103a49b502Dan Shiif __name__ == '__main__':
16636cfd831af781eed114337efa5b90c103a49b502Dan Shi    unittest.main()
167