From 77539e6de2506190af2dbcad0a74e752466e418a Mon Sep 17 00:00:00 2001 From: Nicolas Delaby <nicolas@nexedi.com> Date: Tue, 27 Apr 2010 11:59:02 +0000 Subject: [PATCH] Add test which check that conversion engine is able to fill in cache without overwrite previous conversion when processed at the same time. This test show that conversion cache design is not scallable. All conversions are stored in a unique dictionary per Document. This dictionary can not be modified by parallel threads because multiple copies of this dictionary are distributed among threads. When The last thread finish, it take precedence and erase previous copies of that dictionary. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@34817 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5OOo/tests/testDms.py | 83 ++++++++++++++++++ .../test_document/Forty-Two.Pages-en-001.pdf | Bin 0 -> 24459 bytes 2 files changed, 83 insertions(+) create mode 100644 product/ERP5OOo/tests/test_document/Forty-Two.Pages-en-001.pdf diff --git a/product/ERP5OOo/tests/testDms.py b/product/ERP5OOo/tests/testDms.py index c9a317dbd4..835333ee27 100644 --- a/product/ERP5OOo/tests/testDms.py +++ b/product/ERP5OOo/tests/testDms.py @@ -57,11 +57,15 @@ from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.utils import FileUpload from Products.ERP5Type.tests.utils import DummyLocalizer from Products.ERP5OOo.OOoUtils import OOoBuilder +from Products.CMFCore.utils import getToolByName from AccessControl.SecurityManagement import newSecurityManager +from AccessControl import getSecurityManager from zLOG import LOG from Products.ERP5.Document.Document import NotConvertedError from Products.ERP5Type.tests.backportUnittest import expectedFailure import os +from threading import Thread +import httplib QUIET = 0 RUN_ALL_TEST = 1 @@ -1551,6 +1555,85 @@ style=3D'color:black'>05D65812<o:p></o:p></span></p> self.assertTrue('AZERTYY' not in safe_html) self.assertTrue('#FFAA44' in safe_html) + def test_parallel_conversion(self): + """Check that conversion engine is able to fill in + cache without overwrite previous conversion + when processed at the same time. + """ + portal_type = 'PDF' + document_module = self.portal.getDefaultModule(portal_type) + document = document_module.newContent(portal_type=portal_type) + + upload_file = makeFileUpload('Forty-Two.Pages-en-001.pdf') + document.edit(file=upload_file) + pages_number = int(document.getContentInformation()['Pages']) + transaction.commit() + self.tic() + + document.clearConversionCache() + transaction.commit() + self.tic() + + class ThreadWrappedConverter(Thread): + """Use this class to run different convertion + inside distinct Thread. + """ + def __init__(self, publish_method, document_path, + frame_list, credential): + self.publish_method = publish_method + self.document_path = document_path + self.frame_list = frame_list + self.credential = credential + Thread.__init__(self) + + def run(self): + for frame in self.frame_list: + # Use publish method to dispatch conversion among + # all available Zserver threads. + response = self.publish_method('%s/index_html?format=png'\ + '&display=thumbnail&quality:int=75&resolution='\ + '&frame=%s' % (self.document_path, frame), + self.credential) + assert response.getHeader('content-type') == 'image/png' + assert response.getStatus() == httplib.OK + transaction.commit() + + # assume there is no password + credential = '%s:' % (getSecurityManager().getUser().getId(),) + tested_list = [] + frame_list = list(xrange(pages_number)) + # assume that ZServer is configured with 4 Threads + conversion_per_tread = pages_number / 4 + while frame_list: + local_frame_list = [frame_list.pop() for i in\ + xrange(min(conversion_per_tread, len(frame_list)))] + instance = ThreadWrappedConverter(self.publish, document.getPath(), + local_frame_list, credential) + tested_list.append(instance) + instance.start() + + # Wait until threads finishing + [tested.join() for tested in tested_list] + + transaction.commit() + self.tic() + + preference_tool = getToolByName(self.portal, 'portal_preferences') + image_size = preference_tool.getPreferredThumbnailImageHeight(),\ + preference_tool.getPreferredThumbnailImageWidth() + convert_kw = {'format': 'png', + 'display': 'thumbnail', + 'quality': 75, + 'image_size': image_size, + 'resolution': ''} + result_list = [] + for i in xrange(pages_number): + # all conversions should succeeded and stored in cache storage + convert_kw['frame'] = str(i) + if not document.hasConversion(**convert_kw): + result_list.append(i) + self.assertEquals(result_list, []) + class TestDocumentWithSecurity(ERP5TypeTestCase): username = 'yusei' diff --git a/product/ERP5OOo/tests/test_document/Forty-Two.Pages-en-001.pdf b/product/ERP5OOo/tests/test_document/Forty-Two.Pages-en-001.pdf new file mode 100644 index 0000000000000000000000000000000000000000..52cc3d6647861bb15a68274009efcbad9bb5a104 GIT binary patch literal 24459 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�T4g!?{<b=#hl@mZrK^yQz^0YY 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 Ycz9a4dlEu!7#L&%w7k3u8j7_42T&XilK=n! literal 0 HcmV?d00001 -- 2.30.9