# -*- coding: utf-8 -*
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
#                    Cedric de Saint Martin <cedric.dsm@tiolive.com>
#
# 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 advised 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.
#
##############################################################################

"""Vifib and Slapgrid interaction scenarios"""
import os
import random
import shutil
import signal
import stat
import subprocess
import glob
import re
import xmlrpclib
from DateTime import DateTime
from StringIO import StringIO
from supervisor.xmlrpc import SupervisorTransport

from Testing.ZopeTestCase import _print
import Products.ERP5Type.tests.ERP5TypeLiveTestCase
from Products.ERP5Type.tests.ERP5TypeLiveTestCase import ERP5TypeLiveTestCase
reload(Products.ERP5Type.tests.ERP5TypeLiveTestCase)
ERP5TypeLiveTestCase = Products.ERP5Type.tests.ERP5TypeLiveTestCase.\
     ERP5TypeLiveTestCase
from Products.ERP5Type.tests.Sequence import SequenceList
import transaction

class SubprocessTimeout(Exception):
  pass

def subprocess_timeout_handler(signum, frame):
  raise SubprocessTimeout('Break by %s' % signum)

class TestManualDefaultSetup(ERP5TypeLiveTestCase):
  """Tests default manual setup and slapgrid result"""
  computer_module_portal_type = 'Computer Module'
  computer_partition_portal_type = 'Computer Partition'
  computer_portal_type = 'Computer'
  document_module_portal_type = 'Document Module'
  file_portal_type = 'File'
  hosting_subscription_module_portal_type = 'Hosting Subscription Module'
  hosting_subscription_portal_type = 'Hosting Subscription'
  internet_protocol_address_portal_type = 'Internet Protocol Address'
  purchase_packing_list_portal_type = "Purchase Packing List"
  purchase_packing_list_line_portal_type = "Purchase Packing List Line"
  sale_packing_list_line_portal_type = 'Sale Packing List Line'
  sale_packing_list_module_portal_type = 'Sale Packing List Module'
  sale_packing_list_portal_type = 'Sale Packing List'
  service_module_portal_type = 'Service Module'
  service_portal_type = 'Service'
  software_instance_module_portal_type = 'Software Instance Module'
  software_instance_portal_type = 'Software Instance'
  software_product_portal_type= 'Software Product'
  software_release_module_portal_type = 'Software Release Module'
  software_release_portal_type = 'Software Release'
  usage_report_portal_type = 'Usage Report'

  def afterSetUp(self):
    # validate needed rules
    self.cleanup_list = []
    #self.validateRules()
    self.login("devel")

  def beforeTearDown(self):
    #self.cleanupGarbage()
    pass#transaction.commit()

  def collectGarbage(self, document):
    """Keeps a list of documents to erase at the end of the test
    """
    self.cleanup_list.append(document)

  def cleanupGarbage(self):
    if getattr(self, 'cleanup_list', None) is None:
      return
    for document in self.cleanup_list:
      parent = document.getParentValue()
      document_id = document.getId()
      #if document_id in parent.objectIds():
      parent.manage_delObjects(ids=[document_id])

  #
  # Helper methods
  #
  def defineIds(self):
    """Generates need ids, names and path in order them to be unique"""
    self.tmp_directory = "/tmp"
    try:
      self.tmp_directory = os.environ['TMP']
    except KeyError:
      pass
    self.computer_guid = '%s%s' % ('testslapgrid', #self.id().replace('__', ''),
          int(random.random() * 100000000))
    self.partition_id = '%spart' % self.computer_guid
    self.ip_address = '127.0.0.1'
    self.tcp_port = "1234"
    self.udp_port = "1234"
    self.python_binary = "/home/nexediadmin/python2.6/parts/python2.6/bin/python2.6"
    self.vifib_product_directory = '/home/nexediadmin/vifib-devel-instance/'\
        'buildbot/Products/Vifib/'
    self.working_directory = os.path.join(self.tmp_directory, self.computer_guid)
    self.slapgrid_buildout_directory = os.path.join(self.working_directory,
        'slapgrid_buildout')
    self.buildout_binary = os.path.join(self.slapgrid_buildout_directory,
        'bin', 'buildout')
    self.slapgrid_binary = os.path.join(self.slapgrid_buildout_directory,
        'bin', 'slapgrid')
    self.bootstrap_py_file = os.path.join(self.vifib_product_directory, 'tests',
        'test_data', 'bootstrap.py')
    self.slapgrid_buildout_cfg_file = os.path.join(self.vifib_product_directory,
        'tests', 'test_data', 'slapgrid.buildout.cfg')
    self.software_root_directory = os.path.join(self.working_directory,
        'software_root')
    self.instance_root_directory = os.path.join(self.working_directory,
        'instance_root')
    self.computer_partition_directory = os.path.join(
        self.instance_root_directory, self.partition_id)
    self.supervisor_socket = os.path.join(self.instance_root_directory,
        'supervisor.sock')
  
  def createTestSequenceAndPlay(self, sequence_string):
    """Creates a test sequence, try to play it, then clean up directories"""
    sequence_list = SequenceList()
    sequence_list.addSequenceString(sequence_string)
    try:
      sequence_list.play(self)
    finally:
      if os.path.exists(self.working_directory):
        if os.path.exists(self.supervisor_socket):
          self.shutdownSupervisor()
        if os.environ.get('SLAP_TEST_KEEP_WORKDIR', 'false').lower() != 'true':
          try:
            shutil.rmtree(self.working_directory)
          except OSError:
            shutil.rmtree(self.working_directory)
        else:
          _print('Working directory %r kept.'% self.working_directory)
          
  def appendAggregateToDocument(self, sequence, document_id, append_id):
    document = sequence.get(document_id)
    append = sequence.get(append_id)
    document.edit(
        aggregate_list=document.getAggregateList() + [append.getRelativeUrl()]
    )

  def prepareDirectoryStructure(self):
    """Simulates human which prepares directory structure on server"""
    # first level of working directory - test environment specific
    os.mkdir(self.working_directory)
    # directory where slapgrid will be installed by buildout
    os.mkdir(self.slapgrid_buildout_directory)
    # directory which will be used by slapgrid software
    os.mkdir(self.software_root_directory)
    # directory which will be used by slapgrid instance
    os.mkdir(self.instance_root_directory)
    # and system administrator is responsible for creating computer partition
    os.mkdir(self.computer_partition_directory)
    os.chmod(self.computer_partition_directory, 0750)

  def callAndPrint(self, command_list, remove_from_env=None, asserts=True,
      **subprocess_kwargs):
    _print('\nInvoking %r:\n'%command_list)
    try:
      signal.signal(signal.SIGALRM, subprocess_timeout_handler)
      signal.alarm(int(os.environ.get('SLAP_TEST_SUBPROCESS_TIMEOUT', 300)))
    except ValueError:
      _print('\nCould not set signal.alarm.')
    if remove_from_env is not None:
      subprocess_kwargs['env'] = self.getCleanedEnviron(remove_from_env)
    try:
      subprocess_kwargs.update(stdout=subprocess.PIPE,
          stderr=subprocess.STDOUT)
      popen = subprocess.Popen(command_list, **subprocess_kwargs)
      result = popen.communicate()[0]
      _print(result)
    finally:
      try:
        signal.alarm(0)
      except ValueError:
        pass
    if asserts:
      self.assertEqual(0, popen.returncode,
        'Command %r failed with message:\n%s' % (command_list, result))

  def getCleanedEnviron(self, to_remove_list):
    current_env = os.environ.copy()
    for k in to_remove_list:
      current_env.pop(k, None)
    return current_env

  def bootstrapSlapgridBuildout(self):
    command_list = [self.python_binary, '-S', self.bootstrap_py_file, '-d',
        '-c', self.slapgrid_buildout_cfg_file, 'buildout:directory=%s'%
        self.slapgrid_buildout_directory]
    self.callAndPrint(command_list, cwd=self.slapgrid_buildout_directory,
      remove_from_env=['SOFTWARE_HOME', 'PYTHONPATH',
          'ZOPE_HOME', 'CLIENT_HOME'])

  def runSlapgridBuildout(self):
    command_list = [self.python_binary, '-S', self.buildout_binary, '-U', '-c',
      self.slapgrid_buildout_cfg_file,
      'buildout:directory=%s'% self.slapgrid_buildout_directory,
      'buildout:find-links=%s' % 'https://nexedivifib1.dyn.majimoto.net:40443/'\
          'erp5/web_site_module/erpypi/']
    self.callAndPrint(command_list, remove_from_env=[
      'SOFTWARE_HOME', 'PYTHONPATH', 'ZOPE_HOME', 'CLIENT_HOME'])

  def shutdownSupervisor(self):
    xmlrpclib.ServerProxy('http://127.0.0.1', SupervisorTransport('', '',
      'unix://%s' % self.supervisor_socket)).supervisor.shutdown()

  #
  # Steps
  #
  def stepRunSlapgrid(self, sequence=None):
    """Runs slapgrid binary

    On purpose python environment and site is imported.
    slapgrid shall work correctly in such case and it is its job to clean
    python before running buildout or external python binaries.

    Note: Unfortunately ERP5 tests runs with heavily modified environment and
          it is *just* impossible to run print 'hello world' in different
          python (as PYTHONPATH is set to python2.4 and slapgrid shall run with
          python2.6).
    """
    command_list = [self.slapgrid_binary,
      '--software-root', self.software_root_directory,
      '--instance-root', self.instance_root_directory,
      '--master-url', self.portal.portal_slap.absolute_url(),
      '--computer-id', sequence.get('computer').getReference(),
      '--supervisord-socket', self.supervisor_socket]
    self.callAndPrint(command_list, remove_from_env=[
      'SOFTWARE_HOME', 'PYTHONPATH', 'ZOPE_HOME', 'CLIENT_HOME'])

  def stepRunSlapgridWithoutAssert(self, sequence=None):
    """Runs slapgrid binary

    On purpose python environment and site is imported.
    slapgrid shall work correctly in such case and it is its job to clean
    python before running buildout or external python binaries.

    Note: Unfortunately ERP5 tests runs with heavily modified environment and
          it is *just* impossible to run print 'hello world' in different
          python (as PYTHONPATH is set to python2.4 and slapgrid shall run with
          python2.6).
    """
    command_list = [self.slapgrid_binary,
      '--software-root', self.software_root_directory,
      '--instance-root', self.instance_root_directory,
      '--master-url', self.portal.portal_slap.absolute_url(),
      '--computer-id', sequence.get('computer').getReference(),
      '--supervisord-socket', self.supervisor_socket]
    return self.callAndPrint(command_list, remove_from_env=[
        'SOFTWARE_HOME', 'PYTHONPATH', 'ZOPE_HOME',
        'CLIENT_HOME'], asserts=False)

  def stepPrepareTestingEnvironment(self, sequence=None):
    self.prepareDirectoryStructure()
    self.bootstrapSlapgridBuildout()
    self.runSlapgridBuildout()

  def stepCreateSoftwareReleaseFile(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.document_module_portal_type)
    software_release_file=module.newContent(
        portal_type=self.file_portal_type,
        title='testVifibSlapgrid')
    self.cleanup_list.append(software_release_file)
    sequence.edit(software_release_file=software_release_file)

  def stepCreateSoftwareTemplateFile(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.document_module_portal_type)
    software_template_file = module.newContent(
      portal_type=self.file_portal_type,
      title='testVifibSlapgrid')
    self.cleanup_list.append(software_template_file)
    sequence.edit(software_template_file=software_template_file)

  def stepLoadSoftwareTemplateFile(self, sequence=None):
    software_template_file = sequence.get('software_template_file')
    software_template_file.edit(source_reference='%s-template.cfg' \
        % self.computer_guid,
       version='1',
       file=StringIO(str("""[buildout]
parts =
  dummy-software-instance

[dummy-software-instance]
recipe = collective.recipe.template
input = inline:
  #! /bin/sh
  exec ${source_location}/bin/slapmonitor ${source_location}/bin/dummy-software
output = ${target_location}/bin/run
mode = 755
""")))

  def stepSetReferenceOnSoftwareTemplateFile(self, sequence=None):
    software_template_file = sequence.get('software_template_file')
    software_template_file.edit(reference=self.computer_guid + \
        "_template")

  def stepLoadSoftwareReleaseFile(self, sequence=None):
    software_release_file = sequence.get('software_release_file')
    software_template_file = sequence.get('software_template_file')
    host_pattern = re.compile('^(?:f|ht)tp(?:s)?\://([^/]+)')
    hostname = host_pattern.findall(software_template_file.getAbsoluteUrl())[0]
    software_template_file_uri = 'https://%s/erp5/web_site_module/erpypi/' \
        '%s-1.cfg' % (hostname, software_template_file.getReference())
    content = """[buildout]
parts =
  dummy-software
  dummy-software-template
  slap-monitor
# slap monitor shall be took from trunk
find-links =
  https://nexedivifib1.dyn.majimoto.net:40443/erp5/web_site_module/erpypi/slapos.slapmonitor-0.0.6dev.tar.gz

[dummy-software]
recipe = collective.recipe.template
input = inline:
  #!/bin/sh
  while :; do
    echo "This is dummy software"
    sleep 5
  done

output = ${buildout:bin-directory}/dummy-software
mode = 755

[dummy-software-template]
recipe = hexagonit.recipe.download
url = @DUMMY_SOFTWARE_TEMPLATE@
download-only = true
destination = ${buildout:directory}
filename = template.cfg

[slap-monitor]
recipe = zc.recipe.egg:scripts
eggs =
  slapos.slapmonitor
""".replace('@DUMMY_SOFTWARE_TEMPLATE@', software_template_file_uri)
    source_reference = '%s.cfg' % self.computer_guid
    software_release_file.edit(file=content, source_reference=source_reference,
        version='1')

  def stepLoadEmptySoftwareReleaseFile(self, sequence=None):
    software_release_file = sequence.get('software_release_file')
    content = StringIO(str("""[buildout]
parts = empty_parts

[empty_parts]
recipe = collective.recipe.template
input = inline:
  #!/bin/sh
  sleep 5
output = /dev/null"""))
    source_reference = '%s.cfg' % self.computer_guid
    software_release_file.edit(source_reference= source_reference,
        file=content, version='1')
    content.close()

  def stepLoadTrappedSoftwareReleaseFile(self, sequence=None):
    software_release_file = sequence.get('software_release_file')
    content = StringIO(str(""))
    source_reference = '%s.cfg' % self.computer_guid
    software_release_file.edit(source_reference= source_reference,
        file=content)
    content.close()

  def stepSetReferenceOnSoftwareReleaseFile(self, sequence=None):
    software_release_file = sequence.get('software_release_file')
    software_release_file.edit(reference=self.computer_guid + \
        "_software_release_file")

  def stepPublishSoftwareTemplateFile(self, sequence=None):
    software_template_file = sequence.get('software_template_file')
    software_template_file.publish()

  def stepPublishSoftwareReleaseFile(self, sequence=None):
    software_release_file = sequence.get('software_release_file')
    software_release_file.publish()

  def stepCreateSoftwareAvailabilityService(self, sequence=None):
    software_availability_service = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredSoftwareSetupResource())
    sequence.edit(software_availability_service=software_availability_service)

  def stepCreateInstanceSetupService(self, sequence=None):
    instance_setup_service = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredInstanceSetupResource())
    sequence.edit(instance_setup_service=instance_setup_service)

  def stepCreateInstanceHostingService(self, sequence=None):
    instance_hosting_service = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredInstanceHostingResource())
    sequence.edit(instance_hosting_service=instance_hosting_service)

  def stepCreateInstanceDestroyService(self, sequence=None):
    instance_destroy_service = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredInstanceCleanupResource())
    sequence.edit(instance_destroy_service=instance_destroy_service)

  def stepCreateSoftwareRelease(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.software_release_module_portal_type)
    software_release = module.newContent(
        portal_type=self.software_release_portal_type,
        title='testVifibSlapgrid Software Release')
    self.cleanup_list.append(software_release)
    sequence.edit(software_release=software_release)

  def stepSetSoftwareReleaseUri(self, sequence=None):
    software_release = sequence.get('software_release')
    software_release_file = sequence.get('software_release_file')
    host_pattern = re.compile('^(?:f|ht)tp(?:s)?\://([^/]+)')
    hostname = host_pattern.findall(software_release_file.getAbsoluteUrl())[0]
    software_release_uri = 'https://%s/erp5/web_site_module/erpypi/%s-1.cfg' % (
        hostname, software_release_file.getReference())
    software_release.edit(url_string=software_release_uri)

  def stepSetAggregateToSoftwareRelease(self, sequence=None):
    software_product = self.portal.portal_catalog(
      id='test_software_product',
      portal_type=self.software_product_portal_type)[0].getObject()
    sequence.edit(software_product=software_product)
    self.appendAggregateToDocument(sequence, 'software_release',
        'software_product')
        
  def stepPublishSoftwareRelease(self, sequence=None):
    software_release = sequence.get('software_release')
    software_release.publish()

  def stepCreateComputer(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.computer_module_portal_type)
    computer = module.newContent(portal_type=self.computer_portal_type,
        title='testVifibSlapgrid')
    self.cleanup_list.append(computer)
    sequence.edit(computer=computer)

  def stepSetReferenceOnComputer(self, sequence=None):
    computer = sequence.get('computer')
    computer.edit(reference=self.computer_guid)

  def stepCreateComputerPartition(self, sequence=None):
    computer = sequence.get('computer')
    computer_partition = computer.newContent(
        portal_type=self.computer_partition_portal_type)
    self.cleanup_list.append(computer_partition)
    sequence.edit(computer_partition=computer_partition)

  def stepValidateComputerPartition(self, sequence=None):
    computer_partition = sequence.get('computer_partition')
    computer_partition.validate()
    # Mark newly created computer partition as free by default
    computer_partition.markFree()

  def stepSetReferenceOnComputerPartition(self, sequence=None):
    computer_partition = sequence.get('computer_partition')
    computer_partition.edit(reference=self.partition_id)

  def stepCreateInternetProtocolAddress(self, sequence=None):
    computer = sequence.get('computer_partition')
    internet_protocol_address = computer.newContent(
        portal_type=self.internet_protocol_address_portal_type,
        ip_address='127.0.0.1',
        network_interface='eth0')
    self.cleanup_list.append(internet_protocol_address)
    sequence.edit(internet_protocol_address=internet_protocol_address)

  def stepSetIpAndTcpPortAndUdpPortOnInternetProtocolAddress(self,
      sequence=None):
    internet_protocol_address = sequence.get('internet_protocol_address')
    internet_protocol_address.edit(ip_address=self.ip_address,
        tcp_port_number=self.tcp_port,
        udp_port_number=self.udp_port,
        id='default_network_address')

  def stepValidateComputer(self, sequence=None):
    computer = sequence.get('computer')
    computer.validate()
    self.assertEqual('validated', computer.getValidationState())

  def stepTerminateSoftwareInstance(self, sequence=None):
    software_instance = sequence.get('software_instance')
    software_instance.terminate()
    self.assertEqual('terminate_requested',
        software_instance.getRequestState())

  def stepCreateSoftwareInstance(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.software_instance_module_portal_type)
    software_instance = module.newContent(
      portal_type=self.software_instance_portal_type,
      title='testVifibSlapgrid')
    self.cleanup_list.append(software_instance)
    sequence.edit(software_instance=software_instance)
    
  def stepSetReferenceOnSoftwareInstance(self, sequence=None):
    software_instance = sequence.get('software_instance')
    software_instance.edit(reference='%s_softwareinstance' % self.computer_guid)

  def stepCreateHostingSubscription(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.hosting_subscription_module_portal_type)
    hosting_subscription = module.newContent(
      portal_type=self.hosting_subscription_portal_type,
      title='testVifibSlapgrid')
    self.cleanup_list.append(hosting_subscription)
    sequence.edit(hosting_subscription=hosting_subscription)

  def stepSetSoftwareInstanceMemcachedXml(self, sequence=None):
    software_instance = sequence.get('software_instance')
    software_instance.edit(text_content=self.software_instance_xml)

  def stepCreateSetupSalePackingList(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.sale_packing_list_module_portal_type)
    sale_packing_list = module.newContent(
      portal_type=self.sale_packing_list_portal_type)
    sale_packing_list.edit(title='testVifibSlapgrid Setup SPL')
    self.cleanup_list.append(sale_packing_list)
    sequence.edit(setup_sale_packing_list=sale_packing_list)

  def stepCreateSetupSalePackingListLine(self, sequence=None):
    sale_packing_list = sequence.get('setup_sale_packing_list')
    sale_packing_list_line = sale_packing_list.newContent(
      portal_type=self.sale_packing_list_line_portal_type)
    self.cleanup_list.append(sale_packing_list_line)
    sequence.edit(setup_sale_packing_list_line=sale_packing_list_line)

  def stepSetSetupSalePackingListLineInstanceSetupResource(self, sequence=None):
    sale_packing_list_line = sequence.get('setup_sale_packing_list_line')
    instance_setup_service = sequence.get('instance_setup_service')
    sale_packing_list_line.edit(resource_value=instance_setup_service)
    self.assertNotEqual(None, instance_setup_service)

  def stepAppendSetupSalePackingListLineComputerPartitionAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'setup_sale_packing_list_line',
        'computer_partition')

  def stepAppendSetupSalePackingListLineSoftwareInstanceAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'setup_sale_packing_list_line',
        'software_instance')

  def stepAppendSetupSalePackingListLineSoftwareReleaseAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'setup_sale_packing_list_line',
        'software_release')

  def stepAppendSetupSalePackingListLineHostingSubscriptionAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'setup_sale_packing_list_line',
        'hosting_subscription')

  def stepConfirmSetupSalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('setup_sale_packing_list')
    sale_packing_list.portal_workflow.doActionFor(sale_packing_list,
        'confirm_action')
    self.assertEqual('confirmed', sale_packing_list.getSimulationState())

  def stepStopSetupSalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('setup_setup_sale_packing_list')
    sale_packing_list.stop()
    self.assertEqual('stopped',
        sale_packing_list.getSimulationState())

  def stepSetStartDateOnSetupSalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('setup_sale_packing_list')
    sale_packing_list.edit(start_date=DateTime())

  def stepCreateHostingSalePackingList(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.sale_packing_list_module_portal_type)
    sale_packing_list = module.newContent(
      portal_type=self.sale_packing_list_portal_type,
      title='testVifibSlapgrid Hosting SPL')
    self.cleanup_list.append(sale_packing_list)
    sequence.edit(hosting_sale_packing_list=sale_packing_list)

  def stepCreateHostingSalePackingListLine(self, sequence=None):
    sale_packing_list = sequence.get('hosting_sale_packing_list')
    sale_packing_list_line = sale_packing_list.newContent(
      portal_type=self.sale_packing_list_line_portal_type)
    self.cleanup_list.append(sale_packing_list_line)
    sequence.edit(hosting_sale_packing_list_line=sale_packing_list_line)

  def stepSetHostingSalePackingListLineInstanceHostingResource(self,
      sequence=None):
    sale_packing_list_line = sequence.get('hosting_sale_packing_list_line')
    instance_hosting_service = sequence.get('instance_hosting_service')
    sale_packing_list_line.edit(resource_value=instance_hosting_service)
    self.assertNotEqual(None, instance_hosting_service)

  def stepAppendHostingSalePackingListLineComputerPartitionAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'hosting_sale_packing_list_line',
        'computer_partition')

  def stepAppendHostingSalePackingListLineSoftwareInstanceAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'hosting_sale_packing_list_line',
        'software_instance')

  def stepAppendHostingSalePackingListLineSoftwareReleaseAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'hosting_sale_packing_list_line',
        'software_release')

  def stepAppendHostingSalePackingListLineHostingSubscriptionAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'hosting_sale_packing_list_line',
        'hosting_subscription')

  def stepConfirmHostingSalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('hosting_sale_packing_list')
    sale_packing_list.confirm()
    self.assertEqual('confirmed', sale_packing_list.getSimulationState())

  def stepStopHostingSalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('hosting_sale_packing_list')
    sale_packing_list.stop()
    self.assertEqual('stopped',
        sale_packing_list.getSimulationState())

  def stepSetStartDateOnHostingSalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('hosting_sale_packing_list')
    sale_packing_list.edit(start_date=DateTime())

  def stepCreateDestroySalePackingList(self, sequence=None):
    module = self.portal.getDefaultModule(
        portal_type=self.sale_packing_list_module_portal_type)
    sale_packing_list = module.newContent(
      portal_type=self.sale_packing_list_portal_type,
      title='testVifibSlapgrid Destroy SPL')
    self.cleanup_list.append(sale_packing_list)
    sequence.edit(destroy_sale_packing_list=sale_packing_list)

  def stepCreateDestroySalePackingListLine(self, sequence=None):
    sale_packing_list = sequence.get('destroy_sale_packing_list')
    sale_packing_list_line = sale_packing_list.newContent(
      portal_type=self.sale_packing_list_line_portal_type)
    self.cleanup_list.append(sale_packing_list_line)
    sequence.edit(destroy_sale_packing_list_line=sale_packing_list_line)

  def stepSetDestroySalePackingListLineInstanceDestroyResource(self,
      sequence=None):
    sale_packing_list_line = sequence.get('destroy_sale_packing_list_line')
    instance_destroy_service = sequence.get('instance_destroy_service')
    sale_packing_list_line.edit(resource_value=instance_destroy_service)
    self.assertNotEqual(None, instance_destroy_service)

  def stepAppendDestroySalePackingListLineComputerPartitionAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'destroy_sale_packing_list_line',
        'computer_partition')

  def stepAppendDestroySalePackingListLineSoftwareInstanceAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'destroy_sale_packing_list_line',
        'software_instance')

  def stepAppendDestroySalePackingListLineSoftwareReleaseAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'destroy_sale_packing_list_line',
        'software_release')

  def stepAppendDestroySalePackingListLineHostingSubscriptionAggregate(self,
      sequence=None):
    self.appendAggregateToDocument(sequence, 'destroy_sale_packing_list_line',
        'hosting_subscription')

  def stepConfirmDestroySalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('destroy_sale_packing_list')
    sale_packing_list.confirm()
    self.assertEqual('confirmed', sale_packing_list.getSimulationState())

  def stepSetStartDateOnDestroySalePackingList(self, sequence=None):
    sale_packing_list = sequence.get('destroy_sale_packing_list')
    sale_packing_list.edit(start_date=DateTime())

  def stepCreatePurchasePackingList(self, sequence=None, 
                         sequence_list=None, **kw):
    """
    Create an purchase packing list document.
    """
    module = self.portal.getDefaultModule(
        portal_type=self.purchase_packing_list_portal_type)
    order = module.newContent(
        portal_type=self.purchase_packing_list_portal_type,
        title='testVifibSlapgrid')
    self.cleanup_list.append(order)
    sequence.edit(purchase_packing_list=order)

  def stepCreatePurchasePackingListLine(self, sequence=None, 
                         sequence_list=None, **kw):
    """
    Create an purchase packing list line document.
    """
    order = sequence.get("purchase_packing_list")
    line = order.newContent(
        portal_type=self.purchase_packing_list_line_portal_type)
    self.cleanup_list.append(line)
    sequence.edit(purchase_packing_list_line=line)

  def stepSetPurchasePackingListLineSoftwareResource(self, sequence=None):
    purchase_list_line = sequence.get('purchase_packing_list_line')
    service = sequence.get('software_availability_service')
    purchase_list_line.edit(resource_value=service)
    self.assertNotEqual(None, service)

  def stepSetPurchasePackingListLineAggregate(self, sequence=None, 
                         sequence_list=None, **kw):
    """
    Associate a computer and a software release to the purchase packing list
    line.
    """
    line = sequence.get("purchase_packing_list_line")
    line.edit(
        aggregate_uid_list=[sequence.get('computer').getUid(),
                            sequence.get('software_release').getUid()]
        )

  def stepConfirmPurchasePackingList(self, sequence=None, 
                         sequence_list=None, **kw):
    """
    Confirm the purchase packing list
    """
    order = sequence.get("purchase_packing_list")
    order.portal_workflow.doActionFor(order, 'confirm_action')

  #
  # Assertions
  #
  def stepAssertSoftwareInstanceExternalStateIsStarted(self, sequence=None):
    software_instance = sequence.get('software_instance')
    self.assertEqual('started', software_instance.getExternalState())

  def getPermissionString(self, path):
    return oct(stat.S_IMODE(os.stat(path).st_mode))

  def stepAssertClientGeneratedFileListPermissions(self, sequence=None):
    incorrect_permission_list = []
    # XXX-Luke: Is check software_root_directory really needed?

    # check instance_root_directory
    for directory in os.listdir(self.instance_root_directory):
      if os.path.samefile(os.path.join(self.instance_root_directory,
        directory), self.computer_partition_directory):
        continue
      for walk_tuple in os.walk(os.path.join(self.instance_root_directory,
        directory)):
        path = walk_tuple[0]
        permission = self.getPermissionString(path)
        if permission not in ('0600', '0700'):
          incorrect_permission_list.append('%s:%s'%(path, permission))

    self.assertEqual([], incorrect_permission_list,
        'Insecure file permissions:\n%s' % '\n'.join(
          incorrect_permission_list))

  def _assertPathExistence(self, parent, path_list):
    non_existing_path_list = []
    for path in path_list:
      path = os.path.join(parent, path)
      if not os.path.exists(path):
        non_existing_path_list.append(path)
    self.assertEqual([], non_existing_path_list,
        'Missing paths:\n%s\n' % '\n'.join(non_existing_path_list))

  def stepAssertClientSoftwareReleaseInstalled(self, sequence=None):
    software_root_directory_list = os.listdir(self.software_root_directory)
    self.assertEqual(1, len(software_root_directory_list))

    software_release_directory = [d for d in software_root_directory_list
        if not d.endswith('bin')][0]
    software_release_directory = os.path.join(self.software_root_directory,
        software_release_directory)
    self._assertPathExistence(software_release_directory,
        ['bin/dummy-software', 'bin/slapmonitor', 'template.cfg'])

  def stepAssertClientComputerPartitionInstalled(self, sequence=None):
    self._assertPathExistence(self.computer_partition_directory,
        ['buildout.cfg', 'bin/run'])

  def stepAssertUsageReport(self, sequence=None):
    computer_partition = sequence.get('computer_partition')
    usage_report_list = computer_partition.getCausalityRelatedValueList(
        portal_type=self.usage_report_portal_type)
    self.assertEqual(1, len(usage_report_list))
    usage_report = usage_report_list[0]
    delivery_line_list = usage_report.getAggregateRelatedValueList(
        portal_type=self.sale_packing_list_line_portal_type)
    self.assertEqual(1, len(delivery_line_list))
    delivery_line = delivery_line_list[0]
    self.assertEqual('started', delivery_line.getSimulationState())
    # XXX-Luke: To assert resource it have to be unhardcoded

  def stepAssertClientComputerPartitionIsNotRunning(self, sequence=None):
    computer_partition = sequence.get('computer_partition')
    server_proxy = xmlrpclib.ServerProxy('http://127.0.0.1',
        SupervisorTransport('', '', 'unix://%s' % self.supervisor_socket))
    supervisor_state = server_proxy.supervisor.getProcessInfo(
        computer_partition.getReference())
    self.assertEqual('STOPPED', supervisor_state['statename'])

  def stepAssertClientComputerPartitionIsRunning(self, sequence=None):
    computer_partition = sequence.get('computer_partition')
    server_proxy = xmlrpclib.ServerProxy('http://127.0.0.1',
        SupervisorTransport('', '', 'unix://%s' % self.supervisor_socket))
    supervisor_state = server_proxy.supervisor.getProcessInfo(
        computer_partition.getReference())
    self.assertEqual('RUNNING', supervisor_state['statename'])

  def stepAssertComputerPartitionIsAssigned(self, sequence=None):
    """Checks if current computer partition is not empty"""
    self.assertNotEqual([], glob.glob(self.computer_partition_directory))

  def stepAssertComputerPartitionIsNotAssigned(self, sequence=None):
    """Checks if current computer partition is empty"""
    self.assertEqual([], glob.glob(self.computer_partition_directory))

  def stepAssertComputerPartitionIsCleaned(self, sequence=None):
    """Checks if current computer partition is empty"""
    self.assertEqual([], glob.glob(os.path.join(
        self.computer_partition_directory, '*')))

  def stepAssertSoftwareReleaseErrorReported(self, sequence=None):
    #We test here that software Release Error exist in ERP5
    computer = sequence.get('computer')
    #Now we are testing if External Workflows is in error state
    #self.assertEqual("error", computer.getSlapState())
    last_history_action = computer.portal_workflow.getInfoFor(ob=computer,
        name='history', wf_id='computer_slap_interface_workflow')[-1]['action']
    self.assertEqual(last_history_action, 
        'report_software_release_installation_error')

  def stepAssertSoftwareInstanceErrorReported(self, sequence=None):
    software_instance = sequence.get('software_instance')
    #self.assertEqual("error", software_instance.getSlapState())
    last_history_action = software_instance.portal_workflow.getInfoFor(
        ob=software_instance, name='history',
        wf_id='software_instance_slap_interface_workflow')[-1]['action']
    self.assertEqual(last_history_action, 'report_computer_partition_error')

  def stepCrash(self, sequence):
    """Debugging purpose, stop test"""
    raise OSError()

  #
  # Tests
  #
  def testSlapgridHandlesInstanceState(self):
    """Testing if slapgrid correctly handles partition states.
    Use case : 
    - create a Software release profile which informs the test runner when
      start/stop argument is passed to the wrapper.
    - create all needed objects in ERP5 (as done in "test")
    - change the instance state in ERP5 to start
    - check that the wrapper returns the expected value
    - change the instance state in ERP5 to stop
    - check that the wrapper returns the expected value
    - change the instance state in ERP5 to start
    - check that the wrapper returns the expected value
    - change the instance state in ERP5 to stop
    - check that the wrapper returns the expected value
    - change the instance state in ERP5 to terminated
    - check that slapgrid cleans the computer partition 
    - configure a new software instance
    - check that the computer partition is assigned to this new instance
    - configure a third new software instance
    - check that the computer partition is not assigned to this new instance
    """
    self.defineIds()
    self.software_instance_xml = """<?xml version="1.0" encoding="utf-8"?>
<instance>
<parameter id="memcached_tcp_port">9998</parameter>
<parameter id="memcached_udp_port">9998</parameter>
<parameter id="memcached_host">127.0.0.1</parameter>
<parameter id="memcached_memory_size">2</parameter>
</instance>"""
    sequence_string = """
      Tic
      CreateSoftwareAvailabilityService
      CreateInstanceSetupService
      CreateInstanceHostingService
      CreateInstanceDestroyService
      CreateSoftwareTemplateFile
      LoadSoftwareTemplateFile
      SetReferenceOnSoftwareTemplateFile
      PublishSoftwareTemplateFile
      CreateSoftwareReleaseFile
      LoadSoftwareReleaseFile
      PublishSoftwareReleaseFile
      CreateSoftwareRelease
      SetReferenceOnSoftwareReleaseFile
      SetSoftwareReleaseUri
      SetAggregateToSoftwareRelease
      PublishSoftwareRelease
      CreateComputer
      SetReferenceOnComputer
      ValidateComputer
      Tic
      CreateComputerPartition
      SetReferenceOnComputerPartition
      CreateInternetProtocolAddress
      Tic
      SetIpAndTcpPortAndUdpPortOnInternetProtocolAddress
      ValidateComputerPartition
      CreateHostingSubscription
      CreateSoftwareInstance
      SetReferenceOnSoftwareInstance
      SetSoftwareInstanceMemcachedXml
      CreateSetupSalePackingList
      CreateSetupSalePackingListLine
      SetSetupSalePackingListLineInstanceSetupResource
      AppendSetupSalePackingListLineComputerPartitionAggregate
      AppendSetupSalePackingListLineSoftwareInstanceAggregate
      AppendSetupSalePackingListLineSoftwareReleaseAggregate
      AppendSetupSalePackingListLineHostingSubscriptionAggregate
      ConfirmSetupSalePackingList
      SetStartDateOnSetupSalePackingList
      CreatePurchasePackingList
      CreatePurchasePackingListLine
      SetPurchasePackingListLineSoftwareResource
      SetPurchasePackingListLineAggregate
      ConfirmPurchasePackingList
      Tic
      CreateHostingSalePackingList
      CreateHostingSalePackingListLine
      SetHostingSalePackingListLineInstanceHostingResource
      AppendHostingSalePackingListLineComputerPartitionAggregate
      AppendHostingSalePackingListLineSoftwareInstanceAggregate
      AppendHostingSalePackingListLineSoftwareReleaseAggregate
      AppendHostingSalePackingListLineHostingSubscriptionAggregate
      ConfirmHostingSalePackingList
      SetStartDateOnHostingSalePackingList
      Tic
      PrepareTestingEnvironment
      RunSlapgrid
      AssertClientComputerPartitionIsRunning
      Tic
      RunSlapgrid
      AssertClientComputerPartitionIsRunning
      StopHostingSalePackingList
      Tic
      RunSlapgrid
      AssertClientComputerPartitionIsNotRunning
      CreateHostingSalePackingList
      CreateHostingSalePackingListLine
      SetHostingSalePackingListLineInstanceHostingResource
      AppendHostingSalePackingListLineComputerPartitionAggregate
      AppendHostingSalePackingListLineSoftwareInstanceAggregate
      AppendHostingSalePackingListLineSoftwareReleaseAggregate
      AppendHostingSalePackingListLineHostingSubscriptionAggregate
      ConfirmHostingSalePackingList
      SetStartDateOnHostingSalePackingList
      Tic
      RunSlapgrid
      AssertClientComputerPartitionIsRunning
      StopHostingSalePackingList
      Tic
      RunSlapgrid
      AssertClientComputerPartitionIsNotRunning
      CreateDestroySalePackingList
      CreateDestroySalePackingListLine
      SetDestroySalePackingListLineInstanceDestroyResource
      AppendDestroySalePackingListLineComputerPartitionAggregate
      AppendDestroySalePackingListLineSoftwareInstanceAggregate
      AppendDestroySalePackingListLineSoftwareReleaseAggregate
      AppendDestroySalePackingListLineHostingSubscriptionAggregate
      ConfirmDestroySalePackingList
      SetStartDateOnDestroySalePackingList
      Tic
      RunSlapgrid
      AssertComputerPartitionIsCleaned
      Tic
    """
    self.createTestSequenceAndPlay(sequence_string)

  def testManualDefaultSetup(self):
    """Manual default setup of slapgrid"""
    self.defineIds()
    self.software_instance_xml = """<instance>
  <parameter id="memcached_tcp_port">98076</parameter>
  <parameter id="memcached_udp_port">98076</parameter>
  <parameter id="memcached_host">127.0.0.1</parameter>
  <parameter id="memcached_memory_size">2</parameter>
</instance>"""
    sequence_string = """
      Tic
      CreateSoftwareAvailabilityService
      CreateInstanceSetupService
      CreateInstanceHostingService
      CreateInstanceDestroyService
      CreateSoftwareTemplateFile
      LoadSoftwareTemplateFile
      SetReferenceOnSoftwareTemplateFile
      PublishSoftwareTemplateFile
      CreateSoftwareReleaseFile
      SetReferenceOnSoftwareReleaseFile
      LoadSoftwareReleaseFile
      PublishSoftwareReleaseFile
      CreateSoftwareRelease
      SetSoftwareReleaseUri
      SetAggregateToSoftwareRelease
      PublishSoftwareRelease
      CreateComputer
      SetReferenceOnComputer
      ValidateComputer
      Tic
      CreateComputerPartition
      SetReferenceOnComputerPartition
      CreateInternetProtocolAddress
      Tic
      SetIpAndTcpPortAndUdpPortOnInternetProtocolAddress
      ValidateComputerPartition
      CreateHostingSubscription
      CreateSoftwareInstance
      SetReferenceOnSoftwareInstance
      SetSoftwareInstanceMemcachedXml
      CreateSetupSalePackingList
      CreateSetupSalePackingListLine
      SetSetupSalePackingListLineInstanceSetupResource
      AppendSetupSalePackingListLineComputerPartitionAggregate
      AppendSetupSalePackingListLineSoftwareInstanceAggregate
      AppendSetupSalePackingListLineSoftwareReleaseAggregate
      AppendSetupSalePackingListLineHostingSubscriptionAggregate
      Tic
      ConfirmSetupSalePackingList
      SetStartDateOnSetupSalePackingList
      CreatePurchasePackingList
      CreatePurchasePackingListLine
      SetPurchasePackingListLineSoftwareResource
      SetPurchasePackingListLineAggregate
      ConfirmPurchasePackingList
      Tic
      PrepareTestingEnvironment
      RunSlapgrid
      AssertClientSoftwareReleaseInstalled
      AssertClientComputerPartitionInstalled
      AssertClientGeneratedFileListPermissions
      AssertClientComputerPartitionIsNotRunning
      CreateHostingSalePackingList
      CreateHostingSalePackingListLine
      SetHostingSalePackingListLineInstanceHostingResource
      AppendHostingSalePackingListLineComputerPartitionAggregate
      AppendHostingSalePackingListLineSoftwareInstanceAggregate
      AppendHostingSalePackingListLineSoftwareReleaseAggregate
      AppendHostingSalePackingListLineHostingSubscriptionAggregate
      ConfirmHostingSalePackingList
      SetStartDateOnHostingSalePackingList
      Tic
      RunSlapgrid
      AssertClientComputerPartitionIsRunning
      AssertUsageReport
      AssertSoftwareInstanceExternalStateIsStarted
    """
    self.createTestSequenceAndPlay(sequence_string)

  def testSlapgridTrappedSoftwareRelease(self):
    """Create a Software Release buildout profile which fails when running.
       - create all needed objects in ERP5 (as done in the Luke's test),
       - when running slapgrid, check that the error was correctly
         reported in ERP5 (in the Supply).
    """
    self.defineIds()
    self.software_instance_xml = "<instance></instance>"
    sequence_string = """
      Tic
      CreateSoftwareAvailabilityService
      CreateInstanceSetupService
      CreateInstanceHostingService
      CreateInstanceDestroyService
      CreateSoftwareTemplateFile
      LoadSoftwareTemplateFile
      SetReferenceOnSoftwareTemplateFile
      PublishSoftwareTemplateFile
      CreateSoftwareReleaseFile
      SetReferenceOnSoftwareReleaseFile
      LoadTrappedSoftwareReleaseFile
      PublishSoftwareReleaseFile
      CreateSoftwareRelease
      SetSoftwareReleaseUri
      SetAggregateToSoftwareRelease
      PublishSoftwareRelease
      CreateComputer
      SetReferenceOnComputer
      ValidateComputer
      Tic
      CreateComputerPartition
      SetReferenceOnComputerPartition
      CreateInternetProtocolAddress
      Tic
      SetIpAndTcpPortAndUdpPortOnInternetProtocolAddress
      ValidateComputerPartition
      CreateHostingSubscription
      CreateSoftwareInstance
      SetReferenceOnSoftwareInstance
      SetSoftwareInstanceMemcachedXml
      CreateSetupSalePackingList
      CreateSetupSalePackingListLine
      SetSetupSalePackingListLineInstanceSetupResource
      AppendSetupSalePackingListLineComputerPartitionAggregate
      AppendSetupSalePackingListLineSoftwareInstanceAggregate
      AppendSetupSalePackingListLineSoftwareReleaseAggregate
      AppendSetupSalePackingListLineHostingSubscriptionAggregate
      ConfirmSetupSalePackingList
      SetStartDateOnSetupSalePackingList
      CreatePurchasePackingList
      CreatePurchasePackingListLine
      SetPurchasePackingListLineSoftwareResource
      SetPurchasePackingListLineAggregate
      ConfirmPurchasePackingList
      Tic
      CreateHostingSalePackingList
      CreateHostingSalePackingListLine
      SetHostingSalePackingListLineInstanceHostingResource
      AppendHostingSalePackingListLineComputerPartitionAggregate
      AppendHostingSalePackingListLineSoftwareInstanceAggregate
      AppendHostingSalePackingListLineSoftwareReleaseAggregate
      AppendHostingSalePackingListLineHostingSubscriptionAggregate
      ConfirmHostingSalePackingList
      SetStartDateOnHostingSalePackingList
      Tic
      PrepareTestingEnvironment
      RunSlapgridWithoutAssert
      Tic
      AssertSoftwareReleaseErrorReported
    """
    self.createTestSequenceAndPlay(sequence_string)

  def testSlapgridEmptySoftwareRelease(self):
    """Create a Software Release buildout profile which does nothing during
       installation. It's instanciation template should fails when running.
       - create all needed objects in ERP5 (as done in the Luke's test)
       - when running slapgrid, check that the error was correctly reported
         in ERP5 (in the Software Instance)
    """
    self.defineIds()
    self.software_instance_xml = "<instance></instance>"
    sequence_string = """
      Tic
      CreateSoftwareAvailabilityService
      CreateInstanceSetupService
      CreateInstanceHostingService
      CreateInstanceDestroyService
      CreateSoftwareTemplateFile
      LoadSoftwareTemplateFile
      SetReferenceOnSoftwareTemplateFile
      PublishSoftwareTemplateFile
      CreateSoftwareReleaseFile
      SetReferenceOnSoftwareReleaseFile
      LoadEmptySoftwareReleaseFile
      PublishSoftwareReleaseFile
      CreateSoftwareRelease
      SetSoftwareReleaseUri
      SetAggregateToSoftwareRelease
      PublishSoftwareRelease
      CreateComputer
      SetReferenceOnComputer
      ValidateComputer
      Tic
      CreateComputerPartition
      SetReferenceOnComputerPartition
      CreateInternetProtocolAddress
      Tic
      SetIpAndTcpPortAndUdpPortOnInternetProtocolAddress
      ValidateComputerPartition
      CreateHostingSubscription
      CreateSoftwareInstance
      SetReferenceOnSoftwareInstance
      SetSoftwareInstanceMemcachedXml
      CreateSetupSalePackingList
      CreateSetupSalePackingListLine
      SetSetupSalePackingListLineInstanceSetupResource
      AppendSetupSalePackingListLineComputerPartitionAggregate
      AppendSetupSalePackingListLineSoftwareInstanceAggregate
      AppendSetupSalePackingListLineSoftwareReleaseAggregate
      AppendSetupSalePackingListLineHostingSubscriptionAggregate
      ConfirmSetupSalePackingList
      SetStartDateOnSetupSalePackingList
      CreatePurchasePackingList
      CreatePurchasePackingListLine
      SetPurchasePackingListLineSoftwareResource
      SetPurchasePackingListLineAggregate
      ConfirmPurchasePackingList
      Tic
      CreateHostingSalePackingList
      CreateHostingSalePackingListLine
      SetHostingSalePackingListLineInstanceHostingResource
      AppendHostingSalePackingListLineComputerPartitionAggregate
      AppendHostingSalePackingListLineSoftwareInstanceAggregate
      AppendHostingSalePackingListLineSoftwareReleaseAggregate
      AppendHostingSalePackingListLineHostingSubscriptionAggregate
      ConfirmHostingSalePackingList
      SetStartDateOnHostingSalePackingList
      Tic
      PrepareTestingEnvironment
      RunSlapgridWithoutAssert
      Tic
      AssertSoftwareInstanceErrorReported
    """
    self.createTestSequenceAndPlay(sequence_string)