Difference between revisions of "Python SOAP - Document Injection Example"

From PeformIQ Upgrade
Jump to navigation Jump to search
Line 1: Line 1:
=Using Python [[ZSI]] to implement CDP Billing Test Harness=
=Using Python [[ZSI]] to implement SOAP Test Harness=


A Python script using the [[Zolera SOAP Infrastructure]] was implemented which allowed arbitrary combinations of orders to be generated.  This script was run from the command line with arguments specifying the required attributes of order set. It dynamically generated an order cluster with randomized data, injected this into the web tier and captured and parsed the return response into a log file along with various timings.
A Python script using the [[Zolera SOAP Infrastructure]] was implemented which allowed arbitrary combinations of orders to be generated.  This script was run from the command line with arguments specifying the required attributes of order set. It dynamically generated an order cluster with randomized data, injected this into the web tier and captured and parsed the return response into a log file along with various timings.
Line 30: Line 30:
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


from CDPBilling_serviceagent_services import *
from Submit_serviceagent_services import *


from ZSI import FaultException, Fault
from ZSI import FaultException, Fault
Line 70: Line 70:
log                = None
log                = None


ServiceURL        = "http://host:10000/Services/CDPBilling"  # Is retrieved from WSDL
ServiceURL        = "http://host:10000/Services/Submit"  # Is retrieved from WSDL


notification_email = 'peter.harding@auspost.com.au'
notification_email = 'peter.harding@auspost.com.au'

Revision as of 13:23, 11 July 2008

Using Python ZSI to implement SOAP Test Harness

A Python script using the Zolera SOAP Infrastructure was implemented which allowed arbitrary combinations of orders to be generated. This script was run from the command line with arguments specifying the required attributes of order set. It dynamically generated an order cluster with randomized data, injected this into the web tier and captured and parsed the return response into a log file along with various timings.

Follow these links to view the submit script (do.py) and component ZSI generated modules:

See Gathering TIBCO Queue Statistics for examples of Python scripts to scrape the TIBCO queue statistics fro inclusion in SVT logs.

do.py

The following WSDL was used to generate the Python scripts attached below:

The injection script (do.py) and required components (generated by wsdl2py) are attached here:

One of the gotchas was that I had to modify the ZSI site package to turn off the addition of the type explicitly to each element of the XML. When this was enabled - as by default setup - the injected XML was rejected by the TIBCO interface. Source for modified ZSI site-package is attached at:

#!/usr/bin/env python
#
#
#
#-------------------------------------------------------------------------------

from Submit_serviceagent_services import *

from ZSI import FaultException, Fault

import ZSI

import os
import re
import csv
import sys
import time
import getopt
import random
import socket
import pprint
import pickle
import traceback

import types
import pprint

import xml.dom.minidom

# from xml.dom.utils import FileReader
from string import join, split    
from datetime import datetime, timedelta
from time import strptime

#-------------------------------------------------------------------------------

__version__        = '1.2.0'

debug_flg          = False
verbose_flg        = False
sundry_flg         = False

no_sundries        = 0
cnt_requests       = 0
log                = None

ServiceURL         = "http://host:10000/Services/Submit"  # Is retrieved from WSDL

notification_email = 'peter.harding@auspost.com.au'

cdp_defaults       = {
                        'AAA'    : ['APCBE', 'AAANSW', 1,  'SVT-A-%06d', 0],
                        'MMM'    : ['APCBE', 'MMMVIC', 1,  'SVT-M-%06d', 0],
                        'XXX'    : ['XXXXX', 'XXXACT', 1,  'SVT-X-%06d', 0]
                     }

cdpId              = 'AAA'
cdp_details        = None
service_header     = None
no_orders          = 1

dt_order           = None
dt_request         = None

cdp_data_pickle    = "cdp.pickle"

add_performance    = True

#===============================================================================

class CDP:
   pass

   def __init__(self, cdpID):
      self.cdpID           = cdpID
      self.consortiumID    = cdp_details[cdpID][0]
      self.sourceSystemID  = cdp_details[cdpID][1]
      self.sequenceID      = cdp_details[cdpID][2]
      self.OrderNoFmt      = cdp_details[cdpID][3]
      self.OrderNo         = cdp_details[cdpID][4]
      self.customer        = []

   def get_order_number(self):
      order_number                = self.OrderNo
      self.OrderNo               += 1
      cdp_details[self.cdpID][4]  = self.OrderNo
      return order_number

#===============================================================================

class Customer:
   pass

   def __init__(self, m):
      self.apAccountNumber  = int(m[0])
      self.cdpAccountNumber = int(m[1])
      self.cdpCustomerID    = int(m[2])
      self.cdpCustomerName  = m[3]
      self.workCentreID     = int(m[4])
      self.order            = []

   def __str__(self):
      str = """
      apAccountNumber  = %d
      cdpAccountNumber = %d
      cdpCustomerID    = %d
      cdpCustomerName  = '%s'
      """ % (
               self.apAccountNumber,
               self.cdpAccountNumber,
               self.cdpCustomerID,
               self.cdpCustomerName
             )

      for o in self.order:
         str += """
      Order:\n"""
         str += o.__str__()

      return str

#===============================================================================

class Order:
   pass

   def __init__(self, cdp, customer):
      self.orderID             = cdp.OrderNoFmt % cdp.get_order_number()
      self.orderStatus         = None
      self.orderDateTime       = dt_order.timetuple()
      self.readyDateTime       = (dt_order + timedelta(days=1)).timetuple()
      self.invoiceDateTime     = (dt_order + timedelta(days=2)).timetuple()
      self.numberOfItems       = 1
      self.workCentreID        = customer.workCentreID
      self.CustomerReference   = None
      self.OrderReference      = None
      self.PickUpAddress       = None
      self.DeliveryAddress     = None
      self.Weight              = None
      self.Dimension           = None
      self.Performance         = None
      self.Service             = []

   def __str__(self):
      str = """
         orderID             = %s
         orderDateTime       = %s
         readyDateTime       = %s
         invoiceDateTime     = %s
         numberOfItems       = %d
         workCentreID        = %d
      """ % (
         self.orderID,
         self.orderDateTime,
         self.readyDateTime,
         self.invoiceDateTime,
         self.numberOfItems,
         self.workCentreID
      )
      return str


#===============================================================================

class CustomerReference:
   pass

   def __init__(self, cdp):
      self.customerCostCentre     = '%06d' % random.randint(100000,200000)
      self.otherCustomerRef       = '%s%05d' % (cdp.cdpID, random.randint(10000,99999))
      self.otherCustomerRefDesc   = 'Consignment Note Number'

   def __str__(self):
      return "CustomerReference"

#===============================================================================

class OrderReference:
   pass

   def __init__(self, m):
      self.orderRef1              = 'M%08d' % random.randint(10000000,99999999)
      self.orderRef1Desc          = 'Manifest Number'
      self.orderRef2              = 'R%05d' % random.randint(10000,99999)
      self.orderRef2Desc          = 'Run Number'
      self.orderRef3              = 'J%06d' % random.randint(100000,999999)
      self.orderRef3Desc          = 'Job Number'

   def __str__(self):
      return "OrderReference"

#===============================================================================

class Address:
   pass

   def __init__(self, m):
      # addr = get_address()
      self.address1    = m[0]
      self.address2    = m[1]
      self.address3    = m[2]
      self.address4    = m[3]
      self.suburb      = m[4]
      self.state       = m[5]
      self.postcode    = m[6]
      self.country     = m[7]

   def __str__(self):
      str = "       Address: %s," % self.address1,
      if self.address2:
         str += "%s, " % self.address2
      if self.address3:
         str += "%s, " % self.address3
      str += "%s, %s, %s" % (
         self.suburb,
         self.postcode,
	 self.state
      )
      return str

#===============================================================================

class Weight:
   pass

   def __init__(self, w):
      self.entryWeight  = w
      self.cubedWeight  = w
      self.actualWeight = w

   def __str__(self):
      return "Weight: %d" % (self.entryWeight)

#===============================================================================

class Dimension:
   pass

   def __init__(self, d):
      self.height          = d
      self.length          = d
      self.width           = d

   def __str__(self):
      return "Dimensions: %d x %d x %d" % (self.height, self.length, self.width)

#===============================================================================

class Performance:
   pass

   def __init__(self):
      t_pickup_sched    = dt_order + timedelta(hours=2)
      t_pickup_actual   = t_pickup_sched + timedelta(minutes=30)
      t_delivery_sched  = t_pickup_sched + timedelta(hours=1)
      t_delivery_actual = t_delivery_sched + timedelta(minutes=30)

      self.schedPickUpDateTime        = t_pickup_sched.timetuple()
      self.pickupSignatureRequired    = False
      self.pickupSignatureReceived    = False
      self.actualPickUpDateTime       = t_pickup_actual.timetuple()
      self.latePickUpIndicator        = False
      self.pickUpTimeliness           = -1
      self.schedDeliveryDateTime      = t_delivery_sched.timetuple()
      self.deliverySignatureRequired  = True
      self.deliverySignatureReceived  = True
      self.actualDeliveryDateTime     = t_delivery_actual.timetuple()
      self.lateDeliveryIndicator      = True
      self.deliveryTimeliness         = 7

   def __str__(self):
      return "Performance:"

#===============================================================================

class Service:
   pass

   # serviceCodeSet,serviceType,serviceArea,serviceCode,serviceDesc,apProductCode

   def __init__(self, m):
      self.serviceCodeSet    = m[0]
      self.serviceType       = m[1]
      self.serviceArea       = m[2]
      self.serviceCode       = m[3]
      self.serviceDesc       = m[4]
      self.apProductCode     = m[5]
      self.deliveryDistance  = None
      self.charge            = []

      if  self.apProductCode == '':
         self.apProductCode = None

   def __str__(self):
      return "%s,%s,%s" % (self.serviceType, self.serviceArea,self.serviceCodeSet)

#===============================================================================

class Charge:
   pass

   def __init__(self, cdp, m):
      self.transactionID       = '%s%06d' % (cdp.cdpID[0:1], random.randint(100000,999999))
      self.transactionType     = m[0]
      self.chargeType          = m[1]
      self.chargeCode          = m[2]
      self.chargeCodeDesc      = m[3]
      self.priceCharged        = float(m[4])
      self.taxCode             = m[5]

   def __str__(self):
      return "%s,%s,%s,%s" % (
         self.chargeType,
         self.chargeCode,
         self.chargeCodeDesc,
         self.priceCharged
      )

#===============================================================================
#----- Read in Account address info ---------------------------------------

class Addresses:
   pass

   #-------------------------------------------------------------

   def __init__(self, carrier):
      self.addresses = []

      file = 'dat/%s/Address.csv' % carrier.cdpID

      f_in  = open(file, "r")

      reader = csv.reader(f_in)

      for row in reader:
         if re.search('#', row[0]):
            continue
         self.addresses.append(Address(row))

      f_in.close()  # Explicitly close the file *NOW*

      self.no_addresses = len(self.addresses)

      if debug_flg: print "Read in %d addresses" % self.no_addresses

   #-------------------------------------------------------------

   def Get(self):
      idx = random.randint(0, self.no_addresses - 1)

      return self.addresses[idx]

   #-------------------------------------------------------------

   def GetPair(self):
      idx1 = random.randint(0, self.no_addresses - 1)

      while True:
         idx2 = random.randint(0, self.no_addresses - 1)
         if idx1 != idx2:
            break

      return (self.addresses[idx1], self.addresses[idx2])

#===============================================================================

class Charges:
   pass

   #-------------------------------------------------------------

   def __init__(self, carrier):
      self.values = []

      file = 'dat/%s/Charge.csv' % carrier.cdpID

      f_in  = open(file, "r")

      reader = csv.reader(f_in)

      for row in reader:
         if re.search('#', row[0]):
            continue
         self.values.append(Charge(carrier, row))

      f_in.close()  # Explicitly close the file *NOW*

      self.no_values = len(self.values)

      if debug_flg: print "Read in %d charges" % self.no_values

   #-------------------------------------------------------------

   def Get(self):
      idx = random.randint(0, self.no_values - 1)

      return self.values[idx]

#===============================================================================

class Charges_Sundry:
   pass

   #-------------------------------------------------------------

   def __init__(self, carrier):
      self.values = []

      file = 'dat/%s/Charge_Sundry.csv' % carrier.cdpID

      f_in  = open(file, "r")

      reader = csv.reader(f_in)

      for row in reader:
         if re.search('#', row[0]):
            continue
         sundry = Charge(carrier, row)
         print sundry
         self.values.append(sundry)

      f_in.close()  # Explicitly close the file *NOW*

      self.no_values = len(self.values)

      print "Read in %d sundry charges" % self.no_values
      if debug_flg: print "Read in %d sundry charges" % self.no_values

   #-------------------------------------------------------------

   def Get(self):
      idx = random.randint(0, self.no_values - 1)

      return self.values[idx]

#===============================================================================

class Customers:
   pass

   #-------------------------------------------------------------

   def __init__(self, carrier):
      self.values = []

      file = 'dat/%s/Customer.csv' % carrier.cdpID

      f_in  = open(file, "r")

      reader = csv.reader(f_in)

      for row in reader:
         if re.search('#', row[0]):
            continue
         self.values.append(Customer(row))

      f_in.close()  # Explicitly close the file *NOW*

      self.no_values = len(self.values)

      if debug_flg: print "Read in %d Customers" % self.no_values

   #-------------------------------------------------------------

   def Get(self):
      idx = random.randint(0, self.no_values - 1)

      return self.values[idx]

#===============================================================================

class Services:
   pass

   #-------------------------------------------------------------

   def __init__(self, carrier):
      self.values = []

      file = 'dat/%s/Service.csv' % carrier.cdpID

      if debug_flg: print "Using -- %s" % file

      f_in  = open(file, "r")

      reader = csv.reader(f_in)

      for row in reader:
         if re.search('#', row[0]):
            continue
         s = Service(row)
         # print s
         self.values.append(s)

      f_in.close()  # Explicitly close the file *NOW*

      self.no_values = len(self.values)

      if debug_flg: print "Read in %d services" % self.no_values

   #-------------------------------------------------------------

   def Get(self):
      idx = random.randint(0, self.no_values - 1)

      self.values[idx].charge = []

      return self.values[idx]

#===============================================================================

#-------------------------------------------------------------------------------

def load_cdp_data():
   global cdp_details

   try:
      pf = open(cdp_data_pickle, "r")
   except IOError, msg:
      sys.stderr.write('%s: cannot open: %s\n' % (cdp_data_pickle, msg))
      cdp_details = cdp_defaults
      return

   u  = pickle.Unpickler(pf)

   cdp_details = u.load()

   pf.close()

   return

#-------------------------------------------------------------------------------

def save_cdp_data():

   try:
      pf = open(cdp_data_pickle, 'w')
   except IOError, msg:
      sys.stderr.write('%s: cannot open: %s\n' % (cdp_data_pickle, msg))
      sys.exit(1)

   p = pickle.Pickler(pf)

   p.dump(cdp_details)

   pf.close()

#-------------------------------------------------------------------------------

def generate_orders(cdp, no_orders=1, debug=None):
   #----- Create data constructors ---------------------------------------------

   customers        = Customers(cdp)
   addresses        = Addresses(cdp)
   charges          = Charges(cdp)
   services         = Services(cdp)

   if sundry_flg:
      sundry_charges = Charges_Sundry(cdp)

   customer_list = []
  
   customer         = customers.Get()

   customer_list.append(customer)

   for order_idx in range(no_orders):
      order     = Order(cdp, customer)

      customer.order.append(order)

      order.CustomerReference = CustomerReference(cdp)

      (order.PickUpAddress, order.DeliveryAddress) = addresses.GetPair()

      order.Weight         = Weight(random.randint(100,3000))
      order.Dimension      = Dimension(random.randint(10,99))
      order.Service        = services.Get()

      if add_performance:
         order.Performance = Performance()

      order.Service.charge.append(charges.Get())

      if sundry_flg:
         for i in range(no_sundries):
            order.Service.charge.append(sundry_charges.Get())

      print "Len Charges - %d" % len(order.Service.charge)

   print customer

   return customer_list

#----- Construct the Service Header --------------------------------------------

def create_header(debug=None):

   reqInfo = ns1.RequestorInfo_Def('RequestorInfo').pyclass()

   reqInfo._ComponentID            = 'Test'
   reqInfo._ComponentName          = 'Test Application'

   service_header = ESBSvcHeader()

   #service_header._SvcName         = 'receiveCDPBilling'
   service_header._SvcName         = 'CDPBilling-receiveBilling'
   service_header._SvcVersion      = '1.0'
   service_header._RequestDt       = dt_request.timetuple()
   service_header._RequestorInfo   = reqInfo

   if (debug): print service_header.__dict__

#-------------------------------------------------------------------------------

def create_request(cdp, customers, debug=None):
   global dt_request
   global service_header

   dt_request = datetime.now()

   log.write("============================================================")
   log.write("%s INFO Start new request" % dt_request.strftime("%Y-%m-%d %H:%M:%S"))


   request = None

   #----- Construct the Service Header -----------------------------------------

   reqInfo = ns1.RequestorInfo_Def('RequestorInfo').pyclass()

   reqInfo._ComponentID            = 'Test'
   reqInfo._ComponentName          = 'Test Application'

   service_header = ESBSvcHeader()

   #service_header._SvcName         = 'receiveCDPBilling'
   service_header._SvcName         = 'CDPBilling-receiveBilling'
   service_header._SvcVersion      = '1.0'
   service_header._RequestDt       = dt_request.timetuple()
   service_header._RequestorInfo   = reqInfo

   if (debug): print service_header.__dict__

   #----- Create the order request ---------------------------------------------

   request = ReceiveCDPBilling()

   request._cdpID              = cdp.cdpID
   request._consortiumID       = cdp.consortiumID
   request._sourceSystemID     = cdp.sourceSystemID
   request._sequenceID         = cdp.sequenceID
   request._notificationEmail  = notification_email
   request._Customer           = []

   # print request
   # print request.__dict__

   for cust in customers:
      customer = ns0.Customer_Def('Customer').pyclass()

      request._Customer.append(customer)

      customer._apAccountNumber  = cust.apAccountNumber
      customer._cdpAccountNumber = cust.cdpAccountNumber
      customer._cdpCustomerID    = cust.cdpCustomerID
      customer._cdpCustomerName  = cust.cdpCustomerName
      customer._Order            = []

      # print customer
      # print customer.__dict__

      for ord in cust.order:
         order = ns0.Order_Def('Order').pyclass()

         order._orderID             = ord.orderID
         order._orderStatus         = ord.orderStatus
         order._orderDateTime       = ord.orderDateTime
         order._readyDateTime       = ord.readyDateTime
         order._invoiceDateTime     = ord.invoiceDateTime
         order._numberOfItems       = ord.numberOfItems
         order._workCentreID        = ord.workCentreID
         order._CustomerReference   = None
         order._OrderReference      = None
         order._PickUpAddress       = None
         order._DeliveryAddress     = None
         order._Weight              = None
         order._Dimension           = None
         order._Performance         = None
         order._Service             = []

         print "Constructing order number %s" % order._orderID

         customer._Order.append(order)

         customerReference = ns0.CustomerReference_Def('CustomerReference').pyclass()

         cust_ref = ord.CustomerReference

         customerReference._customerCostCentre     = cust_ref.customerCostCentre
	 customerReference._otherCustomerRef       = cust_ref.otherCustomerRef
         customerReference._otherCustomerRefDesc   = cust_ref.otherCustomerRefDesc

         order._CustomerReference   = customerReference

         pickUpAddress = ns0.Address_Def('Address').pyclass()

         pickUpAddress._address1    = ord.PickUpAddress.address1[:34]
         pickUpAddress._address2    = ord.PickUpAddress.address2[:34]
         pickUpAddress._address3    = ord.PickUpAddress.address3[:34]
         pickUpAddress._suburb      = ord.PickUpAddress.suburb
         pickUpAddress._postcode    = ord.PickUpAddress.postcode
         pickUpAddress._state       = ord.PickUpAddress.state
         pickUpAddress._country     = ord.PickUpAddress.country

         order._PickUpAddress       = pickUpAddress

         deliveryAddress = ns0.Address_Def('Address').pyclass()

         deliveryAddress._address1  = ord.DeliveryAddress.address1[:34]
         deliveryAddress._address2  = ord.DeliveryAddress.address2[:34]
         deliveryAddress._address3  = ord.DeliveryAddress.address3[:34]
         deliveryAddress._suburb    = ord.DeliveryAddress.suburb
         deliveryAddress._postcode  = ord.DeliveryAddress.postcode
         deliveryAddress._state     = ord.DeliveryAddress.state
         deliveryAddress._country   = ord.DeliveryAddress.country

         order._DeliveryAddress     = deliveryAddress

         weight = ns0.Weight_Def('Weight').pyclass()

         weight._entryWeight        = ord.Weight.entryWeight
         weight._cubedWeight        = ord.Weight.cubedWeight
         weight._actualWeight       = ord.Weight.actualWeight

         order._Weight              = weight

         dimension = ns0.Dimension_Def('Dimension').pyclass()
 
         dimension._height          = ord.Dimension.height
         dimension._length          = ord.Dimension.length
         dimension._width           = ord.Dimension.width

         order._Dimension           = dimension

         if ord.Performance:
            performance = ns0.Performance_Def('Performance').pyclass()

            performance._schedPickUpDateTime        = ord.Performance.schedPickUpDateTime
            performance._pickupSignatureRequired    = ord.Performance.pickupSignatureRequired
            performance._pickupSignatureReceived    = ord.Performance.pickupSignatureReceived
            performance._actualPickUpDateTime       = ord.Performance.actualPickUpDateTime
            performance._latePickUpIndicator        = ord.Performance.latePickUpIndicator
            performance._pickUpTimeliness           = ord.Performance.pickUpTimeliness
            performance._schedDeliveryDateTime      = ord.Performance.schedDeliveryDateTime
            performance._deliverySignatureRequired  = ord.Performance.deliverySignatureRequired
            performance._deliverySignatureReceived  = ord.Performance.deliverySignatureReceived
            performance._actualDeliveryDateTime     = ord.Performance.actualDeliveryDateTime
            performance._lateDeliveryIndicator      = ord.Performance.lateDeliveryIndicator
            performance._deliveryTimeliness         = ord.Performance.deliveryTimeliness

            order._Performance                      = performance

         service = ns0.Service_Def('Service').pyclass()

         service._serviceType       = ord.Service.serviceType
         service._serviceArea       = ord.Service.serviceArea
         service._serviceCodeSet    = ord.Service.serviceCodeSet
         service._serviceCode       = ord.Service.serviceCode
         service._serviceDesc       = ord.Service.serviceDesc
         service._apProductCode     = ord.Service.apProductCode
         service._deliveryDistance  = None
         service._Charge            = []

         order._Service.append(service)

         for ord_charge in ord.Service.charge:
            # ord_charge = ord.Service.charge[0]

            charge = ns0.Charge_Def('Charge').pyclass()

            charge._transactionID       = ord_charge.transactionID
            charge._transactionType     = ord_charge.transactionType
            charge._chargeType          = ord_charge.chargeType
            charge._chargeCode          = ord_charge.chargeCode
            charge._chargeCodeDesc      = ord_charge.chargeCodeDesc
            charge._priceCharged        = ord_charge.priceCharged
            charge._taxCode             = ord_charge.taxCode

            service._Charge.append(charge)

   assert isinstance(request, ReceiveCDPBilling), "ERROR: Need ReceiveCDPBilling pyclass instance"

   return request

#-------------------------------------------------------------------------------

def send(request):
   response = None

   locator     = CDPBilling_serviceagentLocator()

   service_url = locator.getCDPBillingAddress()

   log.write('End Point (Servie URL) -> "%s"' % service_url)

   kw = {'url' : service_url}

   if log:
      kw['tracefile'] =  log

   port_type = locator.getCDPBilling(**kw)

   # service_header = GED(u'http://www.auspost.com.au/ESB/schema/ESBTypes', u'ESBSvcHeader').pyclass()
   # service_header.SvcName = 'receiveCDPBilling'

   try:
      response = port_type.receiveCDPBilling(request, soapheaders=[service_header],)

   except (Fault, FaultException), msg:
      dt_end        = datetime.now()

      print "msg -> {{%s}}" % str(msg)
      print "response -> ", response

      # print response._ESBSvcHeader
      # print response._ESBException

      # faultText     = (msg.fault[0].string or '<no fault text available>')
      # faultDetail   = "SOAP response: \n" + msg.fault[1].strip("\n")

      faultText   = 'N/A'
      faultDetail = 'N/A'

      log.write("Fault (for %s): %s" % (request._Customer[0]._cdpCustomerID, faultText))
      log.write("%s ERROR Fault Exception: Details: %s, elapsed: %s, %s, %s" % \
         (datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
          faultText, str(dt_end - dt_request),
          traceback.format_tb(sys.exc_info()[2],1),
          faultDetail))

   except socket.error, msg:
      log.write("Fault - socket error (for %s): %s" % (request._BusinessRefID, msg))
      log.write("%s ERROR Socket Error Exception. Details: %s %s" % \
         (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 
         msg,
         traceback.format_tb(sys.exc_info()[2],1)))

   #----- Order successfully processed -------------------------------

   else:                
      dt_end       = datetime.now()
      log.write("OK  (for Customer %s - %s)" % (request._Customer[0]._cdpCustomerID,
                                                request._Customer[0]._cdpCustomerName))

   return response

#-------------------------------------------------------------------------------

def analyse(logfile):
   cnt = 0

   lfd     = open(logfile, 'r')

   for line in lfd.readlines():
      if cnt == 11:
         response_xml = line[:-1]
         # print "[[%s]]" % response_xml
      # print "Cnt -> %d" % cnt
      cnt += 1

   lfd.close()

   ofd = open('response.xml', 'w')

   ofd.write(response_xml)
   ofd.close()

   return response_xml

#-------------------------------------------------------------------------------

def examine(efd):
   resp_xml = analyse('send.log')

   
   dom_obj  = xml.dom.minidom.parse('response.xml')

   pp       = pprint.PrettyPrinter(indent=3)

   # print "===== dom_obj.__dict__ =========================================\n"
   # pp.pprint(dom_obj.__dict__)
   # print "\n"
   
   envelope = dom_obj.childNodes[0]

   # print "===== dom_obj.childNodes: ======================================\n"
   # pp.pprint(envelope.__dict__)
   # print "\n"

   soap_header = envelope.childNodes[0]
   # pp.pprint(soap_header.__dict__)
   # print "\n"

   svc_header = soap_header.childNodes[0]
   #pp.pprint(svc_header.__dict__)
   #print "\n"

   request_dt = svc_header.childNodes[2]
   # print "request_dt.__dict__"
   # pp.pprint(request_dt.__dict__)
   # print "\n"

   req_date = request_dt.childNodes[0].nodeValue
   t  = split(req_date, '.')
   msec = t[1].replace('Z','')
   dt = datetime(*(strptime(t[0], "%Y-%m-%dT%H:%M:%S")[0:6]))
   dt = dt.replace(microsecond=int(msec) * 1000)

   tracking = svc_header.childNodes[4]
   # print "tracking.__dict__"
   # pp.pprint(tracking.__dict__)
   # print "\n"

   status_node = tracking.childNodes[1]
   # print "status.__dict__"
   # pp.pprint(status.__dict__)
   # print "\n"
   status = status_node.childNodes[0].nodeValue

   tracking_events = tracking.childNodes[3]
   # print "tracking_events.__dict__"
   # pp.pprint(tracking_events.__dict__)
   # print "\n"

   events1 = tracking_events.childNodes[0]
   # print "events1.__dict__"
   # pp.pprint(events1.__dict__)
   # print "\n"

   e1_dt_node = events1.childNodes[1]
   # pp.pprint(e1_dt_node.__dict__)
   # print "\n"
   e1_dt = e1_dt_node.childNodes[0].nodeValue
   t  = split(e1_dt, '.')
   msec = t[1].replace('+10:00','')
   e1_dt = datetime(*(strptime(t[0], "%Y-%m-%dT%H:%M:%S")[0:6]))
   dt_end = e1_dt.replace(microsecond=int(msec) * 1000)

   e1_desc_node = events1.childNodes[2]
   e1_desc = e1_desc_node.childNodes[0].nodeValue
   # print e1_desc
   m = re.search("ocessed is ([0-9]*),", e1_desc)
   if m:
      no_orders = int(m.group(1))
   else:
      no_orders = 0

   events2 = tracking_events.childNodes[1]
   # pp.pprint(events2.__dict__)
   # print "\n"

   e2_node = events2.childNodes[1]
   # pp.pprint(e2_node.__dict__)
   # print "\n"
   e2_dt = e2_node.childNodes[0].nodeValue
   t  = split(e2_dt, '.')
   msec = t[1].replace('+10:00','')
   e2_dt = datetime(*(strptime(t[0], "%Y-%m-%dT%H:%M:%S")[0:6]))
   dt_start = e2_dt.replace(microsecond=int(msec) * 1000)

   e2_desc_node = events2.childNodes[2]
   e2_desc = e2_desc_node.childNodes[0].nodeValue
   #print "    frontend processing desc:  %s" % e2_desc

   t_delta    = dt_end - dt_start
   t_microsec = 0.0 + (t_delta.days * 86400) + t_delta.seconds + (t_delta.microseconds/1000000.0)

   efd.write("                Request date:  %s\n" % req_date)
   efd.write("                    Received:  %d orders\n" % no_orders)
   efd.write("                      Status:  %s\n\n" % status)
   efd.write("Start frontend processing DT:  %s\n" % dt_start)
   efd.write("  End frontend processing DT:  %s\n" % dt_end)
   efd.write("     Average processing time:  %.03f seconds\n" % (t_microsec/no_orders))
   efd.write("    %4d orders processed in:  %.03f seconds\n" % (no_orders, t_microsec))

   efd.close()

   # PLH

   # body = envelope.childNodes[1]
   # pp.pprint(body)
   # pp.pprint(body.__dict__)
   # print "\n"

   # billing_response = body.childNodes[0]
   # pp.pprint(billing_response)
   # pp.pprint(billing_response.__dict__)
   # print "\n"


#-------------------------------------------------------------------------------

def generate(cdpId, no_orders):
   global log
   global dt_order
   global cdp_details
   global add_performance

   dt_order = datetime.now() - timedelta(days=3)
   dt_stamp = datetime.now().strftime('%Y%m%d%H%M%S')

   print "Timestamp [%s]" % dt_stamp
   print "Posting order at %s" % dt_order
   print "timetuple %s" % dt_order.timetuple()

   load_cdp_data()

   if (cdpId == 'MMM'):
      add_performance = True

   logfile = "log/ReceiveCDPBilling__%s.log" % dt_stamp

   log     = open(logfile, 'w+')

   cdp     = CDP(cdpId)

   customer_orders = generate_orders(cdp, no_orders=no_orders)

   request  = create_request(cdp, customer_orders)

   response = send(request)

   save_cdp_data()

   log.close()

   os.system('rm send.log');
   os.system('ln -s %s send.log' % logfile);

   if (response == 'success'):
      exlog = "log/examine__%s.log" % dt_stamp
      efd = open(exlog, 'w')
      examine(efd)
      efd.close()
      os.system('rm examine.log')
      os.system('ln -s %s examine.log' % exlog)
      os.system('cat examine.log')

#-------------------------------------------------------------------------------

def usage():
   USAGE = """
   
     Usage:
     
       $ dt.py
    
   """
   
   sys.stderr.write(USAGE)
   
#-------------------------------------------------------------------------------

def main(argv):
   global debug_flg, verbose_flg, sundry_flg, cdpId, no_orders, no_sundries

   loop_cnt    = 1
   examine_flg = False

   #----- Process command line arguments ----------------------------

   try:
      opts, args = getopt.getopt(argv, "c:dehl:n:sS:v",
              ["cdp", "debug", "examine", "help", "loop", "no=", "sundry", "sundries", "verbose"])
   except getopt.GetoptError:
      usage()
      sys.exit(2)
   else:
      for opt, arg in opts:
         if opt in ("-h", "--help"):
            usage()
            sys.exit(0)
         elif opt in ("-c", "--cdp"):
            cdpId = arg
         elif opt in ("-e", "--examine"):
            examine_flg = True
         elif opt in ("-l", "--loop"):
            loop_cnt = int(arg)
         elif opt in ("-n", "--no"):
            no_orders = int(arg)
         elif opt in ("-s", "--sundry"):
            sundry_flg  = True
            no_sundries = 1
         elif opt in ("-S", "--sundries"):
            sundry_flg  = True
            no_sundries = int(arg)
         elif opt in ("-v", "--verbose"):
            verbose_flg = True

   if not cdp_defaults.has_key(cdpId):
      print 'Bad CDP ID "%s"' % cdpId
      sys.exit(1)

   if examine_flg:
      examine(sys.stdout)
   else:
      for idx in range(loop_cnt):
         generate(cdpId, no_orders)
         if idx < loop_cnt - 1:
            time.sleep(30)


#---------------------------------------------------------------------

if __name__ == "__main__":
   main(sys.argv[1:])


#---------------------------------------------------------------------

"""

ESBSOAPException:
                def __init__(self):
                    # pyclass
                    self._ESBSvcHeader = None
                    self._ESBException = None
                    return

ESBSvcHeader
                def __init__(self):
                    # pyclass
                    self._SvcName = None
                    self._SvcVersion = None
                    self._RequestDt = None
                    self._RequestorInfo = None
                    self._Tracking = None
                    return

ESBException:
                def __init__(self):
                    # pyclass
                    self._ExceptionCategory = None
                    self._ExceptionType = None
                    self._ExceptionCode = None
                    self._ExceptionDescription = None
                    self._ExceptionOtherData = None
                    self._ESBAlert = None
                    return


"""

Example of Usage

Generate a 10 order cluster from MMM CDP

$ ./do.py -c MMM -n 10
Timestamp [20070914150827]
Posting order at 2007-09-11 15:08:27.906250
timetuple (2007, 9, 11, 15, 8, 27, 1, 254, -1)

      apAccountNumber  = 9999999
      cdpAccountNumber = 2222222
      cdpCustomerID    = 3333333
      cdpCustomerName  = 'IST Test customer'
      
      Order:

         orderID             = SVT-M-001510
         orderDateTime       = (2007, 9, 11, 15, 8, 27, 1, 254, -1)
         readyDateTime       = (2007, 9, 12, 15, 8, 27, 2, 255, -1)
         invoiceDateTime     = (2007, 9, 13, 15, 8, 27, 3, 256, -1)
         numberOfItems       = 1
         workCentreID        = 275784
      
      ...
      
      Order:

         orderID             = SVT-M-001518
         orderDateTime       = (2007, 9, 11, 15, 8, 27, 1, 254, -1)
         readyDateTime       = (2007, 9, 12, 15, 8, 27, 2, 255, -1)
         invoiceDateTime     = (2007, 9, 13, 15, 8, 27, 3, 256, -1)
         numberOfItems       = 1
         workCentreID        = 275784
      
      Order:

         orderID             = SVT-M-001519
         orderDateTime       = (2007, 9, 11, 15, 8, 27, 1, 254, -1)
         readyDateTime       = (2007, 9, 12, 15, 8, 27, 2, 255, -1)
         invoiceDateTime     = (2007, 9, 13, 15, 8, 27, 3, 256, -1)
         numberOfItems       = 1
         workCentreID        = 275784
      
Constructing order number SVT-M-001510
Constructing order number SVT-M-001511
Constructing order number SVT-M-001512
Constructing order number SVT-M-001513
Constructing order number SVT-M-001514
Constructing order number SVT-M-001515
Constructing order number SVT-M-001516
Constructing order number SVT-M-001517
Constructing order number SVT-M-001518
Constructing order number SVT-M-001519

                Request date:  2007-09-14T15:08:28.004Z
                    Received:  10 orders
                      Status:  FinishedOK

Start frontend processing DT:  2007-09-14 15:01:27.917000
  End frontend processing DT:  2007-09-14 15:01:30.062000
     Average processing time:  0.214 seconds
      10 orders processed in:  2.145 seconds