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