############################################################################## # # Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved. # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsability of assessing all potential # consequences resulting from its eventual inadequacies and bugs # End users who are looking for a ready-to-use solution with commercial # garantees and support are strongly adviced to contract a Free Software # Service Company # # This program is Free Software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## """ TIMEZONE WARNING The ICal renderer does not take into account time zones, because clients can take care about it for themselves, so we use GMT time. This test assumes the person running the test is in the same time zone as me, which is usually true. It will be fixed some day. I have been investigating this a little, DateTime module caches the timezone very early in the initialisation process, so changing os.environ['TZ'] has no effect. For now, the easiest is to set TZ environ variable to something like 'Europe/France' """ import unittest from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from AccessControl.SecurityManagement import newSecurityManager from Products.ERP5Form.Form import ERP5Form try: from transaction import get as get_transaction except ImportError: pass class TestICal(ERP5TypeTestCase): run_all_test = 1 def getTitle(self): return "ICal Test" def getBusinessTemplateList(self): """ """ return ('erp5_base', 'erp5_trade', 'erp5_project', 'erp5_crm', 'erp5_ical_style') def afterSetUp(self): self.portal = self.getPortal() self.request=self.app.REQUEST self.validateRules() self.makeDataObjects() def login(self, quiet=0, run=run_all_test): uf = self.getPortal().acl_users uf._doAddUser('seb', '', ['Manager'], []) uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], []) user = uf.getUserById('seb').__of__(uf) newSecurityManager(None, user) def makeDataObjects(self, quiet=0, run=run_all_test): """ Create some Pesons so that we have something to feed. """ if hasattr(self.portal.person_module, 'one'): self.portal.person_module.manage_delObjects(['one']) one = self.portal.person_module.newContent(id="one", title="One", description="Person One") get_transaction().commit() self.tic() def parseICalFeed(self, feed_string): """ Parse the feed. We always have one object in feed (in this test), so we can safely use dict to check what is inside. """ feed = feed_string.split('\n') # split once, because link like 'URL:http://myhost...' can exist in feed_string feed = [s.split(':', 1) for s in feed if s] feed_dict = {} for line in feed: if line[0] == 'BEGIN' or line[0] == 'END': feed_dict[':'.join(line)] = line[1] else: feed_dict[line[0]] = line[1] return feed_dict def getICalFeed(self, module): """ Get the feed using form rendered by ical_view pt """ self.request.set('portal_skin', 'iCal'); self.portal.portal_skins.changeSkin('iCal'); feed_string = module.Folder_viewContentListAsICal() return self.parseICalFeed(feed_string) def test_01_renderEvent(self, quiet=0, run=run_all_test): """ Events (like phone call) are rendered as events (not surprisingly). Here we check if the dates, categories and other properties are rendered correctly. """ if not run: return module = self.portal.event_module event = module.newContent(id='one', title='Event One', portal_type='Phone Call') get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertTrue('BEGIN:VCALENDAR' in feed_dict.keys()) self.assertTrue('END:VCALENDAR' in feed_dict.keys()) self.assertTrue('BEGIN:VEVENT' in feed_dict.keys()) self.assertTrue('END:VEVENT' in feed_dict.keys()) self.assertEquals(feed_dict['SUMMARY'], 'Event One') # if not set start date, it must be same as creation date # if not set end date, it must be same as start date self.assertEquals(feed_dict['DTSTART'], event.getCreationDate().HTML4().replace('-','').replace(':','')) self.assertEquals(feed_dict['DTEND'], event.getCreationDate().HTML4().replace('-','').replace(':','')) self.assertEquals(feed_dict['CREATED'], event.getCreationDate().HTML4().replace('-','').replace(':','')) self.assertEquals(feed_dict['LAST-MODIFIED'], event.getModificationDate().HTML4().replace('-','').replace(':','')) self.assertEquals(feed_dict['URL'], event.absolute_url() + '/view') self.assertEquals(feed_dict['UID'], 'uuid%s' % event.getUid()) # there is no description self.assertFalse('DESCRIPTION' in feed_dict.keys()) # current workflow state - draft self.assertEquals(feed_dict['STATUS'], 'TENTATIVE') # set start date, description and change workflow state - new event.receive() event.setStartDate('2007/08/15 10:30') event.setDescription('Event One description') get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals( # if this fail for you, try to set $TZ to Europe/Paris feed_dict['DTSTART'], '20070815T083000Z') # if not set end date, it must be same as start date self.assertEquals(feed_dict['DTEND'], '20070815T083000Z') self.assertEquals(feed_dict['STATUS'], 'TENTATIVE') self.assertEquals(feed_dict['DESCRIPTION'], 'Event One description') # check categorization sale_op = self.portal.sale_opportunity_module.newContent(portal_type='Sale Opportunity', title='New Opportunity', reference='NEWSALEOP') event.setFollowUp(sale_op.getRelativeUrl()) get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertTrue(feed_dict['CATEGORIES'] in ('NEWSALEOP', 'New Opportunity')) # forward compatibility # set stop date and change workflow state - assigned event.assign() event.setStopDate('2007/08/15 15:30') get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals(feed_dict['DTEND'], '20070815T133000Z') self.assertEquals(feed_dict['STATUS'], 'CONFIRMED') # cancel event event.cancel() get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals(feed_dict['STATUS'], 'CANCELLED') def test_02_renderTask(self, quiet=0, run=run_all_test): """ Task - is rendered as "todo". Additionally, it has "status" and "percent-complete" fields which change when the task moves along task_workflow. Dates work the same way, so we don't have to repeat it """ if not run: return module = self.portal.task_module task = module.newContent(id='one', title='Task One', start_date='2007/08/15') get_transaction().commit() self.tic() # current workflow state - draft feed_dict = self.getICalFeed(module) self.assertTrue('BEGIN:VCALENDAR' in feed_dict.keys()) self.assertTrue('END:VCALENDAR' in feed_dict.keys()) self.assertTrue('BEGIN:VTODO' in feed_dict.keys()) self.assertTrue('END:VTODO' in feed_dict.keys()) self.assertEquals(feed_dict['SUMMARY'], 'Task One') self.assertEquals(feed_dict['STATUS'], 'NEEDS-ACTION') self.assertEquals(feed_dict.get('PERCENT-COMPLETE', '0'), '0') # when it is zero it doesn't have to be there # now we check categorization (while we can edit the object) project = self.portal.project_module.newContent(portal_type='Project', title='New Project', reference='NEWPROJ') task.setSourceProjectValue(project) get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals(feed_dict['CATEGORIES'], 'NEWPROJ') # change workflow state - planned task.plan() get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals(feed_dict['STATUS'], 'NEEDS-ACTION') self.assertEquals(feed_dict['PERCENT-COMPLETE'], '33') # change workflow state - ordered task.order() get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals(feed_dict['STATUS'], 'IN-PROCESS') self.assertEquals(feed_dict['PERCENT-COMPLETE'], '66') # change workflow state - confirmed task.confirm() get_transaction().commit() self.tic() feed_dict = self.getICalFeed(module) self.assertEquals(feed_dict['STATUS'], 'COMPLETED') self.assertEquals(feed_dict['PERCENT-COMPLETE'], '100') def test_03_renderJournal(self, quiet=0, run=run_all_test): """ Everyting which is not event and task is rendered as journal. Here we render person module as iCal. In this case pt for render current form('Test_view') is default page template(form_view) """ if not run: return self.request.set('portal_skin', 'iCal'); self.portal.portal_skins.changeSkin('iCal'); self.portal._setObject('Test_view', ERP5Form('Test_view', 'View')) self.portal.Test_view.manage_addField('listbox', 'listbox', 'ListBox') listbox=self.portal.Test_view.listbox self.assertNotEquals(listbox, None) listbox.manage_edit_xmlrpc( dict(columns=[('title', 'Title'), ('creation_date', 'Creation date'), ('description','Description'), ('Base_getICalComponent', 'Component')], sort=[('creation_date | descending')], list_action='list', list_method='searchFolder', count_method='countFolder', selection_name='ical_folder_selection')) module = self.portal.person_module one = self.portal.person_module.one feed_string = self.portal.person_module.Test_view() feed_dict = self.parseICalFeed(feed_string) self.assertTrue('BEGIN:VCALENDAR' in feed_dict.keys()) self.assertTrue('END:VCALENDAR' in feed_dict.keys()) self.assertTrue('BEGIN:VJOURNAL' in feed_dict.keys()) self.assertTrue('END:VJOURNAL' in feed_dict.keys()) self.assertEquals(feed_dict['SUMMARY'], 'One') self.assertEquals(feed_dict['DESCRIPTION'], 'Person One') self.assertEquals(feed_dict['CREATED'], one.getCreationDate().HTML4().replace('-','').replace(':','')) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestICal)) return suite