Commit 7d34f032 authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Keep a reference of Test Component module on ERP5TypeTestLoader.

All other Component modules must be kept alive during the REQUEST life (f523edc4).
However, Unit Tests modules should be kept alive until it finished executing and
this may span accross multiple REQUESTS.

Issue found out when migrating testBusinessTemplate to erp5_core_test which was
failing as the module was GC'ed and its top-level variables were reset to None by
the interpreter.
parent de85c464
...@@ -202,15 +202,12 @@ class ERP5TypeTestReLoader(ERP5TypeTestLoader): ...@@ -202,15 +202,12 @@ class ERP5TypeTestReLoader(ERP5TypeTestLoader):
otherwise fallback on filesystem otherwise fallback on filesystem
""" """
if module is None: if module is None:
import erp5.component.test
try: try:
__import__('erp5.component.test.' + name.split('.')[0], self._importZodbTestComponent(name.split('.')[0])
fromlist=['erp5.component.test'],
level=0)
except ImportError: except ImportError:
pass pass
else: else:
import erp5.component.test
module = erp5.component.test module = erp5.component.test
return super(ERP5TypeTestReLoader, self).loadTestsFromName(name, return super(ERP5TypeTestReLoader, self).loadTestsFromName(name,
......
...@@ -278,6 +278,16 @@ class ERP5TypeTestLoader(unittest.TestLoader): ...@@ -278,6 +278,16 @@ class ERP5TypeTestLoader(unittest.TestLoader):
lambda self: self._testMethodPrefix, lambda self: self._testMethodPrefix,
lambda self, value: None) lambda self, value: None)
def _importZodbTestComponent(self, name):
import erp5.component.test
module = __import__('erp5.component.test.' + name,
fromlist=['erp5.component.test'],
level=0)
try:
self._test_component_ref_list.append(module)
except AttributeError:
self._test_component_ref_list = [module]
def loadTestsFromName(self, name, module=None): def loadTestsFromName(self, name, module=None):
""" """
This method is here for compatibility with old style arguments: This method is here for compatibility with old style arguments:
...@@ -308,17 +318,13 @@ class ERP5TypeTestLoader(unittest.TestLoader): ...@@ -308,17 +318,13 @@ class ERP5TypeTestLoader(unittest.TestLoader):
if ComponentTestCase not in ERP5TypeTestCase.__bases__: if ComponentTestCase not in ERP5TypeTestCase.__bases__:
ERP5TypeTestCase.__bases__ = ComponentTestCase, ERP5TypeTestCase.__bases__ = ComponentTestCase,
# TestLoader() does not perform any import so import the Module manually # `./runUnitTest erp5_base:testBase` executes Unit Test from
module = __import__('erp5.component.test', # erp5.component.testBase Module. This needs be imported beforehand:
fromlist=['erp5.component.test'], # unittest loadTestsFromName() will then `getattr(module, name)`
level=0)
# TODO-arnau: What about loading a test for a specific Component Version?
name = name.split(':')[1] name = name.split(':')[1]
import erp5.component.test
__import__('erp5.component.test.%s' % name.split('.')[0], module = erp5.component.test
['erp5.component.test'], self._importZodbTestComponent(name.split('.')[0])
level=0)
return super(ERP5TypeTestLoader, self).loadTestsFromName(name, module) return super(ERP5TypeTestLoader, self).loadTestsFromName(name, module)
......
...@@ -2829,6 +2829,7 @@ class TestZodbTestComponent(_TestZodbComponent): ...@@ -2829,6 +2829,7 @@ class TestZodbTestComponent(_TestZodbComponent):
def _getValidSourceCode(self, *_): def _getValidSourceCode(self, *_):
return '''from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase return '''from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
import os
class Test(ERP5TypeTestCase): class Test(ERP5TypeTestCase):
def getTitle(self): def getTitle(self):
...@@ -2851,6 +2852,12 @@ class Test(ERP5TypeTestCase): ...@@ -2851,6 +2852,12 @@ class Test(ERP5TypeTestCase):
def test_01_sampleTest(self): def test_01_sampleTest(self):
self.assertEqual(0, 0) self.assertEqual(0, 0)
def afterClear(self):
super(Test, self).afterClear()
# Checked that this module has not been GC'ed until the very end...
self.assertNotEqual(os, None)
''' '''
def testRunLiveTest(self): def testRunLiveTest(self):
...@@ -2864,6 +2871,27 @@ class Test(ERP5TypeTestCase): ...@@ -2864,6 +2871,27 @@ class Test(ERP5TypeTestCase):
component.validate() component.validate()
self.tic() self.tic()
from Products.ERP5Type.tests.runUnitTest import ERP5TypeTestLoader
ERP5TypeTestLoader_loadTestsFromNames = ERP5TypeTestLoader.loadTestsFromNames
def loadTestsFromNames(self, *args, **kwargs):
"""
Monkey patched to simulate a reset right after importing the ZODB Test
Component whose Unit Tests are going to be executed
"""
ret = ERP5TypeTestLoader_loadTestsFromNames(self, *args, **kwargs)
from Products.ERP5.ERP5Site import getSite
getSite().portal_components.reset(force=True)
# Simulate a new REQUEST while the old one has been GC'ed
import erp5.component
erp5.component.ref_manager.clear()
import gc
gc.collect()
return ret
self.assertEqual(component.getValidationState(), 'validated') self.assertEqual(component.getValidationState(), 'validated')
self.assertModuleImportable('testRunLiveTest') self.assertModuleImportable('testRunLiveTest')
self._component_tool.reset(force=True, self._component_tool.reset(force=True,
...@@ -2872,10 +2900,12 @@ class Test(ERP5TypeTestCase): ...@@ -2872,10 +2900,12 @@ class Test(ERP5TypeTestCase):
# ERP5TypeLiveTestCase.runLiveTest patches ERP5TypeTestCase bases, thus it # ERP5TypeLiveTestCase.runLiveTest patches ERP5TypeTestCase bases, thus it
# needs to be restored after calling runLiveTest # needs to be restored after calling runLiveTest
base_tuple = ERP5TypeTestCase.__bases__ base_tuple = ERP5TypeTestCase.__bases__
ERP5TypeTestLoader.loadTestsFromNames = loadTestsFromNames
try: try:
self._component_tool.runLiveTest('testRunLiveTest') self._component_tool.runLiveTest('testRunLiveTest')
finally: finally:
ERP5TypeTestCase.__bases__ = base_tuple ERP5TypeTestCase.__bases__ = base_tuple
ERP5TypeTestLoader.loadTestsFromNames = ERP5TypeTestLoader_loadTestsFromNames
# assertRegexpMatches is only available from Python >= 2.7 # assertRegexpMatches is only available from Python >= 2.7
import re import re
...@@ -2899,10 +2929,12 @@ class Test(ERP5TypeTestCase): ...@@ -2899,10 +2929,12 @@ class Test(ERP5TypeTestCase):
reset_portal_type_at_transaction_boundary=True) reset_portal_type_at_transaction_boundary=True)
base_tuple = ERP5TypeTestCase.__bases__ base_tuple = ERP5TypeTestCase.__bases__
ERP5TypeTestLoader.loadTestsFromNames = loadTestsFromNames
try: try:
self._component_tool.runLiveTest('testRunLiveTest') self._component_tool.runLiveTest('testRunLiveTest')
finally: finally:
ERP5TypeTestCase.__bases__ = base_tuple ERP5TypeTestCase.__bases__ = base_tuple
ERP5TypeTestLoader.loadTestsFromNames = ERP5TypeTestLoader_loadTestsFromNames
# assertRegexpMatches is only available from Python >= 2.7 # assertRegexpMatches is only available from Python >= 2.7
import re import re
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment