[IMP] cron: added yaml test.

The test should probably be a standalone program as the YAML
infrastructure isnt really suited for this purpose.

bzr revid: vmt@openerp.com-20110809111008-vxh0bm08n3drw1o2
This commit is contained in:
Vo Minh Thu 2011-08-09 13:10:08 +02:00
parent ade53b64c7
commit e93d018a39
6 changed files with 118 additions and 19 deletions

View File

@ -95,6 +95,10 @@
'test/test_osv_expression.yml',
'test/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules.
'test/test_ir_values.yml',
# Commented because this takes some time.
# This must be (un)commented with the corresponding import statement
# in test/__init__.py.
# 'test/test_ir_cron.yml', # <-- These tests perform a roolback.
],
'installable': True,
'active': True,

View File

@ -20,6 +20,8 @@
##############################################################################
# Useful for manual testing of cron jobs scheduling.
# This must be (un)commented with the corresponding yml file
# in ../__openerp__.py.
# import test_ir_cron
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -19,12 +19,14 @@
#
##############################################################################
import time
from datetime import datetime
from dateutil.relativedelta import relativedelta
import openerp
JOB = {
'function': u'f',
'function': u'_0_seconds',
'interval_type': u'minutes',
'user_id': 1,
'name': u'test',
@ -83,5 +85,32 @@ class test_ir_cron(openerp.osv.osv.osv):
self.create(cr, uid, dict(JOB, name='test_3 _20_seconds B', function='_20_seconds', nextcall=t2))
self.create(cr, uid, dict(JOB, name='test_3 _20_seconds C', function='_20_seconds', nextcall=t3))
# This test assumes 4 cron threads.
def test_00(self, cr, uid):
self.test_00_set = set()
now = datetime.now()
t1 = (now + relativedelta(minutes=1)).strftime('%Y-%m-%d %H:%M:%S')
t2 = (now + relativedelta(minutes=1, seconds=5)).strftime('%Y-%m-%d %H:%M:%S')
t3 = (now + relativedelta(minutes=1, seconds=10)).strftime('%Y-%m-%d %H:%M:%S')
self.create(cr, uid, dict(JOB, name='test_00 _20_seconds_A', function='_20_seconds_A', nextcall=t1))
self.create(cr, uid, dict(JOB, name='test_00 _20_seconds_B', function='_20_seconds_B', nextcall=t2))
self.create(cr, uid, dict(JOB, name='test_00 _20_seconds_C', function='_20_seconds_C', nextcall=t3))
def _expect(self, cr, uid, to_add, to_sleep, to_expect_in, to_expect_out):
assert self.test_00_set == to_expect_in
self.test_00_set.add(to_add)
time.sleep(to_sleep)
self.test_00_set.discard(to_add)
assert self.test_00_set == to_expect_out
def _20_seconds_A(self, cr, uid):
self._expect(cr, uid, 'A', 20, set(), set(['B', 'C']))
def _20_seconds_B(self, cr, uid):
self._expect(cr, uid, 'B', 20, set('A'), set('C'))
def _20_seconds_C(self, cr, uid):
self._expect(cr, uid, 'C', 20, set(['A', 'B']), set())
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,61 @@
-
Test the cron jobs scheduling.
-
Disable the existing cron jobs if any during the tests.
-
!python {model: ir.cron }: |
# For this test to work, as it involves multiple database cursors,
# we have to commit changes. But YAML tests must be rollbacked, so
# the final database state is left untouched. So we have to be a bit
# ugly here: use our own cursor, commit, and clean after ourselves.
# We also pass around some ids using setattr/delattr, and we have to
# rollback the previous tests otherwise we won't be able to touch the
# db.
# Well, this should probably be a standalone, or regular unit test,
# instead of using the YAML infrastructure.
cr.rollback()
our_cr = self.pool.db.cursor()
try:
ids = self.search(our_cr, uid, [], {})
setattr(self, 'saved_ids', ids)
self.write(our_cr, uid, ids, {'active': False}, {})
our_cr.commit()
finally:
our_cr.close()
-
Three concurrent jobs started with a slight time gap. Assume 4 cron threads.
This will take about 2 minutes.
-
!python {model: ir.cron }: |
# Pretend initialization is already done. We the use a try/finally
# to reset _init correctly.
self.pool._init = False
our_cr = self.pool.db.cursor()
try:
self.test_00(our_cr, uid) # this will commit using the passed cursor
import openerp.cron
openerp.cron._thread_count = 4
# Wake up this db as soon as the master cron thread starts.
openerp.cron.schedule_in_advance(1, self.pool.db.dbname)
# Pretend to be the master thread, for 4 iterations.
openerp.cron.runner_body()
openerp.cron.runner_body()
openerp.cron.runner_body()
openerp.cron.runner_body()
finally:
self.pool._init = True
our_cr.close()
-
Clean after ourselves.
-
!python {model: ir.cron }: |
our_cr = self.pool.db.cursor()
try:
ids = [x for x in self.search(our_cr, uid, ['|', ('active', '=', True), ('active', '=', False)], {}) if x not in self.saved_ids]
self.unlink(our_cr, uid, ids, {})
ids = self.saved_ids
delattr(self, 'saved_ids')
self.write(our_cr, uid, ids, {'active': True}, {})
our_cr.commit()
finally:
our_cr.close()

View File

@ -151,22 +151,25 @@ def runner():
checks every 60 seconds the next database wake-up. TODO: make configurable
"""
while True:
with _wakeups_lock:
while _wakeups and _wakeups[0][0] < time.time() and get_thread_count():
task = heapq.heappop(_wakeups)
timestamp, db_name, canceled = task
if canceled:
continue
task[2] = True
registry = openerp.pooler.get_pool(db_name)
if not registry._init:
registry['ir.cron']._run_jobs()
amount = 60
with _wakeups_lock:
# Sleep less than 60s if the next known wake-up will happen before.
if _wakeups and get_thread_count():
amount = min(60, _wakeups[0][0] - time.time())
time.sleep(amount)
runner_body()
def runner_body():
with _wakeups_lock:
while _wakeups and _wakeups[0][0] < time.time() and get_thread_count():
task = heapq.heappop(_wakeups)
timestamp, db_name, canceled = task
if canceled:
continue
task[2] = True
registry = openerp.pooler.get_pool(db_name)
if not registry._init:
registry['ir.cron']._run_jobs()
amount = 60
with _wakeups_lock:
# Sleep less than 60s if the next known wake-up will happen before.
if _wakeups and get_thread_count():
amount = min(60, _wakeups[0][0] - time.time())
time.sleep(amount)
def start_master_thread():

View File

@ -88,8 +88,8 @@ class Registry(object):
""" Make the cron thread care about this registry/database jobs.
This will initiate the cron thread to check for any pending jobs for
this registry/database as soon as possible. Then it will continously
monitors the ir.cron model for future jobs. See openerp.cron for
this registry/database as soon as possible. Then it will continuously
monitor the ir.cron model for future jobs. See openerp.cron for
details.
"""