1# Lint as: python2, python3 2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import logging 7import os 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.common_lib import utils 11from autotest_lib.server import test 12 13DEFAULT_AVAHI_SIZE_UPDATE_DELAY = 10 14 15# P2P_PATH is the path where the p2p server expects the sharing files. 16P2P_PATH = '/var/cache/p2p' 17 18# Prefix all the test files with P2P_TEST_PREFIX. 19P2P_TEST_PREFIX = 'p2p-test' 20 21# Kilobyte. 22KB = 1024 23 24# File size of the shared file in MB. 25P2P_FILE_SIZE_MB = 4 * KB * KB 26P2P_FILE_SPLIT_SIZE_KB = P2P_FILE_SIZE_MB // (2 * KB) 27 28# After a peer finishes the download we need it to keep serving the file for 29# other peers. This peer will then wait up to P2P_SERVING_TIMEOUT_SECS seconds 30# for the test to conclude. 31P2P_SERVING_TIMEOUT_SECS = 300 32 33 34class p2p_EndToEndTest(test.test): 35 """Test to check that p2p works.""" 36 version = 1 37 38 39 def run_once(self, dut, file_id, companions): 40 self._dut = dut 41 self._companion = companions[0] 42 43 file_id = '%s-%s' % (P2P_TEST_PREFIX, file_id) 44 file_temp_name = os.path.join(P2P_PATH, file_id + '.tmp') 45 file_shared_name = os.path.join(P2P_PATH, file_id + '.p2p') 46 47 logging.info('File ID: %s', file_id) 48 49 # Setup dut and companion. 50 for host in [self._dut, self._companion]: 51 # Ensure that p2p is running. 52 host.run('start p2p || true') 53 host.run('status p2p | grep running') 54 55 # Prepare an empty file to share and specify its final size via the 56 # "user.cros-p2p-filesize" attribute. 57 logging.info('All devices setup. Generating a file on main DUT') 58 dut.run('touch %s' % file_temp_name) 59 dut.run('setfattr -n user.cros-p2p-filesize -v %d %s' % 60 (P2P_FILE_SIZE_MB, file_temp_name)) 61 dut.run('mv %s %s' % (file_temp_name, file_shared_name)) 62 63 # Generate part of the files total file fize. 64 dut.run('dd if=/dev/zero of=%s bs=%d count=%d' % 65 (file_shared_name, KB, P2P_FILE_SPLIT_SIZE_KB)) 66 67 def _wait_until_avahi_size_update(): 68 ret = '' 69 try: 70 ret = self._companion.run( 71 'p2p-client --get-url=%s --minimum-size=%d' % 72 (file_id, P2P_FILE_SPLIT_SIZE_KB * KB)) 73 ret = ret.stdout.strip() 74 except: 75 return False 76 return ret != '' 77 78 err = 'Shared file size did not update in time.' 79 # The actual delay is 10 seconds, so triple that to account for flakes. 80 utils.poll_for_condition(condition=_wait_until_avahi_size_update, 81 timeout=DEFAULT_AVAHI_SIZE_UPDATE_DELAY * 3, 82 exception=error.TestFail(err)) 83 84 # Now thhe companion can attempt a p2p file download. 85 logging.info('Listing all p2p peers for the companion: ') 86 logging.info(self._companion.run('p2p-client --list-all').stdout) 87 ret = self._companion.run('p2p-client --get-url=%s' % file_id, 88 ignore_status=True) 89 url = ret.stdout.strip() 90 91 if not url: 92 raise error.TestFail( 93 'p2p-client on companion returned an empty URL.') 94 else: 95 logging.info('Companion using URL %s.', url) 96 logging.info( 97 'Companion downloading the file from main DUT via p2p in the background.' 98 ) 99 self._companion.run_background('curl %s -o %s' % 100 (url, file_shared_name), 101 verbose=True) 102 103 logging.info( 104 'While companion is downloading the file, we will expand it to its full size.' 105 ) 106 dut.run('dd if=/dev/zero of=%s bs=%d count=%d' 107 ' conv=notrunc oflag=append' % 108 (file_shared_name, KB, P2P_FILE_SPLIT_SIZE_KB)) 109 110 # Calculate the SHA1 (160 bits -> 40 characters when 111 # hexencoded) of the generated file. 112 ret = dut.run('sha1sum %s' % file_shared_name) 113 sha1_main = ret.stdout.strip()[0:40] 114 logging.info('SHA1 of main is %s', sha1_main) 115 sha1_companion = '' 116 logging.info( 117 'Waiting for companion to finish downloading file so we can compare SHA1 values' 118 ) 119 120 def _shas_match(): 121 """Returns true when the SHA1 of the file matches on DUT and companion.""" 122 ret = self._companion.run('sha1sum %s' % file_shared_name) 123 sha1_companion = ret.stdout.strip()[0:40] 124 logging.debug(sha1_companion) 125 return sha1_main == sha1_companion 126 127 err = "Main DUT's SHA1 (%s) doesn't match companions's SHA1 (%s)." % ( 128 sha1_main, sha1_companion) 129 utils.poll_for_condition(condition=_shas_match, 130 timeout=P2P_SERVING_TIMEOUT_SECS, 131 exception=error.TestFail(err)) 132 133 def cleanup(self): 134 # Clean the test environment and stop sharing this file. 135 for host in [self._dut, self._companion]: 136 host.run('rm -f %s/%s-*.p2p' % (P2P_PATH, P2P_TEST_PREFIX)) 137 host.run('stop p2p') 138