diff options
author | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-14 01:28:59 +0000 |
---|---|---|
committer | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-14 01:28:59 +0000 |
commit | 8aa928c3e83ffa86f45ff44debc48a4aece5983a (patch) | |
tree | b9288d9c99f46ecfddb3e198f1bddb89d4abaa4e /native_client_sdk | |
parent | 8ca64d42684fa5d7304805a9225f6880a5cb2fa6 (diff) | |
download | chromium_src-8aa928c3e83ffa86f45ff44debc48a4aece5983a.zip chromium_src-8aa928c3e83ffa86f45ff44debc48a4aece5983a.tar.gz chromium_src-8aa928c3e83ffa86f45ff44debc48a4aece5983a.tar.bz2 |
[NaCl SDK] Add listening for POST to /ok or /fail to httpd.py.
This will allow us to XHR from example code to test.
BUG=139415
TBR=noelallen@chromium.org
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/11360235
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167561 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rwxr-xr-x | native_client_sdk/src/tools/httpd.py | 30 | ||||
-rwxr-xr-x | native_client_sdk/src/tools/run.py | 6 | ||||
-rwxr-xr-x | native_client_sdk/src/tools/tests/chrome_mock.py | 48 | ||||
-rwxr-xr-x | native_client_sdk/src/tools/tests/test_httpd.py | 115 |
4 files changed, 134 insertions, 65 deletions
diff --git a/native_client_sdk/src/tools/httpd.py b/native_client_sdk/src/tools/httpd.py index 0e2ef67..8057f91 100755 --- a/native_client_sdk/src/tools/httpd.py +++ b/native_client_sdk/src/tools/httpd.py @@ -41,6 +41,7 @@ class PluggableHTTPServer(BaseHTTPServer.HTTPServer): def __init__(self, *args, **kwargs): BaseHTTPServer.HTTPServer.__init__(self, *args) self.serve_dir = kwargs.get('serve_dir', '.') + self.test_mode = kwargs.get('test_mode', False) self.delegate_map = {} self.running = True self.result = 0 @@ -108,6 +109,13 @@ class PluggableHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): logging.info('No handler found for path %s. Using default.' % url_path) return delegate + def _SendNothingAndDie(self, result=0): + self.send_response(200, 'OK') + self.send_header('Content-type', 'text/html') + self.send_header('Content-length', '0') + self.end_headers() + self.server.Shutdown(result) + def send_head(self): delegate = self._FindDelegateForURL(self.path) if delegate: @@ -124,11 +132,7 @@ class PluggableHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): if query: params = urlparse.parse_qs(query) if '1' in params.get('quit', None): - self.send_response(200, 'OK') - self.send_header('Content-type', 'text/html') - self.send_header('Content-length', '0') - self.end_headers() - self.server.Shutdown() + self._SendNothingAndDie() return delegate = self._FindDelegateForURL(self.path) @@ -146,18 +150,23 @@ class PluggableHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): return self.base_do_POST() def base_do_POST(self): - pass + if self.server.test_mode: + if self.path == '/ok': + self._SendNothingAndDie(0) + elif self.path == '/fail': + self._SendNothingAndDie(1) class LocalHTTPServer(object): """Class to start a local HTTP server as a child process.""" - def __init__(self, dirname, port): + def __init__(self, dirname, port, test_mode): parent_conn, child_conn = multiprocessing.Pipe() self.process = multiprocessing.Process( target=_HTTPServerProcess, args=(child_conn, dirname, port, { 'serve_dir': dirname, + 'test_mode': test_mode, })) self.process.start() if parent_conn.poll(10): # wait 10 seconds @@ -270,11 +279,16 @@ def main(args): parser.add_option('--no_dir_check', help='No check to ensure serving from safe directory.', dest='do_safe_check', action='store_false', default=True) + parser.add_option('--test-mode', + help='Listen for posts to /ok or /fail and shut down the server with ' + ' errorcodes 0 and 1 respectively.', + dest='test_mode', action='store_true') options, args = parser.parse_args(args) if options.do_safe_check: SanityCheckDirectory(options.serve_dir) - server = LocalHTTPServer(options.serve_dir, int(options.port)) + server = LocalHTTPServer(options.serve_dir, int(options.port), + options.test_mode) # Serve until the client tells us to stop. When it does, it will give us an # errorcode. diff --git a/native_client_sdk/src/tools/run.py b/native_client_sdk/src/tools/run.py index 3fbd0e0..b2e859f 100755 --- a/native_client_sdk/src/tools/run.py +++ b/native_client_sdk/src/tools/run.py @@ -31,12 +31,16 @@ def main(args): parser.add_option('-E', help='Add environment variables when launching the executable.', dest='environ', action='append', default=[]) + parser.add_option('--test-mode', + help='Listen for posts to /ok or /fail and shut down the server with ' + ' errorcodes 0 and 1 respectively.', + dest='test_mode', action='store_true') options, args = parser.parse_args(args) if not args: parser.error('No executable given.') # 0 means use an ephemeral port. - server = httpd.LocalHTTPServer(options.serve_dir, 0) + server = httpd.LocalHTTPServer(options.serve_dir, 0, options.test_mode) print 'Serving %s on %s...' % (options.serve_dir, server.GetURL('')) env = copy.copy(os.environ) diff --git a/native_client_sdk/src/tools/tests/chrome_mock.py b/native_client_sdk/src/tools/tests/chrome_mock.py new file mode 100755 index 0000000..cd20e88 --- /dev/null +++ b/native_client_sdk/src/tools/tests/chrome_mock.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import optparse +import sys +import time +import urllib2 + +def PrintAndFlush(s): + print s + sys.stdout.flush() + +def main(args): + parser = optparse.OptionParser(usage='%prog [options] <URL to load>') + parser.add_option('--post', help='POST to URL.', dest='post', + action='store_true') + parser.add_option('--get', help='GET to URL.', dest='get', + action='store_true') + parser.add_option('--sleep', + help='Number of seconds to sleep after reading URL', + dest='sleep', default=0) + parser.add_option('--expect-to-be-killed', help='If set, the script will warn' + ' if it isn\'t killed before it finishes sleeping.', + dest='expect_to_be_killed', action='store_true') + options, args = parser.parse_args(args) + if len(args) != 1: + parser.error('Expected URL to load.') + + PrintAndFlush('Starting %s.' % sys.argv[0]) + + if options.post: + urllib2.urlopen(args[0], data='').read() + elif options.get: + urllib2.urlopen(args[0]).read() + else: + # Do nothing but wait to be killed. + pass + + time.sleep(float(options.sleep)) + + if options.expect_to_be_killed: + PrintAndFlush('Done sleeping. Expected to be killed.') + sys.exit(0) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/native_client_sdk/src/tools/tests/test_httpd.py b/native_client_sdk/src/tools/tests/test_httpd.py index 83390d1..01ff155 100755 --- a/native_client_sdk/src/tools/tests/test_httpd.py +++ b/native_client_sdk/src/tools/tests/test_httpd.py @@ -4,10 +4,10 @@ # found in the LICENSE file. import os -import re +import Queue import sys import subprocess -import tempfile +import threading import unittest import urllib2 @@ -21,7 +21,7 @@ import httpd class HTTPDTest(unittest.TestCase): def setUp(self): - self.server = httpd.LocalHTTPServer('.', 0) + self.server = httpd.LocalHTTPServer('.', 0, False) def tearDown(self): self.server.Shutdown() @@ -35,74 +35,77 @@ class HTTPDTest(unittest.TestCase): class RunTest(unittest.TestCase): def setUp(self): self.process = None - self.tempscript = None def tearDown(self): if self.process and self.process.returncode is None: self.process.kill() - if self.tempscript: - os.remove(self.tempscript) - def _Run(self, args=None): + @staticmethod + def _SubprocessThread(process, queue): + stdout, stderr = process.communicate() + queue.put((process.returncode, stdout, stderr)) + + def _Run(self, args=None, timeout=None): args = args or [] run_py = os.path.join(PARENT_DIR, 'run.py') cmd = [sys.executable, run_py] cmd.extend(args) self.process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = self.process.communicate() - try: - self.assertEqual(0, self.process.returncode) - except AssertionError: - print 'subprocess failed: %s:\nstdout: %s\nstderr:%s\n' % ( - ' '.join(cmd), stdout, stderr) - return stdout - - def _WriteTempScript(self, script): - fd, filename = tempfile.mkstemp(suffix='.py') - lines = script.splitlines() - assert len(lines[0]) == 0 # First line is always empty. - # Count the number of spaces after the first newline. - m = re.match(r'\s*', lines[1]) - assert m - indent = len(m.group(0)) - script = '\n'.join(line[indent:] for line in lines[1:]) - - os.write(fd, script) - os.close(fd) - self.tempscript = filename + queue = Queue.Queue() + thread = threading.Thread(target=RunTest._SubprocessThread, + args=(self.process, queue)) + thread.daemon = True + thread.start() + thread.join(timeout) + if not thread.is_alive(): + returncode, stdout, stderr = queue.get(False) + return returncode, stdout, stderr + + return -1, None, None + + def _GetChromeMockArgs(self, page, http_request_type, sleep, + expect_to_be_killed=True): + args = ['--test-mode'] + if page: + args.extend(['-P', page]) + args.append('--') + args.extend([sys.executable, os.path.join(SCRIPT_DIR, 'chrome_mock.py')]) + if http_request_type: + args.append('--' + http_request_type) + if sleep: + args.extend(['--sleep', str(sleep)]) + if expect_to_be_killed: + args.append('--expect-to-be-killed') + return args def testQuit(self): - self._WriteTempScript(r""" - import sys - import time - import urllib2 - - print 'running tempscript' - sys.stdout.flush() - f = urllib2.urlopen(sys.argv[-1] + '?quit=1') - f.read() - f.close() - time.sleep(10) - - # Should be killed before this prints. - print 'Not killed yet.' - sys.stdout.flush() - sys.exit(0) - """) - stdout = self._Run(['--', sys.executable, self.tempscript]) - self.assertTrue('running tempscript' in stdout) - self.assertTrue("Not killed yet" not in stdout) + args = self._GetChromeMockArgs('?quit=1', 'get', sleep=10) + _, stdout, _ = self._Run(args, timeout=20) + self.assertTrue('Starting' in stdout) + self.assertTrue('Expected to be killed' not in stdout) def testSubprocessDies(self): - self._WriteTempScript(r""" - import sys - print 'running tempscript' - sys.stdout.flush() - sys.exit(1) - """) - stdout = self._Run(['--', sys.executable, self.tempscript]) - self.assertTrue('running tempscript' in stdout) + args = self._GetChromeMockArgs(page=None, http_request_type=None, sleep=0, + expect_to_be_killed=False) + returncode, stdout, _ = self._Run(args, timeout=10) + self.assertNotEqual(-1, returncode) + self.assertTrue('Starting' in stdout) + + def testPostOk(self): + args = self._GetChromeMockArgs('ok', 'post', sleep=10) + returncode, stdout, _ = self._Run(args, timeout=20) + self.assertEqual(0, returncode) + self.assertTrue('Starting' in stdout) + self.assertTrue('Expected to be killed' not in stdout) + + def testPostFail(self): + args = self._GetChromeMockArgs('fail', 'post', sleep=10) + returncode, stdout, _ = self._Run(args, timeout=20) + self.assertEqual(1, returncode) + self.assertTrue('Starting' in stdout) + self.assertTrue('Expected to be killed' not in stdout) + if __name__ == '__main__': unittest.main() |