Commit 25eb8920 authored by Jérome Perrin's avatar Jérome Perrin

tests: execute `addCleanup` cleanups with ZODB connection

unittest executes the cleanups after `tearDown`, after the ZODB
connection is closed, so accessing database objects cause errors.

According to python unittest documentation, it is safe to call
`doCleanups` ourselves when we need the cleanup to be executed earlier,
this is a typical case where we want the cleanup to be called before
closing the database connections.
parent 4350a316
Pipeline #27864 failed with stage
in 0 seconds
...@@ -162,7 +162,10 @@ class ERP5TypeLiveTestCase(ERP5TypeTestCaseMixin): ...@@ -162,7 +162,10 @@ class ERP5TypeLiveTestCase(ERP5TypeTestCaseMixin):
self._setUpDummyMailHost() self._setUpDummyMailHost()
setUp = PortalTestCase.setUp setUp = PortalTestCase.setUp
tearDown = PortalTestCase.tearDown
def tearDown(self):
self.doCleanups()
PortalTestCase.tearDown(self)
def _app(self): def _app(self):
'''Returns the app object for a test.''' '''Returns the app object for a test.'''
......
...@@ -1346,6 +1346,7 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin): ...@@ -1346,6 +1346,7 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin):
'''Tears down the fixture. Do not override, '''Tears down the fixture. Do not override,
use the hooks instead. use the hooks instead.
''' '''
self.doCleanups()
if not int(os.environ.get('erp5_save_data_fs', 0)): if not int(os.environ.get('erp5_save_data_fs', 0)):
# Drop remaining activities if some of them failed. # Drop remaining activities if some of them failed.
# However, we should not do more activity cleaning, because properly # However, we should not do more activity cleaning, because properly
......
...@@ -3237,17 +3237,19 @@ class Test(ERP5TypeTestCase): ...@@ -3237,17 +3237,19 @@ class Test(ERP5TypeTestCase):
# set a request key, that should not be set from the test request # set a request key, that should not be set from the test request
self.portal.REQUEST.set('foo', 'something from main request') self.portal.REQUEST.set('foo', 'something from main request')
# ERP5TypeLiveTestCase.runLiveTest patches ERP5TypeTestCase bases, thus it def runLiveTest(test_name):
# needs to be restored after calling runLiveTest # ERP5TypeLiveTestCase.runLiveTest patches ERP5TypeTestCase bases, thus it
base_tuple = ERP5TypeTestCase.__bases__ # needs to be restored after calling runLiveTest
ERP5TypeTestLoader.loadTestsFromNames = loadTestsFromNames base_tuple = ERP5TypeTestCase.__bases__
try: ERP5TypeTestLoader.loadTestsFromNames = loadTestsFromNames
self._component_tool.runLiveTest('testRunLiveTest') try:
finally: self._component_tool.runLiveTest(test_name)
ERP5TypeTestCase.__bases__ = base_tuple finally:
ERP5TypeTestLoader.loadTestsFromNames = ERP5TypeTestLoader_loadTestsFromNames ERP5TypeTestCase.__bases__ = base_tuple
ERP5TypeTestLoader.loadTestsFromNames = ERP5TypeTestLoader_loadTestsFromNames
return self._component_tool.readTestOutput()
output = self._component_tool.readTestOutput() output = runLiveTest('testRunLiveTest')
expected_msg_re = re.compile('Ran 1 test.*OK', re.DOTALL) expected_msg_re = re.compile('Ran 1 test.*OK', re.DOTALL)
self.assertRegex(output, expected_msg_re) self.assertRegex(output, expected_msg_re)
...@@ -3265,18 +3267,35 @@ class Test(ERP5TypeTestCase): ...@@ -3265,18 +3267,35 @@ class Test(ERP5TypeTestCase):
self._component_tool.reset(force=True, self._component_tool.reset(force=True,
reset_portal_type_at_transaction_boundary=True) reset_portal_type_at_transaction_boundary=True)
base_tuple = ERP5TypeTestCase.__bases__ output = runLiveTest('testRunLiveTest')
ERP5TypeTestLoader.loadTestsFromNames = loadTestsFromNames
try:
self._component_tool.runLiveTest('testRunLiveTest')
finally:
ERP5TypeTestCase.__bases__ = base_tuple
ERP5TypeTestLoader.loadTestsFromNames = ERP5TypeTestLoader_loadTestsFromNames
output = self._component_tool.readTestOutput()
expected_msg_re = re.compile('Ran 2 tests.*FAILED \(failures=1\)', re.DOTALL) expected_msg_re = re.compile('Ran 2 tests.*FAILED \(failures=1\)', re.DOTALL)
self.assertRegex(output, expected_msg_re) self.assertRegex(output, expected_msg_re)
# Now try addCleanup
source_code = self._getValidSourceCode() + '''
def test_02_addCleanup(self):
self.portal.portal_activities.setTitle("changed")
self.tic()
def cleanup():
self.portal.portal_activities.setTitle({activity_tool_title!r})
self.tic()
self.addCleanup(cleanup)
def test_03_checkAfterCleanUp(self):
self.assertEqual(self.portal.portal_activities.getTitle(), {activity_tool_title!r})
'''.format(activity_tool_title=self.portal.portal_activities.getTitle())
component.setTextContent(source_code)
self.tic()
self.assertEqual(component.getValidationState(), 'validated')
self.assertModuleImportable('testRunLiveTest')
self._component_tool.reset(force=True,
reset_portal_type_at_transaction_boundary=True)
output = runLiveTest('testRunLiveTest')
expected_msg_re = re.compile('Ran 3 test.*OK', re.DOTALL)
self.assertRegex(output, expected_msg_re)
def testERP5Broken(self): def testERP5Broken(self):
# Create a broken ghost object # Create a broken ghost object
import erp5.portal_type import erp5.portal_type
...@@ -3517,39 +3536,30 @@ class TestZodbDocumentComponentReload(ERP5TypeTestCase): ...@@ -3517,39 +3536,30 @@ class TestZodbDocumentComponentReload(ERP5TypeTestCase):
def testAsComposedDocumentCacheIsCorrectlyFlushed(self): def testAsComposedDocumentCacheIsCorrectlyFlushed(self):
component = self.portal.portal_components['document.erp5.BusinessProcess'] component = self.portal.portal_components['document.erp5.BusinessProcess']
component_original_text_content = component.getTextContent() component_original_text_content = component.getTextContent()
self.addCleanup(
self._setBusinessProcessComponentTextContent,
component_original_text_content)
# Use try/finally to restore the content of self._setBusinessProcessComponentTextContent(
# document.erp5.BusinessProcess as using addCleanup function here raises component_original_text_content + """
# with :
# ConnectionStateError: Shouldn't load state for
# Products.DCWorkflow.Scripts.Scripts 0x099ad38a68606074
# when the connection is closed
try:
self._setBusinessProcessComponentTextContent(
component_original_text_content + """
def getVersion(self): def getVersion(self):
return 1 return 1
""" """
) )
movement = self.portal.newContent(portal_type='Movement') movement = self.portal.newContent(portal_type='Movement')
composed_movement = movement.asComposedDocument() composed_movement = movement.asComposedDocument()
self.assertEqual(composed_movement.getVersion(), 1) self.assertEqual(composed_movement.getVersion(), 1)
self._setBusinessProcessComponentTextContent( self._setBusinessProcessComponentTextContent(
component_original_text_content + """ component_original_text_content + """
def getVersion(self): def getVersion(self):
return 2 return 2
""" """
) )
composed_movement = movement.asComposedDocument()
self.assertEqual(composed_movement.getVersion(), 2)
finally: composed_movement = movement.asComposedDocument()
self._setBusinessProcessComponentTextContent( self.assertEqual(composed_movement.getVersion(), 2)
component_original_text_content
)
def test_suite(): def test_suite():
......
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