Changeset 7eb4233 in mod_gnutls for test/mgstest/services.py


Ignore:
Timestamp:
Nov 28, 2020, 3:29:24 PM (2 years ago)
Author:
Fiona Klute <fiona.klute@…>
Branches:
asyncio, master
Children:
65e66c9
Parents:
32e62a3
Message:

Use asyncio to manage test services

This makes it a little easier to handle the services in parallel.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/mgstest/services.py

    r32e62a3 r7eb4233  
    1515"""Handling services needed for mod_gnutls tests"""
    1616
     17import asyncio
    1718import os
    18 import subprocess
    1919
    20 from contextlib import contextmanager
     20from contextlib import asynccontextmanager
    2121from pathlib import Path
    22 from time import sleep
    2322
    2423
     
    5857        self._step = int(os.environ.get('TEST_SERVICE_WAIT', 250)) / 1000
    5958
    60     def start(self):
     59    async def start(self):
    6160        """Start the service"""
    6261        if not self.condition():
     
    6463            return
    6564        print(f'Starting: {self.start_command}')
    66         self.process = subprocess.Popen(self.start_command,
    67                                         env=self.process_env,
    68                                         close_fds=True)
     65        self.process = await asyncio.create_subprocess_exec(
     66            *self.start_command, env=self.process_env, close_fds=True)
    6967        self.returncode = None
    7068
    71     def stop(self):
     69    async def stop(self):
    7270        """Order the service to stop"""
    7371        if not self.condition():
    7472            # skip
    7573            return
    76         if not self.process or self.process.poll():
     74        if not self.process or self.process.returncode is not None:
    7775            # process either never started or already stopped
    7876            return
     
    8078        if self.stop_command:
    8179            print(f'Stopping: {self.stop_command}')
    82             subprocess.run(self.stop_command, check=True, env=self.process_env)
     80            stop = await asyncio.create_subprocess_exec(
     81                *self.stop_command, env=self.process_env)
     82            await stop.wait()
    8383        else:
    8484            print(f'Stopping (SIGTERM): {self.start_command}')
    8585            self.process.terminate()
    8686
    87     def wait(self, timeout=None):
     87    async def wait(self, timeout=None):
    8888        """Wait for the process to terminate.
    8989
    9090        Sets returncode to the process' return code and returns it.
    9191
    92         WARNING: Calling this method without a timeout or calling
    93         stop() first will hang. An expired timeout will raise a
    94         subprocess.TimeoutExpired exception.
     92        WARNING: Calling this method without calling stop() first will
     93        hang, unless the service stops on its own.
    9594
    9695        """
    9796        if self.process:
    98             self.process.wait(timeout=timeout)
     97            await self.process.wait()
    9998            self.returncode = self.process.returncode
    10099            self.process = None
    101100            return self.returncode
    102101
    103     def wait_ready(self, timeout=None):
     102    async def wait_ready(self, timeout=None):
    104103        """Wait for the started service to be ready.
    105104
     
    114113
    115114        """
     115        if not self.condition():
     116            # skip
     117            return None
    116118        if not self.check:
    117119            return None
     
    119121        slept = 0
    120122        while not timeout or slept < timeout:
    121             if self.process and self.process.poll():
     123            if self.process and self.process.returncode is not None:
    122124                return self.process.returncode
    123125            if self.check():
    124126                return None
    125127            else:
    126                 sleep(self._step)
     128                await asyncio.sleep(self._step)
    127129                slept = slept + self._step
    128130        # TODO: A custom ServiceException or something would be nicer
     
    130132        raise TimeoutError('Waiting for service timed out!')
    131133
    132     @contextmanager
    133     def run(self):
     134    @asynccontextmanager
     135    async def run(self, ready_timeout=None):
    134136        """Context manager to start and stop a service. Note that entering the
    135137        context does not call TestService.wait_ready() on the service,
     
    138140        """
    139141        try:
    140             self.start()
    141             # TODO: with async execution we could also call
    142             # wait_ready() here
     142            await self.start()
     143            await self.wait_ready(timeout=ready_timeout)
    143144            yield self
    144145        finally:
    145             self.stop()
    146             # TODO: this would really benefit from async execution
    147             self.wait()
     146            await self.stop()
     147            await self.wait()
    148148
    149149
Note: See TracChangeset for help on using the changeset viewer.