[IMP] phantomtest helper

bzr revid: al@openerp.com-20140209223917-vruzjvl0mtsqoo87
This commit is contained in:
Antony Lesuisse 2014-02-09 23:39:17 +01:00
parent e6ac29ee43
commit 1f67b2165c
9 changed files with 167 additions and 47 deletions

View File

@ -1,11 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import glob
import openerp import openerp
from openerp.tests import common
class test_phantom(common.HttpCase): class test_phantom(openerp.tests.HttpCase):
def test_phantom(self):
def test_01_dummy(self): fname, _ = os.path.splitext(__file__)
self.phantomjs(openerp.modules.module.get_module_resource('base','tests','test_phantom_dummy.js')) for i in glob.glob('%s*.js' % fname):
self.phantomjs(openerp.modules.module.get_module_resource('base','tests', i))
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,4 +0,0 @@
console.log('{ "event": "success", "message": "Phantomjs success"}');
// For a failure:
// console.log('{ "event": "failure", "message": "The test failed" }');
phantom.exit();

View File

@ -0,0 +1,5 @@
console.log("hello from test_phantom_hello.js");
console.log("ok");
// For a failure use:
//console.log("error");
phantom.exit();

View File

@ -0,0 +1,6 @@
// Load helper
phantom.injectJs(phantom.args[0]);
pt = new PhantomTest();
pt.run("/", "console.log('ok')", "console");

View File

@ -0,0 +1,6 @@
// Load helper
phantom.injectJs(phantom.args[0]);
pt = new PhantomTest();
pt.run_admin("/", "console.log('ok')", "console");

View File

@ -845,7 +845,7 @@ def load_test_file_py(test_file):
result = unittest2.TextTestRunner(verbosity=2, stream=openerp.modules.module.TestStream()).run(suite) result = unittest2.TextTestRunner(verbosity=2, stream=openerp.modules.module.TestStream()).run(suite)
if not result.wasSuccessful(): if not result.wasSuccessful():
r = False r = False
_logger.error('module %s: at least one error occurred in a test', module_name) _logger.error('%s: at least one error occurred in a test', test_file)
def preload_registries(dbnames): def preload_registries(dbnames):
""" Preload a registries, possibly run a test file.""" """ Preload a registries, possibly run a test file."""

View File

@ -0,0 +1,2 @@
import common
from common import *

View File

@ -5,20 +5,18 @@ helpers and classes to write tests.
""" """
import json import json
import logging
import os import os
import select import select
import subprocess import subprocess
import sys
import threading import threading
import time import time
import unittest2 import unittest2
import uuid import uuid
import xmlrpclib import xmlrpclib
import logging
import sys
import openerp import openerp
# backward compatbility
common = sys.modules['openerp.tests.common'] = sys.modules['openerp.tests']
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -140,15 +138,12 @@ class HttpCase(SingleTransactionCase):
def phantomjs(self, jsfile, timeout=30, options=None): def phantomjs(self, jsfile, timeout=30, options=None):
""" Phantomjs Test protocol. """ Phantomjs Test protocol.
Use console.log in phantomjs to output test results evrey line must be Use console.log in phantomjs to output test results:
a one line JSON message using the following format:
- for a success: { "event": "success", "message": "Log message" } - for a success: console.log("ok")
- for an error: { "event": "error", "message": "Short error description" } - for an error: console.log("error")
if a non json parsable line is received the helper will raise an Other lines are relayed to the test log.
exception, the output buffer will be printed and phantom will be
killed
""" """
self.timeout = timeout self.timeout = timeout
@ -156,38 +151,35 @@ class HttpCase(SingleTransactionCase):
'timeout' : timeout, 'timeout' : timeout,
'port': PORT, 'port': PORT,
'db': DB, 'db': DB,
'user': ADMIN_USER, 'login': ADMIN_USER,
'password': ADMIN_PASSWORD, 'password': ADMIN_PASSWORD,
'session_id': self.session_id, 'session_id': self.session_id,
} }
if options: if options:
self.options.update(options) self.options.update(options)
self.ignore_filters = [ phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
# Ignore phantomjs warnings
"*** WARNING:",
# Fixes an issue with PhantomJS 1.9.2 on OS X 10.9 (Mavericks)
# cf. https://github.com/ariya/phantomjs/issues/11418
"CoreText performance note",
]
cmd = ['phantomjs', jsfile, json.dumps(self.options)] # phantom.args[0] == phantomtest path
# phantom.args[1] == options
cmd = ['phantomjs', jsfile, phantomtest, json.dumps(self.options)]
_logger.info('executing %s', cmd) _logger.info('executing %s', cmd)
try: try:
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError: except OSError:
_logger.info("phantomjs not found, test %s skipped", jsfile) _logger.info("phantomjs not found, test %s skipped", jsfile)
try: try:
t0 = time.time() t0 = time.time()
buf = '' buf = ''
while 1: while 1:
# timeout
if time.time() > t0 + self.timeout: if time.time() > t0 + self.timeout:
raise Exception("Phantom js timeout (%ss)" % self.timeout) raise Exception("phantomjs test timeout (%ss)" % self.timeout)
# read a byte
ready, _, _ = select.select([phantom.stdout], [], [], 0.5) ready, _, _ = select.select([phantom.stdout], [], [], 0.5)
if ready: if ready:
s = phantom.stdout.read(4096) s = phantom.stdout.read(1)
if s: if s:
buf += s buf += s
else: else:
@ -196,20 +188,12 @@ class HttpCase(SingleTransactionCase):
# process lines # process lines
if '\n' in buf: if '\n' in buf:
line, buf = buf.split('\n', 1) line, buf = buf.split('\n', 1)
if line not in self.ignore_filters: _logger.info("phantomjs: %s", line)
try: if line == "ok":
line_json = json.loads(line) _logger.info("phantomjs test successful")
if line_json.get('event') == 'success': return
_logger.info(line_json.get('message','ok')) if line == "error":
continue raise Exception("phantomjs test failed")
elif line_json.get('event') == 'error':
err = line_json.get('message','error')
_logger.info(err)
else:
err = line + buf
except ValueError:
err = line + buf
raise Exception(err)
finally: finally:
# kill phantomjs if phantom.exit() wasn't called in the test # kill phantomjs if phantom.exit() wasn't called in the test
if phantom.poll() is None: if phantom.poll() is None:

View File

@ -0,0 +1,118 @@
// Phantomjs openerp helper
function waitFor (ready, callback, timeout, timeoutMessageCallback) {
timeout = timeout || 10000;
var start = new Date().getTime();
var condition = ready();
var interval = setInterval(function() {
if ((new Date().getTime() - start < timeout) && !condition ) {
condition = ready();
} else {
if(!condition) {
var message = timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms";
console.log(message);
console.log("Waiting for " + ready);
console.log("error");
phantom.exit(1);
} else {
clearInterval(interval);
callback();
}
}
}, 250);
}
function PhantomTest() {
var self = this;
this.options = JSON.parse(phantom.args[1]);
this.inject = [];
this.timeout = this.options.timeout ? Math.round(parseFloat(this.options.timeout)*1000 - 5000) : 10000;
this.origin = 'http://localhost';
this.origin += this.options.port ? ':' + this.options.port : '';
// ----------------------------------------------------
// test reporting
// ----------------------------------------------------
this.error = function(message) {
console.log(message);
console.log("error");
phantom.exit(1);
};
// ----------------------------------------------------
// configure page
// ----------------------------------------------------
this.page = require('webpage').create();
this.page.viewportSize = { width: 1366, height: 768 };
this.page.addCookie({
'domain': 'localhost',
'name': 'session_id',
'value': this.options.session_id,
});
this.page.onError = function(message, trace) {
self.error(message + " " + trace);
};
this.page.onAlert = function(message) {
self.error(message);
};
this.page.onConsoleMessage = function(message) {
console.log(message);
};
this.page.onLoadFinished = function(status) {
if (status === "success") {
for (var k in self.inject) {
if(!page.injectJs(self.inject[k])) {
self.error("Can't inject " + self.inject[k]);
}
}
}
};
setTimeout(function () {
self.page.evaluate(function () {
var message = ("Timeout\nhref: " + window.location.href
+ "\nreferrer: " + document.referrer
+ "\n\n" + document.body.innerHTML).replace(/[^a-z0-9\s~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "*");
self.error(message);
});
}, self.timeout);
// ----------------------------------------------------
// run test
// ----------------------------------------------------
this.run = function(url_path, code, ready) {
var url = self.origin + url_path;
self.page.open(url, function(status) {
if (status !== 'success') {
self.error("failed to load " + url)
} else {
console.log('loaded', url, status);
// process ready
waitFor(function() {
return self.page.evaluate(function (ready) {
var r = false;
try {
r = !!eval(ready);
} catch(ex) {
console.log("waiting for page " + ready)
};
return r;
}, ready);
// run test
}, function() {
self.page.evaluate(function (code) { return eval(code); }, code);
});
}
});
};
this.run_admin = function(url_path, code, ready) {
qp = [];
qp.push('db=' + self.options.db);
qp.push('login=' + self.options.login);
qp.push('key=' + self.options.password);
qp.push('redirect=' + encodeURIComponent(url_path));
var url_path2 = "/web/login?" + qp.join('&');
return self.run(url_path2, code, ready);
};
}
// vim:et: