Wait for stdout on Popen

2019-08-03 09:00发布

问题:

I am trying to setting up an acceptance test harness for a flask app and I am currently struggling to wait for the app to start before making calls.

Following construct works fine:

class SpinUpTests(unittest.TestCase):
def tearDown(self):
    super().tearDown()
    self.stubby_server.kill()
    self.stubby_server.communicate()

def test_given_not_yet_running_when_created_without_config_then_started_on_default_port(self):
    self.not_yet_running(5000)

    self.stubby_server = subprocess.Popen(['python', '../../app/StubbyServer.py'], stdout=subprocess.PIPE)
    time.sleep(1)#<--- I would like to get rid of this

    self.then_started_on_port(5000)

I would like to wait on stdout for:

self.stubby_server = subprocess.Popen(['python', '../../app/StubbyServer.py'], stdout=subprocess.PIPE) time.sleep(1)#<--- I would like to get rid of this

  • Running on http://127.0.0.1:[port]/ (Press CTRL+C to quit)

I tried

for line in self.stubby_server.stdout.readline()

but readline() never finishes, tho I already see the output in the test output window.

Any ideas how I can wait for the flask app to start without having to use an explicit sleep()?

回答1:

Using the retry package, this will help overcome your problem. Ultimately, you set what you are looking to try again, what exception you want to retry on, and you can set specific timing parameters based on how you want to retry. It's pretty well documented.

Here is an example of how I solved this in one of the projects I was working on here

Here is the snippet of code that will help you, in case that link does not work:

@classmethod
def _start_app_locally(cls):
    subprocess.Popen(["fake-ubersmith"])
    retry_call(
        requests.get,
        fargs=["{}/status".format(cls.endpoint)],
        exceptions=RequestException,
        delay=1
    )

As you can see I just tried to hit my endpoint with a get using requests (the fargs are the arguments passed to requests.get as you can see it calls back the method you pass to retry_call), and based on the RequestException I was expecting, I would retry with a 1 second delay.

Finally, "fake-ubersmith" is the command that will run your server, which is ultimately your similar command of: 'python', '../../app/StubbyServer.py'