Ejemplo n.º 1
0
    def test_async_push_upload_errors(self):
        chunk = 'data_chunk'

        def _generator(_chunk_size):
            yield chunk

        def push_side_effect():
            raise IOError('Nope')

        # TODO(vadimsh): Retrying push when fetching data from a generator is
        # broken now (it reuses same generator instance when retrying).
        content_sources = (
            # generator(),
            lambda _chunk_size: [chunk], )

        for use_zip in (False, True):
            for source in content_sources:
                item = FakeItem(chunk)
                self.mock(item, 'content', source)
                storage_api = self.mock_push(push_side_effect)
                storage = isolateserver.Storage(storage_api, use_zip)
                channel = threading_utils.TaskChannel()
                storage.async_push(channel, 0, item)
                with self.assertRaises(IOError):
                    channel.pull()
                # First initial attempt + all retries.
                attempts = 1 + isolateserver.WorkerPool.RETRIES
                # Single push attempt parameters.
                expected_push = (item, item.zipped if use_zip else item.data)
                # Ensure all pushes are attempted.
                self.assertEqual([expected_push] * attempts,
                                 storage_api.pushed)
Ejemplo n.º 2
0
  def test_async_push_upload_errors(self):
    chunk = 'data_chunk'

    def push_side_effect():
      raise IOError('Nope')

    content_sources = (
        lambda: [chunk],
        lambda: [(yield chunk)],
    )

    for use_zip in (False, True):
      for source in content_sources:
        item = FakeItem(chunk)
        self.mock(item, 'content', source)
        server_ref = isolate_storage.ServerRef(
            'http://localhost:1', 'default-gzip' if use_zip else 'default')
        storage_api = MockedStorageApi(
            server_ref, {item.digest: 'push_state'}, push_side_effect)
        storage = isolateserver.Storage(storage_api)
        channel = threading_utils.TaskChannel()
        storage._async_push(channel, item, self.get_push_state(storage, item))
        with self.assertRaises(IOError):
          next(channel)
        # First initial attempt + all retries.
        attempts = 1 + storage.net_thread_pool.RETRIES
        # Single push attempt call arguments.
        expected_push = (
            item, 'push_state', item.zipped if use_zip else item.data)
        # Ensure all pushes are attempted.
        self.assertEqual(
            [expected_push] * attempts, storage_api.push_calls)
Ejemplo n.º 3
0
 def test_add_task_with_channel_retryable_error(self):
   with threading_utils.AutoRetryThreadPool([OSError], 2, 1, 1, 0) as pool:
     channel = threading_utils.TaskChannel()
     def throw(exc):
       raise exc
     pool.add_task_with_channel(channel, 0, throw, OSError())
     with self.assertRaises(OSError):
       channel.pull()
Ejemplo n.º 4
0
 def test_send_exception_raises_exception(self):
   class CustomError(Exception):
     pass
   with threading_utils.ThreadPool(1, 1, 0) as tp:
     channel = threading_utils.TaskChannel()
     tp.add_task(0, lambda: channel.send_exception(CustomError()))
     with self.assertRaises(CustomError):
       channel.pull()
 def test_timeout_exception_from_task(self):
   with threading_utils.ThreadPool(1, 1, 0) as tp:
     channel = threading_utils.TaskChannel()
     def task_func():
       raise threading_utils.TaskChannel.Timeout()
     tp.add_task(0, channel.wrap_task(task_func))
     # 'Timeout' raised by task gets transformed into 'RuntimeError'.
     with self.assertRaises(RuntimeError):
       channel.next()
Ejemplo n.º 6
0
 def test_wrap_task_raises_exception(self):
   class CustomError(Exception):
     pass
   with threading_utils.ThreadPool(1, 1, 0) as tp:
     channel = threading_utils.TaskChannel()
     def task_func():
       raise CustomError()
     tp.add_task(0, channel.wrap_task(task_func))
     with self.assertRaises(CustomError):
       channel.pull()
Ejemplo n.º 7
0
    def test_send_exception_raises_exception(self):
        class CustomError(Exception):
            pass

        with threading_utils.ThreadPool(1, 1, 0) as tp:
            channel = threading_utils.TaskChannel()
            exc_info = (CustomError, CustomError(), None)
            tp.add_task(0, lambda: channel.send_exception(exc_info))
            with self.assertRaises(CustomError):
                next(channel)
Ejemplo n.º 8
0
    def test_add_task_with_channel_fatal_error(self):
        with threading_utils.AutoRetryThreadPool([OSError], 2, 1, 1,
                                                 0) as pool:
            channel = threading_utils.TaskChannel()

            def throw(exc):
                raise exc

            pool.add_task_with_channel(channel, 0, throw, ValueError())
            with self.assertRaises(ValueError):
                next(channel)
 def test_next_timeout(self):
   with threading_utils.ThreadPool(1, 1, 0) as tp:
     channel = threading_utils.TaskChannel()
     def task_func():
       # This test ultimately relies on the condition variable primitive
       # provided by pthreads. There's no easy way to mock time for it.
       # Increase this duration if the test is flaky.
       time.sleep(0.2)
       return 123
     tp.add_task(0, channel.wrap_task(task_func))
     with self.assertRaises(threading_utils.TaskChannel.Timeout):
       channel.next(timeout=0.001)
     self.assertEqual(123, channel.next())
Ejemplo n.º 10
0
 def test_async_push(self):
     for use_zip in (False, True):
         item = FakeItem('1234567')
         storage_api = self.mock_push()
         storage = isolateserver.Storage(storage_api, use_zip)
         channel = threading_utils.TaskChannel()
         storage.async_push(channel, 0, item)
         # Wait for push to finish.
         pushed_item = channel.pull()
         self.assertEqual(item, pushed_item)
         # StorageApi.push was called with correct arguments.
         self.assertEqual([(item, item.zipped if use_zip else item.data)],
                          storage_api.pushed)
 def test_add_task_with_channel_captures_stack_trace(self):
   with threading_utils.AutoRetryThreadPool([OSError], 2, 1, 1, 0) as pool:
     channel = threading_utils.TaskChannel()
     def throw(exc):
       def function_with_some_unusual_name():
         raise exc
       function_with_some_unusual_name()
     pool.add_task_with_channel(channel, 0, throw, OSError())
     exc_traceback = ''
     try:
       channel.next()
     except OSError:
       exc_traceback = traceback.format_exc()
     self.assertIn('function_with_some_unusual_name', exc_traceback)
Ejemplo n.º 12
0
 def test_generator(self):
     channel = threading_utils.TaskChannel()
     channel.send_result(1)
     channel.send_result(2)
     channel.send_done()
     channel.send_done()
     channel.send_result(3)
     channel.send_done()
     actual = list(channel)
     self.assertEqual([1, 2], actual)
     actual = list(channel)
     self.assertEqual([], actual)
     actual = list(channel)
     self.assertEqual([3], actual)
 def test_wrap_task_exception_captures_stack_trace(self):
   class CustomError(Exception):
     pass
   with threading_utils.ThreadPool(1, 1, 0) as tp:
     channel = threading_utils.TaskChannel()
     def task_func():
       def function_with_some_unusual_name():
         raise CustomError()
       function_with_some_unusual_name()
     tp.add_task(0, channel.wrap_task(task_func))
     exc_traceback = ''
     try:
       channel.next()
     except CustomError:
       exc_traceback = traceback.format_exc()
     self.assertIn('function_with_some_unusual_name', exc_traceback)
Ejemplo n.º 14
0
 def test_async_push(self):
   for use_zip in (False, True):
     item = FakeItem('1234567')
     server_ref = isolate_storage.ServerRef(
         'http://localhost:1', 'default-gzip' if use_zip else 'default')
     storage_api = MockedStorageApi(server_ref, {item.digest: 'push_state'})
     storage = isolateserver.Storage(storage_api)
     channel = threading_utils.TaskChannel()
     storage._async_push(channel, item, self.get_push_state(storage, item))
     # Wait for push to finish.
     pushed_item = next(channel)
     self.assertEqual(item, pushed_item)
     # StorageApi.push was called with correct arguments.
     self.assertEqual(
         [(item, 'push_state', item.zipped if use_zip else item.data)],
         storage_api.push_calls)
Ejemplo n.º 15
0
    def test_async_push_generator_errors(self):
        class FakeException(Exception):
            pass

        def faulty_generator(_chunk_size):
            yield 'Hi!'
            raise FakeException('fake exception')

        for use_zip in (False, True):
            item = FakeItem('')
            self.mock(item, 'content', faulty_generator)
            storage_api = self.mock_push()
            storage = isolateserver.Storage(storage_api, use_zip)
            channel = threading_utils.TaskChannel()
            storage.async_push(channel, 0, item)
            with self.assertRaises(FakeException):
                channel.pull()
            # StorageApi's push should never complete when data can not be read.
            self.assertEqual(0, len(storage_api.pushed))
Ejemplo n.º 16
0
  def test_async_push_generator_errors(self):
    class FakeException(Exception):
      pass

    def faulty_generator():
      yield 'Hi!'
      raise FakeException('fake exception')

    for use_zip in (False, True):
      item = FakeItem('')
      self.mock(item, 'content', faulty_generator)
      server_ref = isolate_storage.ServerRef(
          'http://localhost:1', 'default-gzip' if use_zip else 'default')
      storage_api = MockedStorageApi(server_ref, {item.digest: 'push_state'})
      storage = isolateserver.Storage(storage_api)
      channel = threading_utils.TaskChannel()
      storage._async_push(channel, item, self.get_push_state(storage, item))
      with self.assertRaises(FakeException):
        next(channel)
      # StorageApi's push should never complete when data can not be read.
      self.assertEqual(0, len(storage_api.push_calls))
Ejemplo n.º 17
0
    def test_async_push_upload_errors(self):
        chunk = 'data_chunk'

        def _generator():
            yield chunk

        def push_side_effect():
            raise IOError('Nope')

        # TODO(vadimsh): Retrying push when fetching data from a generator is
        # broken now (it reuses same generator instance when retrying).
        content_sources = (
            # generator(),
            lambda: [chunk], )

        for use_zip in (False, True):
            for source in content_sources:
                item = FakeItem(chunk)
                self.mock(item, 'content', source)
                storage_api = MockedStorageApi(
                    {item.digest: 'push_state'},
                    push_side_effect,
                    namespace='default-gzip' if use_zip else 'default')
                storage = isolateserver.Storage(storage_api)
                channel = threading_utils.TaskChannel()
                storage.async_push(channel, item,
                                   self.get_push_state(storage, item))
                with self.assertRaises(IOError):
                    channel.pull()
                # First initial attempt + all retries.
                attempts = 1 + storage.net_thread_pool.RETRIES
                # Single push attempt call arguments.
                expected_push = (item, 'push_state',
                                 item.zipped if use_zip else item.data)
                # Ensure all pushes are attempted.
                self.assertEqual([expected_push] * attempts,
                                 storage_api.push_calls)
Ejemplo n.º 18
0
 def test_wrap_task_passes_exception_value(self):
     with threading_utils.ThreadPool(1, 1, 0) as tp:
         channel = threading_utils.TaskChannel()
         tp.add_task(0, channel.wrap_task(lambda: Exception()))
         self.assertTrue(isinstance(channel.pull(), Exception))
Ejemplo n.º 19
0
 def test_wrap_task_passes_simple_value(self):
     with threading_utils.ThreadPool(1, 1, 0) as tp:
         channel = threading_utils.TaskChannel()
         tp.add_task(0, channel.wrap_task(lambda: 0))
         self.assertEqual(0, channel.pull())
Ejemplo n.º 20
0
 def test_add_task_with_channel_success(self):
     with threading_utils.AutoRetryThreadPool([OSError], 2, 1, 1,
                                              0) as pool:
         channel = threading_utils.TaskChannel()
         pool.add_task_with_channel(channel, 0, lambda: 0)
         self.assertEqual(0, channel.pull())
Ejemplo n.º 21
0
def yield_results(swarm_base_url, task_keys, timeout, max_threads,
                  print_status_updates, output_collector):
    """Yields swarming task results from the swarming server as (index, result).

  Duplicate shards are ignored. Shards are yielded in order of completion.
  Timed out shards are NOT yielded at all. Caller can compare number of yielded
  shards with len(task_keys) to verify all shards completed.

  max_threads is optional and is used to limit the number of parallel fetches
  done. Since in general the number of task_keys is in the range <=10, it's not
  worth normally to limit the number threads. Mostly used for testing purposes.

  output_collector is an optional instance of TaskOutputCollector that will be
  used to fetch files produced by a task from isolate server to the local disk.

  Yields:
    (index, result). In particular, 'result' is defined as the
    GetRunnerResults() function in services/swarming/server/test_runner.py.
  """
    number_threads = (min(max_threads, len(task_keys))
                      if max_threads else len(task_keys))
    should_stop = threading.Event()
    results_channel = threading_utils.TaskChannel()

    with threading_utils.ThreadPool(number_threads, number_threads, 0) as pool:
        try:
            # Adds a task to the thread pool to call 'retrieve_results' and return
            # the results together with shard_index that produced them (as a tuple).
            def enqueue_retrieve_results(shard_index, task_key):
                task_fn = lambda *args: (shard_index, retrieve_results(*args))
                pool.add_task(0, results_channel.wrap_task(task_fn),
                              swarm_base_url, shard_index, task_key, timeout,
                              should_stop, output_collector)

            # Enqueue 'retrieve_results' calls for each shard key to run in parallel.
            for shard_index, task_key in enumerate(task_keys):
                enqueue_retrieve_results(shard_index, task_key)

            # Wait for all of them to finish.
            shards_remaining = range(len(task_keys))
            active_task_count = len(task_keys)
            while active_task_count:
                shard_index, result = None, None
                try:
                    shard_index, result = results_channel.pull(
                        timeout=STATUS_UPDATE_INTERVAL)
                except threading_utils.TaskChannel.Timeout:
                    if print_status_updates:
                        print(
                            'Waiting for results from the following shards: %s'
                            % ', '.join(map(str, shards_remaining)))
                        sys.stdout.flush()
                    continue
                except Exception:
                    logging.exception(
                        'Unexpected exception in retrieve_results')

                # A call to 'retrieve_results' finished (successfully or not).
                active_task_count -= 1
                if not result:
                    logging.error(
                        'Failed to retrieve the results for a swarming key')
                    continue

                # Yield back results to the caller.
                assert shard_index in shards_remaining
                shards_remaining.remove(shard_index)
                yield shard_index, result

        finally:
            # Done or aborted with Ctrl+C, kill the remaining threads.
            should_stop.set()
Ejemplo n.º 22
0
 def test_passes_simple_value(self):
     with threading_utils.ThreadPool(1, 1, 0) as tp:
         channel = threading_utils.TaskChannel()
         tp.add_task(0, lambda: channel.send_result(0))
         self.assertEqual(0, channel.next())
Ejemplo n.º 23
0
 def test_passes_exception_value(self):
     with threading_utils.ThreadPool(1, 1, 0) as tp:
         channel = threading_utils.TaskChannel()
         tp.add_task(0, lambda: channel.send_result(Exception()))
         self.assertTrue(isinstance(channel.next(), Exception))