[IMP] phantomjs testing

- avoid dbmanager by presetting db in the test session
- correctly handle login option
- serialize test cursor access

bzr revid: al@openerp.com-20140216212222-4o6x9uljyua3g1og
This commit is contained in:
Antony Lesuisse 2014-02-16 22:22:22 +01:00
parent 42db02f73c
commit c8324bafcc
7 changed files with 71 additions and 52 deletions

View File

@ -4,10 +4,14 @@ import os
import openerp
class TestUi(openerp.tests.HttpCase):
def test_js(self):
self.phantom_js('/',"console.log('ok')","console", login=None)
def test_jsfile(self):
def test_01_jsfile_ui_hello(self):
self.phantom_jsfile(os.path.join(os.path.dirname(__file__), 'test_ui_hello.js'))
def test_02_jsfile_ui_load(self):
self.phantom_jsfile(os.path.join(os.path.dirname(__file__), 'test_ui_load.js'))
def test_03_js_public(self):
self.phantom_js('/',"console.log('ok')","console")
def test_04_js_admin(self):
self.phantom_js('/',"console.log('ok')","openerp.client.action_manager.inner_widget.views.kanban", login='admin')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

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

View File

@ -3,26 +3,23 @@ import time
import unittest2
import xmlrpclib
from openerp.tests import common
import openerp
DB = common.DB
ADMIN_USER = common.ADMIN_USER
ADMIN_USER_ID = common.ADMIN_USER_ID
ADMIN_PASSWORD = common.ADMIN_PASSWORD
DB = openerp.tests.common.DB
class test_xmlrpc(common.HttpCase):
class test_xmlrpc(openerp.tests.common.HttpCase):
def test_01_xmlrpc_login(self):
""" Try to login on the common service. """
uid = self.xmlrpc_common.login(DB, ADMIN_USER, ADMIN_PASSWORD)
self.assertTrue(uid == ADMIN_USER_ID)
uid = self.xmlrpc_common.login(DB, 'admin', 'admin')
self.assertTrue(uid == 1)
def test_xmlrpc_ir_model_search(self):
""" Try a search on the object service. """
o = self.xmlrpc_object
ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [])
ids = o.execute(DB, 1, 'admin', 'ir.model', 'search', [])
self.assertIsInstance(ids, list)
ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [], {})
ids = o.execute(DB, 1, 'admin', 'ir.model', 'search', [], {})
self.assertIsInstance(ids, list)
# This test was written to test the creation of a new RPC endpoint, not

View File

@ -168,9 +168,9 @@ class WebRequest(object):
"""
# some magic to lazy create the cr
if not self._cr:
if openerp.tools.config['test_enable'] and self.session_id in openerp.tests.common.HTTP_SESSION:
self._cr = openerp.tests.common.HTTP_SESSION[self.session_id]
else:
# Test cursors
self._cr = openerp.tests.common.acquire_test_cursor(self.session_id)
if not self._cr:
self._cr = self.registry.db.cursor()
return self._cr
@ -180,10 +180,13 @@ class WebRequest(object):
def __exit__(self, exc_type, exc_value, traceback):
_request_stack.pop()
if self._cr and not (openerp.tools.config['test_enable'] and self.session_id in openerp.tests.common.HTTP_SESSION):
if exc_type is None:
self._cr.commit()
self._cr.close()
if self._cr:
# Dont commit test cursors
if not openerp.tests.common.release_test_cursor(self.session_id):
if exc_type is None:
self._cr.commit()
self._cr.close()
# just to be sure no one tries to re-use the request
self.disable_db = True
self.uid = None
@ -595,7 +598,7 @@ class Service(object):
class Model(object):
"""
.. deprecated:: 8.0
Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
Use the resistry and cursor in ``openerp.http.request`` instead.
"""
def __init__(self, session, model):
self.session = session

View File

@ -209,15 +209,6 @@ class TestRLock(object):
def __exit__(self, type, value, traceback):
self.release()
# def __enter__(self, *l, **kw):
# if openerp.tools.config['test_enable']:
# return
# return super(TestRlock, self).__enter__(*l, **kw)
# def __exit__(self, *l, **kw):
# if openerp.tools.config['test_enable']:
# return
# return super(TestRlock, self).__exit__(*l, **kw)
class RegistryManager(object):
""" Model registries manager.

View File

@ -15,6 +15,7 @@ import time
import unittest2
import uuid
import xmlrpclib
import threading
import openerp
@ -25,20 +26,36 @@ ADDONS_PATH = openerp.tools.config['addons_path']
HOST = '127.0.0.1'
PORT = openerp.tools.config['xmlrpc_port']
DB = openerp.tools.config['db_name']
# If the database name is not provided on the command-line,
# use the one on the thread (which means if it is provided on
# the command-line, this will break when installing another
# database from XML-RPC).
if not DB and hasattr(threading.current_thread(), 'dbname'):
DB = threading.current_thread().dbname
ADMIN_USER = 'admin'
# Useless constant, tests are aware of the content of demo data
ADMIN_USER_ID = openerp.SUPERUSER_ID
ADMIN_PASSWORD = 'admin'
# Magic session_id, unfortunately we have to serialize access to the cursors to
# serialize requests. We first tried to duplicate the database for each tests
# but this proved too slow. Any idea to improve this is welcome.
HTTP_SESSION = {}
def acquire_test_cursor(session_id):
if openerp.tools.config['test_enable']:
cr = HTTP_SESSION.get(session_id)
if cr:
cr._test_lock.acquire()
return cr
def release_test_cursor(session_id):
if openerp.tools.config['test_enable']:
cr = HTTP_SESSION.get(session_id)
if cr:
cr._test_lock.release()
return True
return False
class BaseCase(unittest2.TestCase):
"""
Subclass of TestCase for common OpenERP-specific code.
@ -126,9 +143,15 @@ class HttpCase(TransactionCase):
def setUp(self):
super(HttpCase, self).setUp()
self.session_id = uuid.uuid4().hex
# setup a magic session_id that will be rollbacked
self.session = openerp.http.root.session_store.new()
self.session_id = self.session.sid
self.session.db = DB
openerp.http.root.session_store.save(self.session)
self.cr._test_lock = threading.RLock()
HTTP_SESSION[self.session_id] = self.cr
def tearDown(self):
del HTTP_SESSION[self.session_id]
super(HttpCase, self).tearDown()
@ -198,8 +221,9 @@ class HttpCase(TransactionCase):
cmd = ['phantomjs', jsfile, phantomtest, json.dumps(options)]
self.phantom_run(cmd, timeout)
def phantom_js(self, url_path, code, ready="window", timeout=30, **kw):
def phantom_js(self, url_path, code, ready="window", login=None, timeout=30, **kw):
""" Test js code running in the browser
- optionnally log as 'login'
- load page given by url_path
- wait for ready object to be available
- eval(code) inside the page
@ -213,17 +237,17 @@ class HttpCase(TransactionCase):
If neither are done before timeout test fails.
"""
options = {
'port': PORT,
'db': DB,
'url_path': url_path,
'code': code,
'ready': ready,
'timeout' : timeout,
'port': PORT,
'db': DB,
'login': ADMIN_USER,
'password': ADMIN_PASSWORD,
'login' : login,
'session_id': self.session_id,
}
options.update(kw)
options.setdefault('password', options.get('login'))
phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
cmd = ['phantomjs', phantomtest, json.dumps(options)]
self.phantom_run(cmd, timeout)

View File

@ -24,11 +24,7 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) {
function PhantomTest() {
var self = this;
if(phantom.args.length === 1) {
this.options = JSON.parse(phantom.args[0]);
} else {
this.options = JSON.parse(phantom.args[1]);
}
this.options = JSON.parse(phantom.args[phantom.args.length-1]);
this.inject = [];
this.timeout = this.options.timeout ? Math.round(parseFloat(this.options.timeout)*1000 - 5000) : 10000;
this.origin = 'http://localhost';
@ -44,15 +40,15 @@ function PhantomTest() {
};
// ----------------------------------------------------
// configure page
// configure phantom and page
// ----------------------------------------------------
this.page = require('webpage').create();
this.page.viewportSize = { width: 1366, height: 768 };
this.page.addCookie({
phantom.addCookie({
'domain': 'localhost',
'name': 'session_id',
'value': this.options.session_id,
});
this.page = require('webpage').create();
this.page.viewportSize = { width: 1366, height: 768 };
this.page.onError = function(message, trace) {
self.error(message + " " + trace);
};
@ -101,7 +97,7 @@ function PhantomTest() {
qp.push('login=' + self.options.login);
qp.push('key=' + self.options.password);
qp.push('redirect=' + encodeURIComponent(url_path));
var url_path = "/web/login?" + qp.join('&');
var url_path = "/login?" + qp.join('&');
}
var url = self.origin + url_path;
self.page.open(url, function(status) {
@ -116,7 +112,7 @@ function PhantomTest() {
try {
r = !!eval(ready);
} catch(ex) {
console.log("waiting for page " + ready)
console.log("waiting for " + ready)
};
return r;
}, ready);