Home | History | Annotate | Download | only in p2p_EndToEndTest
      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 
      5 import logging
      6 import os
      7 import random
      8 import time
      9 
     10 from autotest_lib.client.common_lib import error
     11 from autotest_lib.server import test
     12 from autotest_lib.server.cros import queue_barrier
     13 
     14 
     15 # P2P_PATH is the path where the p2p server expects the sharing files.
     16 P2P_PATH = '/var/cache/p2p'
     17 
     18 # Prefix all the test files with P2P_TEST_PREFIX.
     19 P2P_TEST_PREFIX = 'p2p-test'
     20 
     21 # File size of the shared file in KB.
     22 P2P_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.
     27 P2P_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.
     32 P2P_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.
     36 P2P_INITIALIZE_TIMEOUT_SECS = 90
     37 
     38 class 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