1# Copyright (c) 2013 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 random 8import time 9 10from autotest_lib.client.common_lib import error 11from autotest_lib.server import test 12from autotest_lib.server.cros import queue_barrier 13 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# File size of the shared file in KB. 22P2P_FILE_SIZE_KB = 80 * 1000 23 24# After a peer finishes the download we need it to keep serving the file for 25# other peers. This peer will then wait up to P2P_SERVING_TIMEOUT_SECS seconds 26# for the test to conclude. 27P2P_SERVING_TIMEOUT_SECS = 600 28 29# The file is initialy shared by the master in two parts. The first part is 30# available at the beginning of the test, while the second part of the file 31# becomes ready in the master after P2P_SHARING_GAP_SECS seconds. 32P2P_SHARING_GAP_SECS = 90 33 34# The master and clients have to initialize the p2p service and, in the case 35# of the master, generate the first part of the file on disk. 36P2P_INITIALIZE_TIMEOUT_SECS = 90 37 38class p2p_EndToEndTest(test.test): 39 """Test to check that p2p works.""" 40 version = 1 41 42 43 def run_once(self, dut, file_id, is_master, peers, barrier): 44 self._dut = dut 45 46 file_id = '%s-%s' % (P2P_TEST_PREFIX, file_id) 47 file_temp_name = os.path.join(P2P_PATH, file_id + '.tmp') 48 file_shared_name = os.path.join(P2P_PATH, file_id + '.p2p') 49 50 # Ensure that p2p is running. 51 dut.run('start p2p || true') 52 dut.run('status p2p | grep running') 53 54 # Prepare the file - this includes specifying its final size. 55 dut.run('touch %s' % file_temp_name) 56 dut.run('setfattr -n user.cros-p2p-filesize -v %d %s' 57 % (P2P_FILE_SIZE_KB * 1000, file_temp_name)) 58 dut.run('mv %s %s' % (file_temp_name, file_shared_name)) 59 60 if is_master: 61 # The master generates a file and shares a part of it but announces 62 # the total size via the "user.cros-p2p-filesize" attribute. 63 # To ensure that the clients are retrieving this first shared part 64 # and hopefully blocking until the rest of the file is available, 65 # a sleep is included in the master side. 66 67 logging.info('Master process running.') 68 69 first_part_size_kb = P2P_FILE_SIZE_KB / 3 70 dut.run('dd if=/dev/urandom of=%s bs=1000 count=%d' 71 % (file_shared_name, first_part_size_kb)) 72 73 # This small sleep is to ensure that the new file size is updated 74 # by avahi daemon. 75 time.sleep(5) 76 77 # At this point, the master is sharing a non-empty file, signal all 78 # the clients that they can start the test. The clients should not 79 # take more and a few seconds to launch. 80 barrier.master_barrier(timeout=P2P_INITIALIZE_TIMEOUT_SECS) 81 82 # Wait some time to allow clients download a partial file. 83 time.sleep(P2P_SHARING_GAP_SECS) 84 dut.run('dd if=/dev/urandom of=%s bs=1000 count=%d' 85 ' conv=notrunc oflag=append' 86 % (file_shared_name, P2P_FILE_SIZE_KB - first_part_size_kb)) 87 else: 88 # On the client side, first wait until the master is sharing 89 # a non-empty file, otherwise p2p-client will ignore the file. 90 # The master should not take more than a few seconds to generate 91 # the file. 92 barrier.slave_barrier(timeout=P2P_INITIALIZE_TIMEOUT_SECS) 93 94 # Wait a random time in order to not launch all the downloads 95 # at the same time, otherwise all devices would be seeing 96 # num-connections < $THRESHOLD . 97 r = random.Random() 98 secs_to_sleep = r.randint(1, 10) 99 logging.debug('Sleeping %d seconds', secs_to_sleep) 100 time.sleep(secs_to_sleep) 101 102 # Attempt the file download and start sharing it while 103 # downloading it. 104 ret = dut.run('p2p-client --get-url=%s' % file_id) 105 url = ret.stdout.strip() 106 107 if not url: 108 raise error.TestFail('p2p-client returned an empty URL.') 109 else: 110 logging.info('Using URL %s', url) 111 dut.run('curl %s -o %s' % (url, file_shared_name)) 112 113 # Calculate the SHA1 (160 bits -> 40 characters when 114 # hexencoded) of the file and report this back so the 115 # server-side test can check they're all the same. 116 ret = dut.run('sha1sum %s' % file_shared_name) 117 sha1 = ret.stdout.strip()[0:40] 118 logging.info('SHA1 is %s', sha1) 119 120 # Wait for all the clients to finish and check the received SHA1. 121 if is_master: 122 try: 123 client_sha1s = barrier.master_barrier( 124 timeout=P2P_SERVING_TIMEOUT_SECS) 125 except queue_barrier.QueueBarrierTimeout: 126 raise error.TestFail("Test failed to complete in %d seconds." 127 % P2P_SERVING_TIMEOUT_SECS) 128 129 for client_sha1 in client_sha1s: 130 if client_sha1 != sha1: 131 # Wrong SHA1 received. 132 raise error.TestFail("Received SHA1 (%s) doesn't match " 133 "master's SHA1 (%s)." % (client_sha1, sha1)) 134 else: 135 try: 136 barrier.slave_barrier(sha1, timeout=P2P_SERVING_TIMEOUT_SECS) 137 except queue_barrier.QueueBarrierTimeout: 138 raise error.TestFail("Test failed to complete in %d seconds." 139 % P2P_SERVING_TIMEOUT_SECS) 140 141 142 def cleanup(self): 143 # Clean the test environment and stop sharing this file. 144 self._dut.run('rm -f %s/%s-*.p2p' % (P2P_PATH, P2P_TEST_PREFIX)) 145