1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6import os 7import time 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.server import autotest 11from autotest_lib.server import hosts 12from autotest_lib.server import test 13from autotest_lib.server.cros import remote_command 14 15class network_DiskFull(test.test): 16 """Test networking daemons when /var is full.""" 17 18 version = 1 19 CLIENT_TEST_LIST = [ 20 ('network_DhcpNegotiationSuccess', {}), 21 ('network_DhcpRenew', {}), 22 ('network_RestartShill', { 23 'tag': 'profile_exists', 24 'remove_profile': False}), 25 ('network_RestartShill', { 26 'tag': 'profile_missing', 27 'remove_profile': True}), 28 ] 29 CLIENT_TMP_DIR = '/tmp' 30 DISK_FILL_SCRIPT = 'hog_disk.sh' 31 FILL_TIMEOUT_SECONDS = 5 32 MAX_FREE_KB = 1024 33 STATEFUL_PATH = '/var' 34 TEST_TIMEOUT_SECONDS = 180 35 36 def get_free_kilobytes(self, mount_point): 37 """ 38 Get the size of free space on the filesystem mounted at |mount_point|, 39 in kilobytes. 40 41 @return Kilobytes free, as an integer. 42 """ 43 # Filesystem 1024-blocks Used Available Capacity Mount... 44 # /dev/mapper/encstateful 290968 47492 243476 17% /var 45 output = self._client.run('df -P %s' % mount_point).stdout 46 lines = output.splitlines() 47 if len(lines) != 2: 48 raise error.TestFail('Unexpected df output: %s' % lines) 49 _, _, _, free_kb, _, df_mount_point = lines[1].split(None, 5) 50 if df_mount_point != mount_point: 51 raise error.TestFail('Failed to find %s, got %s instead.' % 52 (mount_point, df_mount_point)) 53 return int(free_kb) 54 55 56 def wait_until_full(self, mount_point, max_free_kilobytes): 57 """ 58 Wait until |mount_point| has no more than |max_free_kilobytes| free. 59 60 @param mount_point The path at which the filesystem is mounted. 61 @param max_free_kilobytes Maximum free space permitted, in kilobytes. 62 @return True if the disk is full, else False 63 """ 64 start_time = time.time() 65 while time.time() - start_time < self.FILL_TIMEOUT_SECONDS: 66 if (self.get_free_kilobytes(mount_point) <= max_free_kilobytes): 67 return True 68 else: 69 time.sleep(1) 70 return False 71 72 73 def run_once(self, client_addr): 74 """ 75 Test main loop. 76 77 @param client_addr DUT hostname or IP address. 78 """ 79 self._client = hosts.create_host(client_addr) 80 client_autotest = autotest.Autotest(self._client) 81 82 disk_filler_src = os.path.join(self.bindir, self.DISK_FILL_SCRIPT) 83 disk_filler_dst = os.path.join(self.CLIENT_TMP_DIR, 84 os.path.basename(self.DISK_FILL_SCRIPT)) 85 self._client.send_file(disk_filler_src, disk_filler_dst) 86 87 disk_filler_command = '%s %s %d' % ( 88 disk_filler_dst, self.STATEFUL_PATH, self.TEST_TIMEOUT_SECONDS) 89 90 with remote_command.Command(self._client, disk_filler_command) \ 91 as disk_filler_process: 92 if not self.wait_until_full(self.STATEFUL_PATH, self.MAX_FREE_KB): 93 logging.debug(disk_filler_process.result) 94 raise error.TestFail( 95 'did not fill %s within %d seconds' % ( 96 self.STATEFUL_PATH, self.FILL_TIMEOUT_SECONDS)) 97 98 client_autotest.run_test('network_CheckCriticalProcesses', 99 tag='before_client_tests') 100 passed_with_failsafe = [] 101 102 for name, kwargs in self.CLIENT_TEST_LIST: 103 # Autotest goes to /mnt/stateful_partition/dev_image, 104 # while /var is on /mnt/stateful_partition/encrypted. 105 # 106 # These are separate partitions, so we can copy 107 # the tests onto the DUT even when /var is full. 108 client_autotest.run_test(name, **kwargs) 109 110 if 'tag' in kwargs: 111 full_test_name = '%s.%s' % (name, kwargs['tag']) 112 else: 113 full_test_name = name 114 115 # To avoid leaving the system in a bad state, the disk 116 # filler times out eventually. This means a test can 117 # "pass" due to the failsafe. Check if the failsafe 118 # kicked in, by checking if the disk is still full. 119 if (self.get_free_kilobytes(self.STATEFUL_PATH) > 120 self.MAX_FREE_KB): 121 passed_with_failsafe.append(full_test_name) 122 123 client_autotest.run_test('network_CheckCriticalProcesses', 124 tag='after_%s' % full_test_name) 125 126 if len(passed_with_failsafe): 127 raise error.TestFail( 128 '%d test(s) triggered the fail-safe: %s. ' 129 'They may be incorrectly listed as passing.' % ( 130 len(passed_with_failsafe), 131 ', '.join(passed_with_failsafe))) 132