def _testPipeLoggerToPipe(self, test_string, loop=None):
        """
		Test PipeLogger writing to a pipe connected to a PipeReader.
		This verifies that PipeLogger does not deadlock when writing
		to a pipe that's drained by a PipeReader running in the same
		process (requires non-blocking write).
		"""

        producer = PopenProcess(proc=subprocess.Popen(
            ["bash", "-c", self._echo_cmd % test_string],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT),
                                scheduler=loop)

        pr, pw = os.pipe()

        consumer = producer.pipe_reader = PipeLogger(
            background=True,
            input_fd=producer.proc.stdout,
            log_file_path=os.fdopen(pw, 'wb', 0))

        reader = _reader(pr, loop=loop)
        yield producer.async_start()
        content = yield reader
        yield producer.async_wait()
        yield consumer.async_wait()

        self.assertEqual(producer.returncode, os.EX_OK)
        self.assertEqual(consumer.returncode, os.EX_OK)

        coroutine_return(content.decode('ascii', 'replace'))
Beispiel #2
0
    async def _testPipeLoggerToPipe(self, test_string, loop):
        """
		Test PipeLogger writing to a pipe connected to a PipeReader.
		This verifies that PipeLogger does not deadlock when writing
		to a pipe that's drained by a PipeReader running in the same
		process (requires non-blocking write).
		"""

        input_fd, writer_pipe = os.pipe()
        _set_nonblocking(writer_pipe)
        writer_pipe = os.fdopen(writer_pipe, 'wb', 0)
        writer = asyncio.ensure_future(
            _writer(writer_pipe, test_string.encode('ascii')))
        writer.add_done_callback(lambda writer: writer_pipe.close())

        pr, pw = os.pipe()

        consumer = PipeLogger(background=True,
                              input_fd=input_fd,
                              log_file_path=os.fdopen(pw, 'wb', 0),
                              scheduler=loop)
        consumer.start()

        # Before starting the reader, wait here for a moment, in order
        # to exercise PipeLogger's handling of EAGAIN during write.
        await asyncio.wait([writer], timeout=0.01)

        reader = _reader(pr)
        await writer
        content = await reader
        await consumer.async_wait()

        self.assertEqual(consumer.returncode, os.EX_OK)

        return content.decode('ascii', 'replace')
Beispiel #3
0
    def communicate(self, input=None):
        """
		Read data from stdout and stderr, until end-of-file is reached.
		Wait for process to terminate.

		@param input: stdin content to write
		@type input: bytes
		@return: tuple (stdout_data, stderr_data)
		@rtype: asyncio.Future (or compatible)
		"""
        futures = []
        for input_file in (self._proc.stdout, self._proc.stderr):
            if input_file is None:
                future = self._loop.create_future()
                future.set_result(None)
            else:
                future = _reader(input_file, loop=self._loop)
            futures.append(future)

        writer = None
        if input is not None:
            if self._proc.stdin is None:
                raise TypeError(
                    'communicate: expected file or int, got {}'.format(
                        type(self._proc.stdin)))
            stdin = self._proc.stdin
            stdin = os.fdopen(stdin, 'wb', 0) if isinstance(stdin,
                                                            int) else stdin
            _set_nonblocking(stdin.fileno())
            writer = asyncio.ensure_future(_writer(stdin,
                                                   input,
                                                   loop=self._loop),
                                           loop=self._loop)
            writer.add_done_callback(lambda writer: stdin.close())

        try:
            yield asyncio.wait(futures + [self.wait()], loop=self._loop)
        finally:
            if writer is not None:
                if writer.done():
                    # Consume expected exceptions.
                    try:
                        writer.result()
                    except EnvironmentError:
                        # This is normal if the other end of the pipe was closed.
                        pass
                else:
                    writer.cancel()

        coroutine_return(tuple(future.result() for future in futures))