From 726fd3f2bc09c7ea0c0e5725317bf41f70817a1c Mon Sep 17 00:00:00 2001 From: ddm Date: Mon, 23 Dec 2013 11:00:03 +0100 Subject: [PATCH] [FIX] Handle timeout in UI tests bzr revid: ddm@openerp.com-20131223100003-h8qhzmk61dz9bzon --- addons/website/tests/test_ui.py | 89 +++++++++++++++----- addons/website/tests/ui_suite/banner_tour.js | 17 ++++ 2 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 addons/website/tests/ui_suite/banner_tour.js diff --git a/addons/website/tests/test_ui.py b/addons/website/tests/test_ui.py index 927d407af70..32675717943 100644 --- a/addons/website/tests/test_ui.py +++ b/addons/website/tests/test_ui.py @@ -1,8 +1,10 @@ -import json -import subprocess import unittest +import subprocess import os +import select import time +import json +from openerp import tools ROOT = os.path.join(os.path.dirname(__file__), 'ui_suite') @@ -11,6 +13,26 @@ __all__ = ['load_tests', 'WebsiteUiSuite'] def _exc_info_to_string(err, test): return err +class LineReader(object): + def __init__(self, fd): + self._fd = fd + self._buf = '' + + def fileno(self): + return self._fd + + def readlines(self): + data = os.read(self._fd, 4096) + if not data: + # EOF + return None + self._buf += data + if '\n' not in data: + return [] + tmp = self._buf.split('\n') + lines, self._buf = tmp[:-1], tmp[-1] + return lines + class WebsiteUiTest(unittest.TestCase): def __init__(self, name): self.name = name @@ -20,7 +42,8 @@ class WebsiteUiTest(unittest.TestCase): return self.name class WebsiteUiSuite(unittest.TestSuite): - def __init__(self, testfile, timeout=5000): + # timeout is in seconds + def __init__(self, testfile, timeout=5): self.testfile = testfile self.timeout = timeout self._test = None @@ -31,9 +54,12 @@ class WebsiteUiSuite(unittest.TestSuite): def run(self, result): # Test if phantom is correctly installed try: - subprocess.call(['phantomjs', '-v'], - stdout=open(os.devnull, 'w'), - stderr=subprocess.STDOUT) + subprocess.call([ + 'phantomjs', + '-v' + ], + stdout=open(os.devnull, 'w'), + stderr=subprocess.STDOUT) except OSError: test = WebsiteUiTest('UI Tests') result.startTest(test) @@ -48,24 +74,45 @@ class WebsiteUiSuite(unittest.TestSuite): del result._exc_info_to_string def _run(self, result): + self._test = WebsiteUiTest(self.testfile) + self.start_time = time.time() + + phantomOptions = json.dumps({ + 'timeout': self.timeout, + 'port': tools.config['xmlrpc_port'] + }) phantom = subprocess.Popen([ 'phantomjs', os.path.join(ROOT, self.testfile), - json.dumps({ 'timeout': self.timeout }) - ], stdout=subprocess.PIPE) + phantomOptions + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) - self._test = WebsiteUiTest(self.testfile) + proc_stdout = LineReader(phantom.stdout.fileno()) + readable = [proc_stdout] + last_check_time = time.time() try: - while True: - line = phantom.stdout.readline() - if line: - # the runner expects only one result per test - self.process(line, result) - result.stopTest(self._test) - break - else: - time.sleep(0.1) + while readable and last_check_time < self.start_time + self.timeout: + ready, _, _ = select.select(readable, [], [], 0) + if not ready: + last_check_time = time.time() + continue + for stream in ready: + lines = stream.readlines() + if lines is None: + # got EOF on this stream + readable.remove(stream) + break; + for line in lines: + # the runner expects only one output line + self.process(line, result) + break + + if last_check_time >= (self.start_time + self.timeout): + result.addError(self._test, "Timeout after %s s" % (last_check_time - self.start_time )) + result.stopTest(self._test) finally: # kill phantomjs if phantom.exit() wasn't called in the test if phantom.poll() is None: @@ -81,12 +128,11 @@ class WebsiteUiSuite(unittest.TestSuite): result.startTest(self._test) try: args = json.loads(line) - event = args.get('event') - message = args.get('message', "") - + event = args.get('event', None) if event == 'success': result.addSuccess(self._test) elif event == 'failure': + message = args.get('message', "") result.addFailure(self._test, message) else: result.addError(self._test, "Unexpected message: %s" % line) @@ -95,4 +141,5 @@ class WebsiteUiSuite(unittest.TestSuite): def load_tests(loader, base, _): base.addTest(WebsiteUiSuite('sample_test.js')) + base.addTest(WebsiteUiSuite('banner_tour.js')) return base \ No newline at end of file diff --git a/addons/website/tests/ui_suite/banner_tour.js b/addons/website/tests/ui_suite/banner_tour.js new file mode 100644 index 00000000000..686f86e446e --- /dev/null +++ b/addons/website/tests/ui_suite/banner_tour.js @@ -0,0 +1,17 @@ +var options = JSON.parse(phantom.args); +var page = require('webpage').create(); +var url = 'http://localhost:'+options.port; +page.open(url, function (status) { + if (status !== 'success') { + console.log('{ "event": "failure", "message": "'+url+' failed to load"}'); + phantom.exit(); + } else { + page.evaluate(function() { + $(document).on("tour:ready", function () { + openerp.website.TestConsole.test('banner').run(true) + console.log('{ "event": "success" }'); + phantom.exit(); + }); + }); + } +}); \ No newline at end of file