test.erp5.testBusinessPackage.py 14.2 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
##############################################################################
#
# Copyright (c) 2002-2017 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################

from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
29
import time
30 31 32 33
import os
from App.config import getConfiguration
from urllib import pathname2url
#import tempfile
34
from Products.ERP5.Document.BusinessPackage import InstallationTree, createInstallationData
35
#from Products.ERP5Type.tests.runUnitTest import tests_home
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

class TestBusinessPackage(ERP5TypeTestCase):
  """
  Test class to test that Business Package object can export some paths
  and install them on an erp5 site

  Steps:
  - Create BusinessPackage object
  - Add path list to the object
  - Build the package and expect the items mentioned in path list gets
  exported in the build step
  - Remove the objects mentioned in path_list from the site
  - Install the package
  - Expected result should be that it installs the objects on the site
  """

  def getTitle(self):
    return "TestBusinessPackage"

  def getBusinessTemplateList(self):
    """
    Tuple of Business Templates we need to install
    """
    return (
      'erp5_base',
61
      'erp5_core',
Ayush Tiwari's avatar
Ayush Tiwari committed
62
      'erp5_dms',
63
      'erp5_property_sheets',
64 65 66 67 68 69 70 71
      'erp5_business_package',
      )

  def afterSetUp(self):
    """
    This is ran before anything, used to set the environment
    """
    # here, you can create the categories and objects your test will depend on
72
    #self.export_dir = tempfile.mkdtmp(dir=tests_home)
73
    self.export_dir = ''
74 75 76 77 78 79 80 81 82 83 84
    self.portal = self.getPortalObject()

  def beforeTearDown(self):
    try:
      package_id  = self.package.getId()
      if package_id:
        self.portal.manage_delObjects([package_id,]) 
    except AttributeError:
      pass

  def _createBusinessPackage(self):
85
    new_id = 'package_%s'%str(time.time())
86
    package = self.portal.portal_templates.newContent(id=new_id, portal_type='Business Package')
87 88
    #self.assertTrue(package.getBuildingState() == 'draft')
    #self.assertTrue(package.getInstallationState() == 'not_installed')
89
    package.edit(title = new_id,
90 91
                  version='1.0',
                  description='package for live test')
92
    self.tic()
93 94
    return package

95
  def _buildAndExportBusinessPackage(self, package):
96 97 98 99 100 101 102
    """
    Builds and exports Business Package to a given export directory
    """
    # Build Package
    # Expected result should be while building the path object items
    # are going to be exported as XML(?)
    self.tic()
103
    package.build()
104 105
    self.tic()

106 107 108 109
    cfg = getConfiguration()
    bp_title = pathname2url(package.getTitle())
    package_path = os.path.join(cfg.instancehome, 'tests', '%s' % (bp_title,))

110
    # Export package (not needed)
111 112
    package.export(path=package_path, local=True)
    self.tic()
113 114 115 116 117
    import_package = self.portal.portal_templates.download(
                    url='file:'+package_path,
                    id=package.id+'1',
                    is_package=True)

118 119 120 121 122
    return import_package

  def _importBusinessPackage(self, package):
    self.portal.portal_templates.manage_delObjects(package.getId())
    self.tic()
123
    import_package = self.portal.portal_templates.download(
124
                                  url='file:'+self.export_dir,
125 126
                                  id=package.getId(),
                                  is_package=True)
127
    return import_package
128

129
  def _installBusinessPackage(self, package):
130 131 132 133
    """
    Install the package from its built version.
    Expected to install the PathTemplateObject items
    """
134
    package.install()
135 136 137

  def test_fileImportAndReinstallForDocument(self):
    """
138 139 140
    Test Business Package build and install with test document.

    Expected result: Installs the exported object to the path expected on site.
141
    """
142
    package = self._createBusinessPackage()
143 144 145 146 147 148 149 150 151
    document_file = self.portal.document_module.newContent(
                                    portal_type = 'File',
                                    title = 'Test Document',
                                    reference = 'erp5-package.Test.Document',
                                    data = 'test file',
                                    content_type = None)
    self.tic()

    file_path = document_file.getRelativeUrl()
152
    package.edit(template_path_list=[file_path,])
153 154

    # Build package
155
    import_package = self._buildAndExportBusinessPackage(package)
156 157 158 159 160 161

    # Delete document from site
    self.portal.document_module.manage_delObjects([document_file.getId(),])
    self.tic()

    # Test if the file is gone
162
    self.assertRaises(KeyError, lambda: self.portal.restrictedTraverse(file_path))
163
    #import_package = self._importBusinessPackage(package)
164 165

    # Install package
166
    self._installBusinessPackage(import_package)
167 168 169

    # Test if the file is back
    self.assertIsNotNone(self.portal.restrictedTraverse(file_path))
170 171
    document = self.portal.restrictedTraverse(file_path)
    self.assertEquals(document.title, 'Test Document')
172 173 174

  def test_sameFileImportAndReinstallOnTwoPackages(self):
    """
175 176
    Test two Business Packages build and installation of same file.

177 178 179
    Here we will be using Insatallation Tree to install in the two packages
    all together, rather than doing installation one after another.

180 181 182
    Expected result: If we install same object from 2 different business packages,
    then in that case the installation object should compare between the
    state of OFS and installation and install accordingly.
183
    """
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208

    old_package = self._createBusinessPackage()
    new_package = self._createBusinessPackage()

    document_file = self.portal.document_module.newContent(
                                    portal_type = 'File',
                                    title = 'Test Document',
                                    reference = 'erp5-package.Test.Document.Two.BP',
                                    data = 'test file',
                                    content_type = None)
    self.tic()

    file_path = document_file.getRelativeUrl()
    old_package.edit(template_path_list=[file_path,])
    new_package.edit(template_path_list=[file_path,])
    self.tic()

    # Build both the packages
    self._buildAndExportBusinessPackage(old_package)
    self._buildAndExportBusinessPackage(new_package)
    self.tic()

    # Get installation data from the list of packages which we want to install
    package_list = [old_package, new_package]

209
    final_data, conflicted_data = createInstallationData(package_list)
210 211 212 213 214 215 216 217

    # Delete document from site
    self.portal.document_module.manage_delObjects([document_file.getId(),])
    self.tic()

    # Test if the file doesn't exist on site anymore
    self.assertRaises(KeyError, lambda: self.portal.restrictedTraverse(file_path))

218 219 220 221 222 223 224 225 226 227 228 229
    if not conflicted_data:
      # Create InstallationTree object
      installation_tree = InstallationTree(final_data)
      # We try to install pakcages via mapping the installation tree to ZODB
      # As both have exactly same document we expect that only one of them get installed
      installation_tree.mapToERP5Site(self.portal)


    # Test if the file is back
    self.assertIsNotNone(self.portal.restrictedTraverse(file_path))
    document = self.portal.restrictedTraverse(file_path)
    self.assertEquals(document.title, document_file.title)
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

  def test_AddConflictedFileAtSamePathViaTwoPackages(self):
    """
    Test the result of conflict of two files to be installed at same path
    by two different Business Packages
    """
    old_package = self._createBusinessPackage()
    new_package = self._createBusinessPackage()

    document_file = self.portal.document_module.newContent(
                                    portal_type = 'File',
                                    title = 'Test Document',
                                    reference = 'erp5-package.Test.Document.Two.BP',
                                    data = 'test file',
                                    content_type = None)
    self.tic()

    file_path = document_file.getRelativeUrl()
    old_package.edit(template_path_list=[file_path,])

    # Build the first package
    self._buildAndExportBusinessPackage(old_package)
    self.tic()

    # Change something in the document file
255
    document_file.edit(data='Voila, we play with conflict')
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
    self.tic()
    new_package.edit(template_path_list=[file_path,])

    # Build the second package
    self._buildAndExportBusinessPackage(new_package)
    self.tic()

    # Get installation data from the list of packages which we want to install
    package_list = [old_package, new_package]

    final_data, conflicted_data = createInstallationData(package_list)

    # Delete document from site
    self.portal.document_module.manage_delObjects([document_file.getId(),])
    self.tic()

    # Assert that the final data is empty and conflicted data contains \
    # two different versions of the file
    self.assertFalse(final_data)
    self.assertTrue(conflicted_data)
    self.assertEquals(len(conflicted_data[file_path]), 2)
277

278
  def test_checkPathTemplateBuildForFolder(self):
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    """
    This test should ensure that we are able to use folder as path for Business
    Packages without the need to export every path inside it explicitly

    In this test, we take the example to do this first with default catalog,
    then with multiple catalogs
    """

    # With single catalog
    folder_path = 'portal_catalog/erp5_mysql_innodb/**'
    package = self._createBusinessPackage()
    package.edit(template_path_list=[folder_path,])
    self._buildAndExportBusinessPackage(package)
    self.tic()

    # Check for the presence of catalog objects/paths in the business package
    built_package = self.portal._getOb(package.getId())
    path_item = built_package._path_item

    folder = self.portal.unrestrictedTraverse('portal_catalog/erp5_mysql_innodb')
    folder_object_id_list = sorted([l for l in folder.objectIds()])
    folder_object_count =  len(folder_object_id_list)

    package_object_id_list = sorted([l.getId() for l in path_item._objects.values()])
    package_object_count = len(package_object_id_list)

    self.assertEquals(folder_object_count, package_object_count)
    self.assertEquals(folder_object_id_list, package_object_id_list)

    # With multiple catalogs
    folder_path_list = [ 
          'portal_catalog/erp5_mysql_innodb/**',
          'portal_catalog/erp5_mysql_innodb100/**'
          ]

    package.edit(template_path_list=folder_path_list)
    self.tic()
    # XXX: Here, we are not exporting the package and its objects, just building
    # and saving it inside the package for the tests.
    self._buildAndExportBusinessPackage(package)
    self.tic()

    # Check for presence of catalog objects from all the catalogs mentioned in
    # the folder path list
    built_package = self.portal._getOb(package.getId())
    path_item = built_package._path_item
    new_folder = self.portal.unrestrictedTraverse('portal_catalog/erp5_mysql_innodb100')
    new_folder_id_list = sorted([l for l in new_folder.objectIds()])
    new_folder_object_count =  len(new_folder_id_list)

    total_object_count  = new_folder_object_count + folder_object_count
    package_object_id_list = sorted([l.getId() for l in path_item._objects.values()])
    object_id_list = sorted(folder_object_id_list + new_folder_id_list) 
    package_object_count = len(package_object_id_list)
    self.assertEquals(total_object_count, package_object_count)
    self.assertEquals(object_id_list, package_object_id_list)
335 336 337 338 339 340 341 342 343

  def test_addObjectPropertyTemplateItemInPackage(self):
    """
    Add ObjectPropertyTemplateItem to Business Package with the hash
    """
    package = self._createBusinessPackage()
    relative_url = 'portal_catalog/erp5_mysql_innodb'
    file_path_list = [relative_url]

344
    portal_catalog = self.portal.portal_catalog
345 346 347 348 349
    catalog_object = self.portal.unrestrictedTraverse(relative_url)
    object_property_list = []
    for property_id in catalog_object.propertyIds(): 
      object_property_list.append('%s | %s'%(relative_url, property_id))

350 351 352
    for property_id in portal_catalog.propertyIds():
      object_property_list.append('%s | %s'%(portal_catalog.getRelativeUrl(), property_id))

353 354 355 356 357 358 359 360 361 362
    package.edit(template_path_list=file_path_list)
    package.edit(template_object_property_list=object_property_list)
    self.tic()

    self._buildAndExportBusinessPackage(package)
    self.tic()

    # Check for presence of catalog objects from all the catalogs mentioned in
    # the folder path list
    built_package = self.portal._getOb(package.getId())
363 364 365 366 367 368 369 370 371
    object_property_item = built_package._object_property_item

    property_object_path_list = sorted(object_property_item._objects.keys())
    self.assertIn(relative_url, property_object_path_list)
    self.assertIn(portal_catalog.getRelativeUrl(), property_object_path_list)

    property_object_hash_list = sorted(object_property_item._hash.keys())
    self.assertIn(relative_url, property_object_hash_list)
    self.assertIn(portal_catalog.getRelativeUrl(), property_object_hash_list)
372 373 374 375 376 377 378

  def test_udpateInstallationStateOnlyForBusinessPackage(self):
    """
    Updating Business Package with the changed installation state and trying
    to show the diff between the two installation state
    """
    pass