[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 -*-
import os
import glob
import openerp
from openerp.tests import common
class test_phantom(common.HttpCase):
def test_01_dummy(self):
self.phantomjs(openerp.modules.module.get_module_resource('base','tests','test_phantom_dummy.js'))
class test_phantom(openerp.tests.HttpCase):
def test_phantom(self):
fname, _ = os.path.splitext(__file__)
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:

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)
if not result.wasSuccessful():
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):
""" 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 logging
import os
import select
import subprocess
import sys
import threading
import time
import unittest2
import uuid
import xmlrpclib
import logging
import sys
import openerp
# backward compatbility
common = sys.modules['openerp.tests.common'] = sys.modules['openerp.tests']
_logger = logging.getLogger(__name__)
@ -140,15 +138,12 @@ class HttpCase(SingleTransactionCase):
def phantomjs(self, jsfile, timeout=30, options=None):
""" Phantomjs Test protocol.
Use console.log in phantomjs to output test results evrey line must be
a one line JSON message using the following format:
Use console.log in phantomjs to output test results:
- for a success: { "event": "success", "message": "Log message" }
- for an error: { "event": "error", "message": "Short error description" }
- for a success: console.log("ok")
- for an error: console.log("error")
if a non json parsable line is received the helper will raise an
exception, the output buffer will be printed and phantom will be
killed
Other lines are relayed to the test log.
"""
self.timeout = timeout
@ -156,38 +151,35 @@ class HttpCase(SingleTransactionCase):
'timeout' : timeout,
'port': PORT,
'db': DB,
'user': ADMIN_USER,
'login': ADMIN_USER,
'password': ADMIN_PASSWORD,
'session_id': self.session_id,
}
if options:
self.options.update(options)
self.ignore_filters = [
# 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",
]
phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
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)
try:
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
_logger.info("phantomjs not found, test %s skipped", jsfile)
try:
t0 = time.time()
buf = ''
while 1:
# 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)
if ready:
s = phantom.stdout.read(4096)
s = phantom.stdout.read(1)
if s:
buf += s
else:
@ -196,20 +188,12 @@ class HttpCase(SingleTransactionCase):
# process lines
if '\n' in buf:
line, buf = buf.split('\n', 1)
if line not in self.ignore_filters:
try:
line_json = json.loads(line)
if line_json.get('event') == 'success':
_logger.info(line_json.get('message','ok'))
continue
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)
_logger.info("phantomjs: %s", line)
if line == "ok":
_logger.info("phantomjs test successful")
return
if line == "error":
raise Exception("phantomjs test failed")
finally:
# kill phantomjs if phantom.exit() wasn't called in the test
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: