Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 1 | #!/usr/bin/python -u |
| 2 | # |
| 3 | # Copyright (c) 2011 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 | |
Aviv Keshet | 4111f86 | 2013-02-13 13:11:11 -0800 | [diff] [blame] | 8 | #pylint: disable-msg=C0111 |
| 9 | |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 10 | import mox, os, shutil, tempfile, unittest |
| 11 | |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 12 | import common |
Allen Li | 5cca818 | 2017-11-20 13:12:51 -0800 | [diff] [blame] | 13 | from django.conf import settings |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 14 | from autotest_lib.client.common_lib import global_config |
Jakob Juelich | 934f0dc | 2014-10-14 18:21:13 -0700 | [diff] [blame] | 15 | from autotest_lib.frontend import database_settings_helper |
Fang Deng | 9ec6680 | 2014-04-28 19:04:33 +0000 | [diff] [blame] | 16 | from autotest_lib.frontend import setup_django_environment |
| 17 | from autotest_lib.frontend import setup_test_environment |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 18 | from autotest_lib.frontend.afe import frontend_test_utils |
| 19 | from autotest_lib.frontend.afe import models as django_afe_models |
| 20 | from autotest_lib.frontend.tko import models as django_tko_models |
| 21 | from autotest_lib.tko import db as tko_db |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 22 | from autotest_lib.tko.site_parse import StackTrace |
| 23 | |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 24 | # Have to import this after setup_django_environment and setup_test_environment. |
| 25 | # It creates a database connection, so the mocking has to be done first. |
| 26 | from django.db import connections |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 27 | |
| 28 | class stack_trace_test(unittest.TestCase): |
| 29 | |
| 30 | |
| 31 | def setUp(self): |
Fang Deng | 9ec6680 | 2014-04-28 19:04:33 +0000 | [diff] [blame] | 32 | setup_test_environment.set_up() |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 33 | self._fake_results = tempfile.mkdtemp() |
| 34 | self._cros_src_dir = global_config.global_config.get_config_value( |
| 35 | 'CROS', 'source_tree', default=None) |
| 36 | |
| 37 | if not self._cros_src_dir: |
| 38 | self.fail('No Chrome OS source tree defined in global_config.ini') |
| 39 | |
| 40 | self._stack_trace = StackTrace( |
| 41 | self._fake_results, self._cros_src_dir) |
| 42 | |
| 43 | self._cache_dir = os.path.join( |
| 44 | self._cros_src_dir, 'chroot', self._stack_trace._CACHE_DIR) |
| 45 | |
| 46 | # Ensure we don't obliterate a live cache directory by accident. |
| 47 | if os.path.exists(self._cache_dir): |
| 48 | self.fail( |
| 49 | 'Symbol cache directory already exists. Cowardly refusing to' |
| 50 | ' run. Please remove this directory manually to continue.') |
| 51 | |
| 52 | |
| 53 | def tearDown(self): |
Fang Deng | 9ec6680 | 2014-04-28 19:04:33 +0000 | [diff] [blame] | 54 | setup_test_environment.tear_down() |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 55 | shutil.rmtree(self._fake_results) |
| 56 | if os.path.exists(self._cache_dir): |
| 57 | shutil.rmtree(self._cache_dir) |
| 58 | |
| 59 | |
| 60 | def _setup_basic_cache(self, |
| 61 | job_name='x86-alex-r16-R16-1166.0.0-a1-b1118_bvt', |
| 62 | mkdir=True): |
| 63 | # Ensure cache directory is present. |
| 64 | self._stack_trace._get_cache_dir() |
| 65 | board, rev, version = self._stack_trace._parse_job_name(job_name) |
| 66 | |
| 67 | symbols_dir = os.path.join( |
| 68 | self._cache_dir, '-'.join([board, rev, version])) |
| 69 | if mkdir: |
| 70 | os.mkdir(symbols_dir) |
| 71 | |
| 72 | chroot_symbols_dir = os.sep + os.path.relpath( |
| 73 | symbols_dir, self._stack_trace._chroot_dir) |
| 74 | |
| 75 | return job_name, symbols_dir, chroot_symbols_dir |
| 76 | |
| 77 | |
| 78 | def test_get_job_name(self): |
| 79 | job_name = 'x86-alex-r16-R16-1166.0.0-a1-b1118_regression' |
| 80 | with open(os.path.join(self._fake_results, 'keyval'), 'w') as f: |
| 81 | f.write('label=%s' % job_name) |
| 82 | |
| 83 | self.assertEqual(self._stack_trace._get_job_name(), job_name) |
| 84 | |
| 85 | |
| 86 | def test_parse_3_tuple_job_name(self): |
| 87 | job_name = 'x86-alex-r16-R16-1166.0.0-a1-b1118_regression' |
| 88 | board, rev, version = self._stack_trace._parse_job_name(job_name) |
| 89 | self.assertEqual(board, 'x86-alex') |
| 90 | self.assertEqual(rev, 'r16') |
| 91 | self.assertEqual(version, '1166.0.0') |
| 92 | |
| 93 | |
| 94 | def test_parse_4_tuple_job_name(self): |
| 95 | job_name = 'x86-mario-r15-0.15.1011.74-a1-b61_bvt' |
| 96 | board, rev, version = self._stack_trace._parse_job_name(job_name) |
| 97 | self.assertEqual(board, 'x86-mario') |
| 98 | self.assertEqual(rev, 'r15') |
| 99 | self.assertEqual(version, '0.15.1011.74') |
| 100 | |
| 101 | |
| 102 | def test_parse_4_tuple_au_job_name(self): |
| 103 | job_name = 'x86-alex-r15-0.15.1011.81_to_0.15.1011.82-a1-b69_mton_au' |
| 104 | board, rev, version = self._stack_trace._parse_job_name(job_name) |
| 105 | self.assertEqual(board, 'x86-alex') |
| 106 | self.assertEqual(rev, 'r15') |
| 107 | self.assertEqual(version, '0.15.1011.82') |
| 108 | |
| 109 | |
| 110 | def test_parse_3_tuple_au_job_name(self): |
| 111 | job_name = 'x86-alex-r16-1165.0.0_to_R16-1166.0.0-a1-b69_mton_au' |
| 112 | board, rev, version = self._stack_trace._parse_job_name(job_name) |
| 113 | self.assertEqual(board, 'x86-alex') |
| 114 | self.assertEqual(rev, 'r16') |
| 115 | self.assertEqual(version, '1166.0.0') |
| 116 | |
| 117 | |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 118 | class database_selection_test(mox.MoxTestBase, |
| 119 | frontend_test_utils.FrontendTestMixin): |
| 120 | |
| 121 | def setUp(self): |
| 122 | super(database_selection_test, self).setUp() |
| 123 | self._frontend_common_setup(fill_data=False) |
| 124 | |
| 125 | |
| 126 | def tearDown(self): |
| 127 | super(database_selection_test, self).tearDown() |
| 128 | self._frontend_common_teardown() |
| 129 | global_config.global_config.reset_config_values() |
| 130 | |
| 131 | |
| 132 | def assertQueries(self, database, assert_in, assert_not_in): |
| 133 | assert_in_found = False |
| 134 | for query in connections[database].queries: |
| 135 | sql = query['sql'] |
| 136 | # Ignore CREATE TABLE statements as they are always executed |
| 137 | if 'INSERT INTO' in sql or 'SELECT' in sql: |
| 138 | self.assertNotIn(assert_not_in, sql) |
| 139 | if assert_in in sql: |
| 140 | assert_in_found = True |
| 141 | self.assertTrue(assert_in_found) |
| 142 | |
| 143 | |
| 144 | def testDjangoModels(self): |
| 145 | # If DEBUG=False connection.query will be empty |
| 146 | settings.DEBUG = True |
| 147 | |
| 148 | afe_job = django_afe_models.Job.objects.create(created_on='2014-08-12') |
| 149 | # Machine has less dependencies than tko Job so it's easier to create |
| 150 | tko_job = django_tko_models.Machine.objects.create() |
| 151 | |
| 152 | django_afe_models.Job.objects.get(pk=afe_job.id) |
| 153 | django_tko_models.Machine.objects.get(pk=tko_job.pk) |
| 154 | |
| 155 | self.assertQueries('global', 'tko_machines', 'afe_jobs') |
| 156 | self.assertQueries('default', 'afe_jobs', 'tko_machines') |
| 157 | |
| 158 | # Avoid unnecessary debug output from other tests |
| 159 | settings.DEBUG = True |
| 160 | |
| 161 | |
Jakob Juelich | 934f0dc | 2014-10-14 18:21:13 -0700 | [diff] [blame] | 162 | def testRunOnShardWithoutGlobalConfigsFails(self): |
| 163 | global_config.global_config.override_config_value( |
| 164 | 'SHARD', 'shard_hostname', 'host1') |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 165 | from autotest_lib.frontend import settings |
Jakob Juelich | 934f0dc | 2014-10-14 18:21:13 -0700 | [diff] [blame] | 166 | # settings module was already loaded during the imports of this file, |
| 167 | # so before the configuration setting was made, therefore reload it: |
| 168 | reload(database_settings_helper) |
| 169 | self.assertRaises(global_config.ConfigError, |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 170 | reload, settings) |
Jakob Juelich | 934f0dc | 2014-10-14 18:21:13 -0700 | [diff] [blame] | 171 | |
| 172 | |
| 173 | def testRunOnMasterWithoutGlobalConfigsWorks(self): |
| 174 | global_config.global_config.override_config_value( |
| 175 | 'SHARD', 'shard_hostname', '') |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 176 | from autotest_lib.frontend import settings |
Jakob Juelich | 934f0dc | 2014-10-14 18:21:13 -0700 | [diff] [blame] | 177 | # settings module was already loaded during the imports of this file, |
| 178 | # so before the configuration setting was made, therefore reload it: |
| 179 | reload(database_settings_helper) |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 180 | reload(settings) |
| 181 | |
| 182 | |
| 183 | def testTkoDatabase(self): |
| 184 | global_host = 'GLOBAL_HOST' |
| 185 | global_user = 'GLOBAL_USER' |
| 186 | global_db = 'GLOBAL_DB' |
| 187 | global_pw = 'GLOBAL_PW' |
| 188 | global_port = '' |
| 189 | local_host = 'LOCAL_HOST' |
| 190 | |
| 191 | global_config.global_config.override_config_value( |
| 192 | 'AUTOTEST_WEB', 'global_db_type', '') |
| 193 | |
| 194 | global_config.global_config.override_config_value( |
| 195 | 'AUTOTEST_WEB', 'global_db_host', global_host) |
| 196 | global_config.global_config.override_config_value( |
| 197 | 'AUTOTEST_WEB', 'global_db_database', global_db) |
| 198 | global_config.global_config.override_config_value( |
| 199 | 'AUTOTEST_WEB', 'global_db_user', global_user) |
| 200 | global_config.global_config.override_config_value( |
| 201 | 'AUTOTEST_WEB', 'global_db_password', global_pw) |
| 202 | global_config.global_config.override_config_value( |
| 203 | 'AUTOTEST_WEB', 'host', local_host) |
| 204 | |
| 205 | class ConnectCalledException(Exception): |
| 206 | pass |
| 207 | |
| 208 | # We're only interested in the parameters connect is called with here. |
| 209 | # Take the fast path out so we don't have to mock all the other calls |
| 210 | # that will later be made on the connection |
| 211 | def fake_connect(*args, **kwargs): |
| 212 | raise ConnectCalledException |
| 213 | |
| 214 | tko_db.db_sql.connect = None |
| 215 | self.mox.StubOutWithMock(tko_db.db_sql, 'connect') |
| 216 | tko_db.db_sql.connect( |
| 217 | global_host, global_db, global_user, global_pw, |
| 218 | global_port).WithSideEffects(fake_connect) |
| 219 | |
| 220 | self.mox.ReplayAll() |
| 221 | |
| 222 | self.assertRaises(ConnectCalledException, tko_db.db_sql) |
Jakob Juelich | 934f0dc | 2014-10-14 18:21:13 -0700 | [diff] [blame] | 223 | |
| 224 | |
Dale Curtis | 4a431e6 | 2011-10-11 17:37:07 -0700 | [diff] [blame] | 225 | if __name__ == "__main__": |
| 226 | unittest.main() |