testWorklist.py 19.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
##############################################################################
#
# Copyright (c) 2007 Nexedi SA and Contributors. 
# All Rights Reserved.
#          Romain Courteaud <romain@nexedi.com>
#
# 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.
#
##############################################################################

import unittest

from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Testing.ZopeTestCase.PortalTestCase import PortalTestCase

class TestWorklist(ERP5TypeTestCase):

  run_all_test = 1
  quiet = 1
  login = PortalTestCase.login

  checked_portal_type = 'Organisation'
42
  module_selection_name = 'organisation_module_selection'
43
  checked_validation_state = 'draft'
44
  not_checked_validation_state = 'not_draft'
45 46 47 48 49
  checked_workflow = 'validation_workflow'
  worklist_assignor_id = 'assignor_worklist'
  actbox_assignor_name = 'assignor_todo'
  worklist_owner_id = 'owner_worklist'
  actbox_owner_name = 'owner_todo'
50 51
  worklist_assignor_owner_id = 'assignor_owner_worklist'
  actbox_assignor_owner_name = 'assignor_owner_todo'
52 53
  worklist_desactivated_id = '%s_desactivated' % worklist_owner_id
  actbox_desactivated_by_expression = '%s_desactivated' % actbox_owner_name
54 55
  worklist_wrong_state_id = '%s_wrong_state' % worklist_owner_id
  actbox_wrong_state = '%s_wrong_state' % actbox_owner_name
56

57
  worklist_int_variable_id = 'int_value_worklist'
58 59 60 61
  actbox_int_variable_name = 'int_value_todo'
  int_catalogued_variable_id = 'int_index'
  int_value = 1

62 63 64
  def getTitle(self):
    return "Worklist"

65 66 67 68 69 70 71
  def clearModule(self, module):
    module.manage_delObjects(list(module.objectIds()))
    self.tic()

  def beforeTearDown(self):
    self.clearModule(self.portal.person_module)
    self.clearModule(self.portal.organisation_module)
72 73
    self.clearModule(self.portal.portal_categories.region)
    self.clearModule(self.portal.portal_categories.role)
74

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
  def getBusinessTemplateList(self):
    """
    Return list of bt5 to install
    """
    return ('erp5_base',)

  def getUserFolder(self):
    """
    Return the user folder
    """
    return getattr(self.getPortal(), 'acl_users', None)

  def createManagerAndLogin(self):
    """
    Create a simple user in user_folder with manager rights.
    This user will be used to initialize data in the method afterSetup
    """
    self.getUserFolder()._doAddUser('manager', '', ['Manager'], [])
    self.login('manager')

  def createERP5Users(self, user_dict):
    """
    Create all ERP5 users needed for the test.
    ERP5 user = Person object + Assignment object in erp5 person_module.
    """
    portal = self.getPortal()
    module = portal.getDefaultModule("Person")
    # Create the Person.
    for user_login, user_data in user_dict.items():
      # Create the Person.
      self.logMessage("Create user: %s" % user_login)
      person = module.newContent(
        portal_type='Person', 
        reference=user_login, 
        password='hackme',
      )
      # Create the Assignment.
      assignment = person.newContent( 
        portal_type = 'Assignment',
        group = "%s" % user_data[0],
        function = "%s" % user_data[1],
        start_date = '01/01/1900',
        stop_date = '01/01/2900',
      )
119
      assignment.open()
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    # Reindexing is required for the security to work
    self.tic()

  def createUsers(self):
    """
    Create all users needed for the test
    """
    self.createERP5Users(self.getUserDict())

  def getUserDict(self):
    """
    Return dict of users needed for the test
    """
    user_dict = {
      'foo': [None, None],
      'bar': [None, None],
    }
    return user_dict

139
  def createDocument(self, **kw):
140
    module = self.getPortal().getDefaultModule(self.checked_portal_type)
141
    result = module.newContent(portal_type=self.checked_portal_type, **kw)
142
    result.setProperty(self.int_catalogued_variable_id, self.int_value)
143 144
    assert result.getValidationState() == self.checked_validation_state
    return result
145

146
  def getWorklistDocumentCountFromActionName(self, action_name):
147
    self.assertEqual(action_name[-1], ')')
148 149 150 151
    left_parenthesis_offset = action_name.rfind('(')
    self.assertNotEquals(left_parenthesis_offset, -1)
    return int(action_name[left_parenthesis_offset + 1:-1])

152
  def associatePropertySheet(self):
153
    self._addPropertySheet(self.checked_portal_type, 'SortIndex')
154

155 156 157 158
  def addWorkflowCataloguedVariable(self, workflow_id, variable_id):
    variables = self.getWorkflowTool()[workflow_id].variables
    variables.addVariable(variable_id)
    assert variables[variable_id].for_catalog == 1
159

160 161
  def createWorklist(self, workflow_id, worklist_id, actbox_name,
                     actbox_url=None, **kw):
162 163 164
    worklists = self.getWorkflowTool()[workflow_id].worklists
    worklists.addWorklist(worklist_id)
    worklists._getOb(worklist_id).setProperties('',
165 166 167
        actbox_name='%s (%%(count)s)' % actbox_name, actbox_url=actbox_url,
        props=dict((k.startswith('guard_') and k or 'var_match_'+k, v)
                    for k, v in kw.iteritems()))
168

169 170 171 172
  def removeWorklist(self, workflow_id, worklist_id_list):
    worklists = self.getWorkflowTool()[workflow_id].worklists
    worklists.deleteWorklists(worklist_id_list)

173
  def createWorklists(self):
174
    for worklist_id, actbox_name, role, expr, state, int_variable in [
175
          (self.worklist_assignor_id, self.actbox_assignor_name, 
176
           'Assignor', None, self.checked_validation_state, None),
177
          (self.worklist_owner_id, self.actbox_owner_name, 
178
           'Owner', None, self.checked_validation_state, None),
179
          (self.worklist_desactivated_id, self.actbox_desactivated_by_expression, 
180
           'Owner', 'python: 0', self.checked_validation_state, None),
181
          (self.worklist_wrong_state_id, self.actbox_wrong_state, 
182
           'Owner', None, self.not_checked_validation_state, None),
183
          (self.worklist_assignor_owner_id, self.actbox_assignor_owner_name, 
184 185 186 187
           'Assignor; Owner', None, self.checked_validation_state, None),
          (self.worklist_int_variable_id, self.actbox_int_variable_name, 
           None, None, None, str(self.int_value)),
    ]:
188 189 190 191 192
      self.createWorklist(self.checked_workflow, worklist_id, actbox_name,
                          guard_roles=role, guard_expr=expr,
                          portal_type=self.checked_portal_type,
                          validation_state=state,
                          **{self.int_catalogued_variable_id: int_variable})
193

194 195 196 197 198 199 200 201 202 203
  def removeWorklists(self):
    self.removeWorklist(self.checked_workflow, [
          self.worklist_assignor_id, 
          self.worklist_owner_id, 
          self.worklist_desactivated_id, 
          self.worklist_wrong_state_id, 
          self.worklist_assignor_owner_id, 
          self.worklist_int_variable_id, 
    ])

204 205 206
  def clearCache(self):
    self.portal.portal_caches.clearAllCache()

207
  def checkWorklist(self, result, name, count, url_parameter_dict=None):
208
    entry_list = [x for x in result if x['name'].startswith(name)]
209
    self.assertEqual(len(entry_list), count and 1)
210
    if count:
211
      self.assertEqual(count,
212
        self.getWorklistDocumentCountFromActionName(entry_list[0]['name']))
213 214 215 216 217 218 219 220 221 222 223 224
    if not entry_list:
      return
    url = entry_list[0].get('url')
    if url_parameter_dict:
      self.assertTrue(url, 'Can not check url parameters without url')
      url = '%s%s' % (self.portal.getId(), url[len(self.portal.absolute_url()):])
      # Touch URL to save worklist parameters in listbox selection
      self.publish(url, 'manager:') # XXX which user ?
      selection_parameter_dict = self.portal.portal_selections.getSelectionParamsFor(
                                                    self.module_selection_name)
      for parameter, value in url_parameter_dict.iteritems():
        self.assertTrue(parameter in selection_parameter_dict)
225
        self.assertEqual(value, selection_parameter_dict[parameter])
226

227
  def test_01_permission(self, quiet=0, run=run_all_test):
228 229 230 231 232 233 234 235
    """
    Test the permission of the building module.
    """
    if not run: 
      return

    workflow_tool = self.portal.portal_workflow

236
    self.logMessage("Create users")
237 238
    self.createManagerAndLogin()
    self.createUsers()
239
    self.logMessage("Create worklists")
240
    self.associatePropertySheet()
241 242 243
    self.addWorkflowCataloguedVariable(self.checked_workflow,
                                       self.int_catalogued_variable_id)
    self.createWorklists()
244 245 246
    try:
      self.logMessage("Create document as Manager")
      document = self.createDocument()
247

248 249
      self.tic()
      self.clearCache()
250 251

      result = workflow_tool.listActions(object=document)
252 253 254 255 256 257 258 259 260 261 262 263 264

      # Users can not see worklist as they are not Assignor
      for user_id in ('manager', ):
        self.login(user_id)
        result = workflow_tool.listActions(object=document)
        self.logMessage("Check %s worklist as Assignor" % user_id)
        self.checkWorklist(result, self.actbox_assignor_name, 0)
        self.logMessage("Check %s worklist as Owner" % user_id)
        self.checkWorklist(result, self.actbox_owner_name, 1)
      for user_id in ('foo', 'bar'):
        self.logMessage("Check %s worklist" % user_id)
        self.login(user_id)
        result = workflow_tool.listActions(object=document)
265
        self.assertEqual(result, [])
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

      for role, user_id_list in (('Assignor', ('foo', 'manager')),
                                 ('Assignee', ('foo', 'bar'))):
        self.login('manager')
        for user_id in user_id_list:
          self.logMessage("Give %s %s role" % (user_id, role))
          document.manage_addLocalRoles(user_id, [role])
        document.reindexObject()
        self.tic()
        self.clearCache()

        for user_id, assignor, owner, both in (('manager', 1, 1, 1),
                                               ('bar'    , 0, 0, 0),
                                               ('foo'    , 1, 0, 1)):
          self.login(user_id)
          result = workflow_tool.listActions(object=document)
          self.logMessage("  Check %s worklist as Assignor" % user_id)
          self.checkWorklist(result, self.actbox_assignor_name, assignor)
          self.logMessage("  Check %s worklist as Owner" % user_id)
          self.checkWorklist(result, self.actbox_owner_name, owner)
          self.logMessage("  Check %s worklist as Owner and Assignor" % user_id)
          self.checkWorklist(result, self.actbox_assignor_owner_name, both)

      # Check if int variable are managed by the worklist
      user_id = 'manager'
291 292
      self.login(user_id)
      result = workflow_tool.listActions(object=document)
293 294 295
      self.logMessage("Check %s worklist with int value as %s" % \
                                     (user_id, self.int_value))
      self.checkWorklist(result, self.actbox_int_variable_name, 1)
296

297 298 299
      # Change int value on document
      new_value = self.int_value + 1
      document.setProperty(self.int_catalogued_variable_id, new_value)
300 301
      self.tic()
      self.clearCache()
302

303 304 305 306
      result = workflow_tool.listActions(object=document)
      self.logMessage("Check %s worklist with int value as %s" % \
                                     (user_id, new_value))
      self.checkWorklist(result, self.actbox_int_variable_name, 0)
307

308 309 310 311 312 313
      #
      # Check monovalued security role
      #
      self.login('manager')
      module = self.getPortal().getDefaultModule(self.checked_portal_type)
      module.manage_setLocalRoles('bar', ['Author'])
314

315
      self.login('bar')
316

317 318
      bar_document = self.createDocument()
      bar_document.manage_permission('View', ['Owner', 'Assignee'], 0)
319

320 321 322
      bar_assignee_document = self.createDocument()
      bar_assignee_document.manage_setLocalRoles('manager', ['Assignee'])
      bar_assignee_document.manage_permission('View', ['Owner', 'Assignee'], 0)
323

324 325
      user_id = 'manager'
      self.login(user_id)
326

327
      module.manage_delLocalRoles('bar')
328

329 330 331
      def test(*count_list):
        local_role_list = 'Assignee', 'Owner'
        document.manage_setLocalRoles('manager', local_role_list)
332

333 334 335 336 337
        for i, count in enumerate(count_list):
          document.manage_permission('View', local_role_list[:i], 0)
          document.reindexObject()
          self.tic()
          self.clearCache()
338

339 340 341
          result = workflow_tool.listActions(object=document)
          self.logMessage("Check %s worklist as Owner (%s)" % (user_id, count))
          self.checkWorklist(result, self.actbox_owner_name, count)
342

343
      test(0, 0, 1)
344

345 346 347 348 349
      # Define a local role key
      sql_catalog = self.portal.portal_catalog.getSQLCatalog()
      current_sql_catalog_local_role_keys = \
            sql_catalog.sql_catalog_local_role_keys
      sql_catalog.sql_catalog_local_role_keys = ('Owner | owner', )
350
      self.commit()
351
      self.portal.portal_caches.clearAllCache()
352

353 354 355 356 357
      try:
        test(0, 1, 1)
      finally:
        sql_catalog.sql_catalog_local_role_keys = \
            current_sql_catalog_local_role_keys
358
        self.commit()
359
    finally:
360
      self.removeWorklists()
361

362 363 364 365 366 367 368 369 370
  def test_02_related_key(self, quiet=0, run=run_all_test):
    """
    Test related keys
    """
    if not run:
      return

    workflow_tool = self.getWorkflowTool()
    self.createManagerAndLogin()
371

372
    self.logMessage("Create categories")
373 374 375 376 377 378 379
    for base_category, category_list in (
        ('region', ('somewhere', 'elsewhere')),
        ('role',   ('client',    'supplier'))):
      newContent = self.getCategoryTool()[base_category].newContent
      for category in category_list:
        newContent(portal_type='Category', id=category)

380 381 382
    self.logMessage("Create worklists using 'base_category_id' related key")
    self.addWorkflowCataloguedVariable(self.checked_workflow,
                                       'base_category_id')
383 384 385 386 387 388 389
    self.createWorklist(self.checked_workflow, 'region_worklist', 'has_region',
                        portal_type=self.checked_portal_type,
                        base_category_id='region')
    self.createWorklist(self.checked_workflow, 'role_worklist', 'has_role',
                        portal_type=self.checked_portal_type,
                        base_category_id='role')

390 391 392 393 394 395 396 397
    try:
      document = self.createDocument()
      self.tic()
      self.clearCache()
      self.logMessage("  Check no document has region/role categories defined")
      result = workflow_tool.listActions(object=document)
      self.checkWorklist(result, 'has_region', 0)
      self.checkWorklist(result, 'has_role', 0)
398

399 400 401 402
      self.logMessage("  Creates documents with region/role categories defined")
      self.createDocument(role='client')
      self.createDocument(region='somewhere')
      self.createDocument(region='elsewhere')
403

404 405 406 407 408 409 410 411 412 413
      self.tic()
      self.clearCache()
      self.logMessage(
               "  Check there are documents with region/role categories defined")
      result = workflow_tool.listActions(object=document)
      self.checkWorklist(result, 'has_region', 2)
      self.checkWorklist(result, 'has_role', 1)
    finally:
      self.removeWorklist(self.checked_workflow, 
                          ['region_worklist', 'role_worklist'])
414

Romain Courteaud's avatar
Romain Courteaud committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
  def test_03_worklist_guard(self, quiet=0, run=run_all_test):
    """
    Test worklist guard
    """
    if not run:
      return

    workflow_tool = self.getWorkflowTool()
    self.createManagerAndLogin()
    self.createUsers()

    self.logMessage("Create worklists with guard expression")
    self.createWorklist(self.checked_workflow, 'guard_expression_worklist', 
                        'valid_guard_expression',
                        portal_type=self.checked_portal_type,
                        validation_state='validated',
                        guard_roles="Associate",
                        guard_expr='python: user.getId() == "bar"')

434 435 436 437 438 439 440 441
    try:
      document = self.createDocument()
      document.manage_addLocalRoles("bar", ["Associate"])
      document.manage_addLocalRoles("foo", ["Associate"])
      document.validate()
      document.reindexObject()
      self.tic()
      self.clearCache()
Romain Courteaud's avatar
Romain Courteaud committed
442

443 444 445
      self.logMessage("  Check that manager can not access worklist")
      result = workflow_tool.listActions(object=document)
      self.checkWorklist(result, 'valid_guard_expression', 0)
Romain Courteaud's avatar
Romain Courteaud committed
446

447 448 449 450
      self.logMessage("  Check that user bar can access worklist")
      self.login('bar')
      result = workflow_tool.listActions(object=document)
      self.checkWorklist(result, 'valid_guard_expression', 1)
Romain Courteaud's avatar
Romain Courteaud committed
451

452 453 454 455 456 457 458
      self.logMessage("  Check that user foo can not access worklist")
      self.login('foo')
      result = workflow_tool.listActions(object=document)
      self.checkWorklist(result, 'valid_guard_expression', 0)
    finally:
      self.removeWorklist(self.checked_workflow, 
                          ['guard_expression_worklist'])
459

460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
  def test_04_dynamic_variables(self):
    """
    Test related keys and TALES Expression
    """

    workflow_tool = self.getWorkflowTool()
    self.createManagerAndLogin()

    self.logMessage("Create categories")
    for base_category, category_list in (
        ('region', ('somewhere', 'elsewhere')),
        ('role',   ('client',    'supplier'))):
      newContent = self.getCategoryTool()[base_category].newContent
      for category in category_list:
        newContent(portal_type='Category', id=category)

    self.logMessage("Create worklists using 'region_uid' related key"\
                    " and TALES Expression")
    self.addWorkflowCataloguedVariable(self.checked_workflow,
                                       'region_uid')
    self.createWorklist(self.checked_workflow, 'region_worklist',
                        'has_semewhere_region',
                        portal_type=self.checked_portal_type,
                        actbox_url='organisation_module?'\
                        'region_uid:list=%(region_uid)s&'\
                        'portal_type:list=%(portal_type)s&reset:int=1',
                        region_uid='python:object.getPortalObject().'\
                        'portal_categories.getCategoryUid("somewhere",'\
                        ' base_category="region")')

    try:
      document = self.createDocument()
      self.tic()
      self.clearCache()
      self.logMessage("  Check no document has region categories defined")
      result = workflow_tool.listActions(object=document)
      self.checkWorklist(result, 'has_semewhere_region', 0)

      self.logMessage("  Creates documents with region categories defined")

      self.createDocument(region='somewhere')
      self.createDocument(region='somewhere')
      self.createDocument(region='elsewhere')

      self.tic()
      self.clearCache()
      self.logMessage(
               "  Check there are documents with region categories defined")
      result = workflow_tool.listActions(object=document)
      url_parameter_dict = {'region_uid': [str(self.portal.portal_categories.\
                                          getCategoryUid("region/somewhere"))],
                            'portal_type': [self.checked_portal_type]}
      self.checkWorklist(result, 'has_semewhere_region', 2,
                         url_parameter_dict=url_parameter_dict)

    finally:
      self.removeWorklist(self.checked_workflow, ['region_worklist'])


519 520 521 522
def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestWorklist))
  return suite