Subversion Repositories DevTools

Rev

Rev 2218 | Blame | Compare with Previous | Last modification | View Log | RSS feed

//---------------------------------------------------------------------------

#pragma warn -com
#include <LoggingMacros.h>
#pragma warn +com

#include <vcl.h>
#pragma hdrstop

#include "stdio.h"
#include "io.h"
#include "dir.h"
#include "RunTests.h"
#include "Utilities.h"

#define MASSUDWriter    "MASSUDWriter"

#define ADV_PROGRESS_BAR
//#define STORE_IN_DATABASE
#define STORE_PAYLOAD
#define INITIALISETXNSTRUCTURE

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "Grids_ts"
#pragma link "TSDBGrid"
#pragma link "TSGrid"
#pragma link "AdvProgressBar"
#pragma resource "*.dfm"
TRunTestsForm *RunTestsForm;


//---------------------------------------------------------------------------
/**
 *      Process paint message.
 */
void ProcessPaintMessages( HWND Handle )
{
        MSG msg;
        while ( PeekMessage( &msg, Handle, WM_PAINT, WM_PAINT, PM_REMOVE ) )
        {
                DispatchMessage( &msg );
        }
}


//---------------------------------------------------------------------------
__fastcall TRunTestsForm::TRunTestsForm(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

/**
 *      Get the collection of schemas and find our schema in that collection.
 */

const bool TRunTestsForm::findSchema( vector< AnsiString > &    xmlSchemas,
                                                                          TXMLSchema &                          schema,
                                                                          const AnsiString &            currentProject,
                                                                          const int &                           currentIteration )
{
        vector< string > schemas;
        if ( schema.GetSchemas( schemas ) )
        {
                AnsiString theSchema;
                for ( vector< string >::iterator what = schemas.begin();
                          what != schemas.end();
                          ++what )
                {
                        theSchema = what->c_str();

                        if ( theSchema.Pos( MASSUDWriter ) == 1 )
                        {
                                xmlSchemas.push_back( theSchema );
                        }
                }
        }

        string handle;
        for ( vector< AnsiString >::iterator where = xmlSchemas.begin();
                  where != xmlSchemas.end();
                  ++where )
        {
                handle = where->c_str();

                vector< string >        schema_structures;
                string                          project;
                string                          majorversion;

                schema.GetAttributeProperty( handle, "project", project );

                if ( currentProject.UpperCase() == AnsiString( project.c_str() ).UpperCase() )
                {
                        schema.GetAttributeProperty( handle, "majorversion", majorversion );

                        if ( currentIteration == atoi( majorversion.c_str() ) )
                        {
                                return ( true );
                        }
                }
        }

        return ( false );
}


//---------------------------------------------------------------------------
/**
 *      Build the transaction map for faster lookup.
 */

void TRunTestsForm::buildTranactionMap( TXNIndexMap &           transactions,
                                                                                const AnsiString &      currentProject,
                                                                                const int &                     currentIteration )
{
        TADOQuery *     query = 0;
        try
        {
                query = new TADOQuery( this );
                query->Connection = Data_Module->IntegrationDBConnection;

                AnsiString sql_statement;
                sql_statement.sprintf(
                        "SELECT "
                                "NAME, "
                                "UDTYPE, "
                                "UDSUBTYPE "
                        "FROM "
                                "MASS_TXNS "
                        "WHERE "
                                "PROJECTCODE=\'%s\' AND "
                                "ITERATION=%d ",
                        currentProject.c_str(),
                        currentIteration );

                query->SQL->Text = sql_statement;
                query->Open();

                unsigned short  udtype          = 0;
                unsigned short  udsubtype       = 0;
                unsigned int    udindex         = 0;
                while ( !query->Eof )
                {
                        udtype          = query->FieldByName( "UDTYPE" )->AsInteger;
                        udsubtype       = query->FieldByName( "UDSUBTYPE" )->AsInteger;
                        udindex         = ( udtype << 16 ) + udsubtype;

                        transactions.insert( TXNIndexPair(
                                udindex,
                                query->FieldByName( "NAME" )->AsString ) );

                        query->Next();
                }
        }
        __finally
        {
                delete query;
                query = 0;
        }
}


//---------------------------------------------------------------------------
/**
 *      Substitute any macros with the appropriate value.
 */
AnsiString & TRunTestsForm::substituteMacro( AnsiString & value, const unsigned short & udType )
{
        if ( value == "@ACCOUNTTYPE" )
        {
                int     accountFormat = 0;
                switch ( udType )
                {
                case 1: // Card
                        accountFormat = 2;
                        break;
                case 2: // Application
                        accountFormat = 1;
                        break;
                case 3: // Product
                        accountFormat = 3;
                        break;
                case 4: // Other
                        accountFormat = 4;
                        break;
                case 5: // Audit
                        accountFormat = 4;
                        break;
                case 6: // Event
                        accountFormat = 4;
                        break;
                case 7: // Project
                        accountFormat = 4;
                        break;
                } // switch

                value.sprintf( "%d", accountFormat );
        }
        return ( value );
}


//---------------------------------------------------------------------------
/**
 *      Evaluate to true when the given value is a macro, and to false otherwise.
 */
const bool TRunTestsForm::isMacro( const string & value )
{
        return ( value == "@ACCOUNTTYPE" );
}


//---------------------------------------------------------------------------
/**
 *      Build the header that we use as the basis for prefixing each transaction
 *      when prefixing is required.
 */

void TRunTestsForm::buildHeader( string &                                                       handle,
                                                                 TXMLSchema &                                           schema,
                                                                 vector< pair< string, string > > &     macros,
                                                                 const AnsiString &                                     currentProject,
                                                                 const int &                                            currentIteration )
{
        const char * headerStructure = "SysHdr_t";

        TADOQuery *     query = 0;
        try
        {
                try
                {
                        if ( schema.Create( headerStructure, currentIteration, handle, 0 ) )
                        {
                                query = new TADOQuery( this );
                                query->Connection = Data_Module->IntegrationDBConnection;

                                AnsiString sqlStatement;
                                sqlStatement.sprintf(
                                        "SELECT "
                                                "* "
                                        "FROM "
                                                "TXNHDR_VALUES "
                                        "WHERE "
                                                "PROJECT_CODE=\'%s\' AND "
                                                "ITERATION=%d ",
                                        currentProject.c_str(),
                                        currentIteration );

                                query->SQL->Text = sqlStatement;
                                query->Open();

                                string fieldName;
                                string fieldValue;
                                string attributePath;
                                string valuemap;

                                while ( !query->Eof )
                                {
                                        fieldName       = query->FieldByName( "FIELDNAME" )->AsString.c_str();
                                        fieldValue      = query->FieldByName( "FIELDVALUE" )->AsString.c_str();

                                        if ( !isMacro( fieldValue ) )
                                        {
                                                attributePath = handle + "." + fieldName;
                                                m_XMLSchema->GetAttributeProperty( attributePath, "valuemap", valuemap );

                                                if ( valuemap.empty() )
                                                {
//                                                      string fieldDatatype;
//                                                      schema.GetAttributeProperty( attributePath, "datatype", fieldDatatype );

                                                        if ( fieldValue[ 0 ] == '-' )
                                                        {
                                                                schema.SetAttributeValue( handle, fieldName.c_str(), atoi( fieldValue.c_str() ) );
                                                        }
                                                        else
                                                        {
                                                                schema.SetAttributeValue( handle, fieldName.c_str(), fieldValue.c_str());
                                                        }
                                                }
                                                else
                                                {
                                                        if ( ( fieldValue[ 0 ] >= '0' && fieldValue[ 0 ] <= '9' ) ||
                                                                 ( fieldValue[ 0 ] == '-' && fieldValue[ 1 ] >= '0' && fieldValue[ 1 ] <= '9' ) )
                                                        {
                                                                schema.SetAttributeValue( handle, fieldName.c_str(), atoi( fieldValue.c_str() ) );
                                                        }
                                                        else
                                                        {
                                                                schema.SetAttributeValue( handle, fieldName.c_str(), fieldValue.c_str());
                                                        }
                                                }
                                        }
                                        else
                                        {
                                                macros.push_back( std::pair< std::string, std::string >(
                                                        fieldName,
                                                        fieldValue ) );
                                        }

                                        query->Next();
                                }

                                query->Close();
                        }
                        else
                        {
                                MessageDlg( "Failed to create header structure",
                                        mtError,
                                        TMsgDlgButtons() << mbOK,
                                        0 );
                                MTHROW( std::runtime_error, \
                                        "Cannot create \"" \
                                        << headerStructure \
                                        << "\", version " \
                                        << currentIteration \
                                        << '.' );
                        }
                }
                catch ( ... )
                {
                        if ( !handle.empty() )
                        {
                                schema.Destroy( handle );
                                handle = "";
                        }
                        throw;
                }
        }
        __finally
        {
                delete query;
                query = 0;
        }
}


//---------------------------------------------------------------------------
/**
 *      Replace the given macros.
 */
void TRunTestsForm::substituteMacros(
                string &                                                                        handle,
                TXMLSchema &                                                            schema,
                const vector< pair< string, string > > &        macros,
                const unsigned short &                                          udType )
{
        AnsiString value;
        for ( vector< pair< string, string > >::const_iterator
                        where = macros.begin();
                  where != macros.end();
                  ++where )
        {
                schema.SetAttributeValue(
                        handle,
                        where->first.c_str(),
                        substituteMacro( value = where->second.c_str(), udType ).c_str() );
        }
}



//---------------------------------------------------------------------------
/**
 *      Load transaction parameters.
 */
void TRunTestsForm::loadParameters( IterationParams &   parameters,
                                                                        const int &                     testScenario,
                                                                        const int &                     transactionSpecification )
{
        TADOQuery * query = 0;

        try
        {
                AnsiString sql_statement;
                sql_statement.sprintf(
                        "SELECT "
                                "FIELDNAME, "
                                "SUBSCRIPT, "
                                "FIELDVALUE "
                        "FROM "
                                "TXNSPEC_VALUES "
                        "WHERE "
                                "TESTSCENARIO_NO=%d AND "
                                "TXNSPEC_NO=%d AND "
                                "( FIELDVALUE IS NOT NULL OR FIELDVALUE<>\'\')",
                        testScenario,
                        transactionSpecification );


                query = new TADOQuery( 0 );
                query->Connection = Data_Module->IntegrationDBConnection;
                query->SQL->Text = sql_statement;

                query->Open();
                AnsiString field;
                while ( !query->Eof )
                {

                        if ( query->FieldByName( "SUBSCRIPT" )->AsInteger == 0 )
                        {
                                field = query->FieldByName( "FIELDNAME" )->AsString;
                        }
                        else
                        {
                                field.sprintf( "%s.%d",
                                                                 query->FieldByName( "FIELDNAME" )->AsString.c_str(),
                                                                 query->FieldByName( "SUBSCRIPT" )->AsInteger );
                        }

                        parameters.insert(
                                IterationParamsPair(
                                        field.c_str(),
                                        query->FieldByName( "FIELDVALUE" )->AsString.c_str() ) );

                        query->Next();
                }
        }
        __finally
        {
                delete query;
                query = 0;
        }
}


//---------------------------------------------------------------------------
/**
 *      Get the value of the key assigned last to the named table.
 */
const unsigned int getLastAssignedSk( TADOConnection * database, const char * tableName )
{
    unsigned int        value   = 0;
    AnsiString          sqlQuery;
    TADOQuery *         query   = 0;

    try
    {
        query = new TADOQuery( 0 );
        query->Connection = database;

        AnsiString sequenceName;
        sequenceName.sprintf( "%s_SK", tableName );

        sqlQuery.sprintf(
                        "SELECT FN_SEQ_CURRVAL( \'%s\' ) FROM DUAL",
                        sequenceName );
        query->SQL->Text = sqlQuery;
        query->Open();
        value = query->Fields->Fields[ 0 ]->AsInteger;
    }
    __finally
    {
        query->Close();
        delete query;
    }

    return value;
}


//---------------------------------------------------------------------------
/**
 *      Create an instance of the given scenario, and evaluate to its key.
 */
void createScenario( TADOConnection * database, int & key, const unsigned int & testScenario )
{
        TADOQuery *     query = 0;

        try
        {
                query = new TADOQuery( 0 );
                query->Connection = database;

                AnsiString sqlQuery;
                sqlQuery.sprintf(
                        "INSERT INTO GENERATED_SCENARIO( TEST_SCENARIO_FK ) VALUES ( %u )",
                        testScenario );

                query->SQL->Text = sqlQuery;
                query->ExecSQL();

                key = getLastAssignedSk( database, "GENERATED_SCENARIO" );
    }
    __finally
    {
        query->Close();
        delete query;
    }
}


//---------------------------------------------------------------------------
/**
 *      Create a batch for the given scenario instance, and evaluate to its key.
 */
void createBatch( TADOConnection * database, int & key, const unsigned int & number, const int & scenario )
{
        TADOQuery *     query = 0;

        try
        {
                query = new TADOQuery( 0 );
                query->Connection = database;

                AnsiString sqlQuery;
                sqlQuery.sprintf(
                        "INSERT INTO GENERATED_BATCH( GENERATED_SCENARIO_FK, SEQUENCE_NUMBER ) VALUES ( %d, %u )",
                        scenario,
                        number );

                query->SQL->Text = sqlQuery;
                query->ExecSQL();

                key = getLastAssignedSk( database, "GENERATED_BATCH" );
    }
    __finally
    {
        query->Close();
        delete query;
    }
}


//---------------------------------------------------------------------------
/**
 *      Create a transaction for the given batch and transaction specification,
 *      and evaluate to its key.
 */
void createTransaction( TADOConnection *                database,
                                                int &                                   key,
                                                const int &                             batch,
                                                const int &                             transactionSpecification,
                                                TMemoryStream *                 payload )
{
        TADOQuery *     query = 0;

        try
        {
                query = new TADOQuery( 0 );
                query->Connection = database;

                /**
                 *      This is a strange way of going about inserting a row, but it 
                 *      seems to be the only one that works with Oracle.
                 */
                query->SQL->Text = "SELECT * FROM GENERATED_TRANSACTION";
                query->Open();
                query->Append();

                query->FieldByName( "GENERATED_BATCH_FK" )->AsInteger = batch;
                query->FieldByName( "TRANSACTION_SPECIFICATION_FK" )->AsInteger = transactionSpecification;

                TBlobField *blob = dynamic_cast< TBlobField * >( query->FieldByName( "PAYLOAD" ) );
                if ( blob )
                {
                        blob->LoadFromStream( payload );
                }

                query->Post();

                key = getLastAssignedSk( database, "GENERATED_TRANSACTION" );
        }
        __finally
        {
                query->Close();
        delete query;
    }
}


//---------------------------------------------------------------------------
/**
 *      Generate the given transaction.
 */
void TRunTestsForm::generateScenario( const unsigned int &                                              testscenario_no,
                                                                          TXNIndexMap &                                                         mass_txns,
                                                                          const bool &                                                          isTds,
                                                                          string &                                                                      headerHandle,
                                                                          TransactionSchedule &                                         transactionSchedule,
                                                                          const vector< pair< string, string > > &      macros,
                                                                          const unsigned int &                                          repeatCount,
                                                                          const unsigned int &                                          total,
                                                                          const int &                                                           batchSk )
{
        TMemoryStream * payload = 0;

        try
        {
                payload = new TMemoryStream();

                bool    txngen_error    = false;
#ifdef STORE_IN_DATABASE
                int             transactionSk   = 0;
#endif
                for ( TransactionSchedule::iterator
                                transaction = transactionSchedule.begin();
                          !txngen_error && transaction != transactionSchedule.end();
                          ++transaction )
                {
                        payload->Clear();
#if 1
                        // If this is a TDS then prefix with a SysHdr_t
                        if ( isTds )    // TDS
                        {
                                substituteMacros( headerHandle, *m_XMLSchema, macros, transaction->second->getUdType() );

                                const string    streamtype      = "XDR";
                                const string    stream_args;
                                void *                  stream          = 0;
                                unsigned int    stream_size     = 0;

                                if ( m_XMLSchema->Serialise( headerHandle, streamtype, stream_args, stream, stream_size, 0, 0, 0 ) )
                                {
                                        payload->Write( stream, stream_size );
                                }
                        }

#ifdef INITIALISETXNSTRUCTURE
                        // Initialise our transaction artefact with its parameters
                        if ( InitialiseTxnStructure(
                                        transaction->second->getHandle(),
                                        0,
                                        transaction->second->getIterationParameters() ) )
#endif
                        {
                                // If we have initialised the Txn successfully then Serialise the outcome

                                const string    streamtype = "XDR";
                                const string    stream_args;
                                void *                  stream = 0;
                                unsigned int    stream_size = 0;

                                if ( m_XMLSchema->Serialise(
                                                transaction->second->getHandle(),
                                                streamtype,
                                                stream_args,
                                                stream,
                                                stream_size,
                                                0,
                                                0,
                                                0 ) )
                                {
                                        payload->Write( stream, stream_size );
#ifdef STORE_IN_DATABASE
                                        createTransaction(
                                                Data_Module->IntegrationDBConnection,
                                                transactionSk,
                                                batchSk,
                                                transaction->first,
                                                payload );
#endif
                                        }
                                else
                                {
                                        AnsiString      msg;
                                        msg.sprintf(
                                                "Failed to serialise txn \'%s\' for \'%s\'",
                                                transaction->second->getName().c_str(),
                                                m_testcase.c_str() );

                                        MessageDlg(msg, mtError, TMsgDlgButtons() << mbOK, 0);

                                        txngen_error = true;
                                }
                        }
#ifdef INITIALISETXNSTRUCTURE
                        else
                        {
                                txngen_error = true;
                        }
#endif
#endif
                } // while
        }
        __finally
        {
                delete payload;
                payload = 0;
        }
}


//---------------------------------------------------------------------------
/**
 *      Read the transaction schedule for the given test scenario.
 */
void TRunTestsForm::readTransactionSchedule( TADOConnection *           database,
                                                                                         TXMLSchema &                   schema,
                                                                                         const int &                    currentIteration,
                                                                                         TXNIndexMap &                  massTransactions,
                                                                                         const int &                    testScenario,
                                                                                         TransactionSchedule &  transactionSchedule )
{
        TADOQuery *     query = 0;
        try
        {
                query = new TADOQuery( 0 );
                query->Connection = database;

                AnsiString sqlQuery;
                sqlQuery.sprintf(
                        "SELECT "
                                "TXNSPEC_NO, "
                                "UDTYPE, "
                                "UDSUBTYPE "
                        "FROM "
                                "TRANSACTION_SPECIFICATION "
                        "WHERE "
                                "TESTSCENARIO_NO=%d "
                        "ORDER BY "
                                "SEQ_NO",
                        testScenario );

                query->SQL->Text = sqlQuery;

                pair< TransactionSchedule::iterator, bool > where;
                int                                             transactionSpecification        = 0;
                unsigned short                  udType                                          = 0;
                unsigned short                  udSubtype                                       = 0;
                TransactionArtefact *   transactionArtefact                     = 0;
                string                                  handle;
                TXNIndexMap::iterator   transaction;
                string                                  structureName;

                for ( query->Open(); !query->Eof; query->Next() )
                {
                        transactionSpecification        = query->FieldByName( "TXNSPEC_NO" )->AsInteger;
                        udType                                          = query->FieldByName( "UDTYPE" )->AsInteger;
                        udSubtype                                       = query->FieldByName( "UDSUBTYPE" )->AsInteger;

                        // Resolve the UD type and subtype into a structure name.
                        transaction = massTransactions.find( ( udType << 16 ) + udSubtype );
                        if ( transaction != massTransactions.end() )
                        {
                                structureName = transaction->second.c_str();

                                where = transactionSchedule.insert(
                                        TransactionSchedule::value_type( transactionSpecification, 0 ) );
                                if ( where.second )
                                {
                                        try
                                        {
                                                transactionArtefact = new TransactionArtefact(
                                                        schema,
                                                        structureName,
                                                        udType );

                                                if ( schema.Create( "",
                                                                                        structureName.c_str(),
                                                                                        currentIteration,
                                                                                        handle,
                                                                                        0 ) )
                                                {
                                                        where.first->second = transactionArtefact;
                                                        transactionArtefact->setHandle( handle );
                                                }
                                                else
                                                {
                                                        MTHROW( std::runtime_error, \
                                                                "Cannot create structure \"" \
                                                                << structureName \
                                                                << "\" for iteration " \
                                                                << currentIteration \
                                                                << '.' );
                                                }

                                                loadParameters(
                                                        transactionArtefact->getIterationParameters(),
                                                        testScenario,
                                                        transactionSpecification );
                                        }
                                        catch ( ... )
                                        {
                                                delete transactionArtefact;
                                                transactionArtefact = 0;

                                                transactionSchedule.erase( where.first );

                                                throw;
                                        }
                                }
                                else
                                {
                                        MTHROW( std::runtime_error, \
                                                "Cannot cache handle for structure \"" \
                                                << structureName \
                                                << "\"." );
                                }
                        }
                        else
                        {
                                MTHROW( std::runtime_error, \
                                        "Cannot find structure for UD type " \
                                        << udType \
                                        << ", subtype " \
                                        << udSubtype \
                                        << '.' );
                        }
                }
    }
    __finally
    {
        query->Close();
        delete query;
    }
}


//---------------------------------------------------------------------------
/**
 *      Generate the given test case.
 */
void TRunTestsForm::generateTestCase( void )
{
#ifdef ADV_PROGRESS_BAR
        m_progressBar->Show();
        m_progressBar->Position = 0;
#else
        m_progressBarOld->Show();
        m_progressBarOld->Position = 0;
#endif

        const bool isTds = ( GenerationTargetComboBox->ItemIndex == 1 );

        TransactionSchedule     transactionSchedule;

        TADOQuery * query = 0;
        try
        {
                const bool foundSchema = findSchema(
                        m_xml_schemas,
                        *m_XMLSchema,
                        m_currentproject,
                        m_currentiteration );

                // Did we find the Target XML Writer Schema ?
                if ( foundSchema )
                {
                        /**
                         *      When we need a header, then create the header that we'll 
                         *      prepend to every transaction.  Macros are evaluated later,
                         *      so we need to remember them until then.
                         */
                        string headerHandle;
                        vector< pair< string, string > > macros;
                        if ( isTds )
                        {
                                buildHeader(
                                        headerHandle,
                                        *m_XMLSchema,
                                        macros,
                                        m_currentproject,
                                        m_currentiteration );
                        }

                        Data_Module->IntegrationDBConnection->BeginTrans();

                        AnsiString      sql_statement;

                        query = new TADOQuery( this );
                        query->Connection = Data_Module->IntegrationDBConnection;

                        // Build a MASS Txn Map for fast lookup
                        TXNIndexMap mass_txns;
                        buildTranactionMap( mass_txns, m_currentproject, m_currentiteration );

                        // Process ALL TestScenarios, in order, for this TestCase

                        bool    txngen_error = false;

                        sql_statement="";
                        sql_statement.sprintf("select testscenario_no,testcase_seqno,name,repeat_count,batch_size "
                                                                  "from test_scenarios "
                                                                  "where project_code='%s' and iteration=%d "
                                                                  "and testcase_id='%s' "
                                                                  "order by testcase_seqno",
                                                                  m_currentproject.c_str(),
                                                                  m_currentiteration,
                                                                  m_testcase.c_str());

                        query->SQL->Text = sql_statement;

                        /**
                         *      First, we traverse the result set to scope out the work that
                         *      we're about to embark upon.  We use this as an indication of
                         *      progress.
                         */
                        query->Open();
                        unsigned int total = 0;
                        unsigned int count = 0;
                        while ( !query->Eof )
                        {
                                total += ( !query->FieldByName("REPEAT_COUNT")->IsNull
                                        ? query->FieldByName("REPEAT_COUNT")->AsInteger
                                        : 1 );
                                query->Next();
                        }
                        query->Close();

                        /**
                         *      Now we traverse the result set to actually do the work.
                         */
                        query->Open();
                        TDateTime beginning     = TDateTime::CurrentDateTime();
                        TDateTime now           = TDateTime::CurrentDateTime();
                        TDateTime update        = TDateTime::CurrentDateTime();
                        const TDateTime step( 0, 0, 2, 500 );
                        double duration;
                        double estimate;
                        double scale = 0.0;
                        AnsiString progress;

#ifdef STORE_IN_DATABASE
                        int scenarioSk  = 0;
#endif
                        int batchSk             = 0;
                        int batchNumber = 0;
                        unsigned int batchLength        = 0;
                        while ( !txngen_error && !query->Eof )
                        {
                                const unsigned int testscenario_no      = query->FieldByName( "TESTSCENARIO_NO" )->AsInteger;
                                const unsigned int repeatCount          = ( !query->FieldByName( "REPEAT_COUNT" )->IsNull
                                        ? query->FieldByName("REPEAT_COUNT")->AsInteger
                                        : 1 );
                                const unsigned int batchSize            = ( !query->FieldByName( "BATCH_SIZE" )->IsNull
                                        ? query->FieldByName("batch_size")->AsInteger
                                        : 1 );
                                const AnsiString name                           = query->FieldByName("NAME")->AsString.c_str();

                                AnsiString      testcase_desc;
                                testcase_desc.sprintf("(%d) %s",
                                                                          query->FieldByName("TESTCASE_SEQNO")->AsInteger,
                                                                          name.c_str()
                                                                          );

                                readTransactionSchedule(
                                        Data_Module->IntegrationDBConnection,
                                        *m_XMLSchema,
                                        m_currentiteration,
                                        mass_txns,
                                        testscenario_no,
                                        transactionSchedule );
                                batchNumber     = 1;
                                batchLength     = 0;
#ifdef STORE_IN_DATABASE
                                createScenario(
                                        Data_Module->IntegrationDBConnection,
                                        scenarioSk,
                                        testscenario_no );
                                createBatch(
                                        Data_Module->IntegrationDBConnection,
                                        batchSk,
                                        batchNumber,
                                        scenarioSk );
#endif
//                              TTreeNode *testcase_node = TestCaseTxnTreeView->Items->AddObject(NULL, testcase_desc, (void *)testscenario_no);

                                /**
                                 *      Determine the set of Transaction Specifications for the ordered
                                 *      set of test scenarios
                                 */
                                for ( unsigned int i=0; i<repeatCount; ++i )
                                {
                                        if ( batchLength >= batchSize )
                                        {
                                                ++batchNumber;
                                                batchLength = 1;
                                                
#ifdef STORE_IN_DATABASE
                                                createBatch(
                                                        Data_Module->IntegrationDBConnection,
                                                        batchSk,
                                                        batchNumber,
                                                        scenarioSk );
#endif
                                        }
                                        else
                                        {
                                                ++batchLength;
                                        }
                                        generateScenario(
                                                testscenario_no,
                                                mass_txns,
                                                isTds,
                                                headerHandle,
                                                transactionSchedule,
                                                macros,
                                                repeatCount,
                                                total,
                                                batchSk );
                                        ++count;

                                        now = TDateTime::CurrentDateTime();
                                        if ( now - update >= step )
                                        {
                                                scale = double( total ) / double( count );
                                                duration = now - beginning;
                                                estimate = ( duration * scale ) - duration;
                                                StatusBar->Panels->Items[0]->Text = "Estimated Time Remaining: " + TDateTime( estimate ).FormatString( "tt" );

                                                progress.sprintf( "Count: %d, avg: %f ms/t",
                                                        count,
                                                        ( duration / count ) * 24 * 60 * 60 * 1000 );
                                                StatusBar->Panels->Items[1]->Text = progress;

                                                ProcessPaintMessages( StatusBar->Handle );

                                                update = now;
                                        }
#ifdef ADV_PROGRESS_BAR
                                        if ( m_progressBar->Position != int( count / double( total ) * 100.0 ) )
                                        {
                                                m_progressBar->Position = int( count / double( total ) * 100.0 );
                                        }
#else
                                        m_progressBarOld->Position = count / double( total ) * 100.0;
#endif
                                }

                                query->Next();
                        } // while

                        StatusBar->Panels->Items[0]->Text = "";
                        StatusBar->Panels->Items[1]->Text = "";

                        if (!txngen_error)
                        {
                                Data_Module->IntegrationDBConnection->CommitTrans();
                        }
                }
                else
                {
                        AnsiString      msg;

                        msg.sprintf("Failed to locate XML for %s (%s) Iteration: %d\nPlease verify XMLSchema.ini",
                                                MASSUDWriter,
                                                m_currentproject.c_str(),
                                                m_currentiteration
                                                );

                MessageDlg(msg.c_str(),
                           mtError, TMsgDlgButtons() << mbOK, 0);
        }
    }
    __finally
    {
                delete query;
                query = 0;

        if (Data_Module->IntegrationDBConnection->InTransaction)
        {
                        Data_Module->IntegrationDBConnection->RollbackTrans();
                }

                // Clear the transaction schedule.
                for ( TransactionSchedule::iterator where = transactionSchedule.begin();
                          where != transactionSchedule.end();
                          ++where )
                {
                        delete where->second;
                        where->second = 0;
                }
                transactionSchedule.clear();

#ifdef ADV_PROGRESS_BAR
                m_progressBar->Hide();
#else
                m_progressBarOld->Hide();
#endif
        }
}


//---------------------------------------------------------------------------
void __fastcall TRunTestsForm::GenerateTransactionsClick(TObject *Sender)
{
        const TCursor Save_Cursor = Screen->Cursor;
        Screen->Cursor = crHourGlass;

        try
        {
                TestCaseTxnTreeView->Items->Clear();
                generateTestCase();
                MWARNING( "TODO: rebuild tree view." );
        }
        __finally
        {
                Screen->Cursor = Save_Cursor;
        }
}


//---------------------------------------------------------------------------
bool __fastcall TRunTestsForm::InitialiseTxnStructure(const string &structure_handle, int subscript, IterationParams &structure_params)
{
    vector<string>                              structure_attributes;
    vector<string>::iterator    s_itr;
//      AnsiString                                      sql_statement;
    bool                                                noerror = true;

    m_XMLSchema->GetAttributes(structure_handle, structure_attributes);

    s_itr = structure_attributes.begin();
    while ( noerror && (s_itr != structure_attributes.end()) )
    {
        string  elementtype;
        string  attr_handle = (*s_itr);

        m_XMLSchema->GetAttributeProperty(attr_handle, "type", elementtype);

        if (elementtype == "field")
        {
            string      datatype;

            m_XMLSchema->GetAttributeProperty(attr_handle, "datatype", datatype);

            if (datatype == "Struct")
            {
                    noerror = InitialiseTxnStructure(attr_handle, subscript, structure_params);
            }
            else
            {
                string  fieldname;
                string  tagvalue;
                string  xpath;

                m_XMLSchema->GetAttributeProperty(attr_handle, "tag", tagvalue);

                if (tagvalue.length() > 0)
                {
                    m_XMLSchema->GetAttributeProperty(attr_handle, "name", fieldname);

                    AnsiString  fieldid;

                    if (subscript == 0)
                    {
                        fieldid = fieldname.c_str();
                    }
                    else
                    {
                            fieldid.sprintf("%s.%d", fieldname.c_str(), subscript);
                    }

                    IterationParams::iterator   f_itr = structure_params.find(fieldid.c_str());

                                        if (f_itr != structure_params.end())
                    {
                        string  fieldvalue = (*f_itr).second;
                        string  valuemap;

                        m_XMLSchema->GetAttributeProperty(attr_handle, "valuemap", valuemap);
                        if (valuemap.empty())
                        {
                                if (fieldvalue[0] == '-')
                            {
                                int     int_value = atoi( fieldvalue.c_str() );

                                m_XMLSchema->SetAttributeValue(attr_handle, "", int_value);
                            }
                            else
                            if (m_XMLSchema->SetAttributeValue(attr_handle, "", fieldvalue.c_str()) == false)
                            {
                                AnsiString      msg;
                                msg.sprintf("Failed to initialise attribute '%s' to (%s) DataType: %s\n"
                                                        "Continue ?",
                                            fieldname.c_str(), fieldvalue.c_str(),
                                            datatype.c_str());

                                if (MessageDlg(msg, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0) == mrNo)
                                {
                                        noerror = false;
                                }
                            }
                        }
                        else
                                                {
                            if ( (fieldvalue[0] == '-') || (fieldvalue[0] >='0' && fieldvalue[0] <='9') )
                            {
                                int     int_value = atoi( fieldvalue.c_str() );

                                if (m_XMLSchema->SetAttributeValue(attr_handle, "", int_value) == false)
                                {
                                    AnsiString  msg;
                                    msg.sprintf("Failed to initialise attribute '%s' to (%s) DataType: %s\n"
                                                "Continue ?",
                                                fieldname.c_str(), fieldvalue.c_str(),
                                                datatype.c_str());

                                    if (MessageDlg(msg, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0) == mrNo)
                                    {
                                        noerror = false;
                                    }
                                }
                            }
                            else
                            {
                                if (m_XMLSchema->SetAttributeValue(attr_handle, "", fieldvalue.c_str()) == false)
                                {
                                    AnsiString  msg;
                                    msg.sprintf("Failed to initialise attribute '%s' to (%s) DataType: %s\n"
                                                "Continue ?",
                                                fieldname.c_str(), fieldvalue.c_str(),
                                                datatype.c_str());

                                    if (MessageDlg(msg, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0) == mrNo)
                                                                        {
                                        noerror = false;
                                    }
                                }
                            }
                        }
                    }
                }
                }
                }
        else
        if (elementtype == "repeat")
        {
                string  refcountfield;
                string  maxOccursStr;
            string      refcountAttribute;

            m_XMLSchema->GetAttributeProperty(attr_handle, "refcountfield", refcountfield);

            if (!refcountfield.empty())
            {
                    string              refcountAttribute = structure_handle+"."+refcountfield;

                m_XMLSchema->GetAttributeProperty(refcountAttribute, "max", maxOccursStr);
            }

            if (maxOccursStr.empty())
            {
                    m_XMLSchema->GetAttributeProperty(attr_handle, "maxOccurs", maxOccursStr);
            }

            int maxOccurs = atoi(maxOccursStr.c_str());

            // Limit to 100 elements
            if (maxOccurs > 100)
            {
                    maxOccurs = 100;
            }

            string      refcount_value;
            m_XMLSchema->GetAttributeValue(structure_handle, refcountfield, refcount_value);

            string      repeat_name;
            m_XMLSchema->GetAttributeProperty(attr_handle, "name", repeat_name);

            if (!refcount_value.empty())
            {
                maxOccurs = atoi(refcount_value.c_str());
            }
            m_XMLSchema->SetAttributeValue(structure_handle, refcountfield, maxOccurs);

            for (int occurrence=1; occurrence<=maxOccurs; occurrence++)
            {
                string          repeat_attribute_handle;
                AnsiString      temp;

                temp.sprintf("%s.%d",
                             attr_handle.c_str(),
                             occurrence);

                                repeat_attribute_handle = temp.c_str();

                noerror = InitialiseTxnStructure(repeat_attribute_handle, occurrence, structure_params);
            } // for (int i=1; i<=occurrence; i++)
        }

        s_itr++;
    } // while

    return noerror;
}

//---------------------------------------------------------------------------


void TRunTestsForm::ShowForm(const AnsiString &testcase, const AnsiString &testname, const AnsiString &project, int currentiteration, const AnsiString &user_gen_dir, TXMLSchema *XMLSchema)
{
    m_currentproject = project;
    m_currentiteration = currentiteration;
        m_XMLSchema = XMLSchema;
    m_testcase = testcase;
    m_user_gen_dir = user_gen_dir;

        TestCaseTitle->Caption = testname;

        ShowModal();
}

//---------------------------------------------------------------------------

void __fastcall TRunTestsForm::TestCaseTxnTreeViewChange(TObject *Sender,
      TTreeNode *Node)
{
        if (Node->Level == 1)
    {
        TADOQuery       *query = new TADOQuery(this);
        query->Connection = Data_Module->IntegrationDBConnection;

        int     testscenario_no = (int)(Node->Parent->Data);
        int     txnspec_no              = (int)(Node->Data);

        AnsiString      sql_statement;

        sql_statement.sprintf("SELECT PAYLOAD FROM TRANSACTION_SPECIFICATION "
                                                  "WHERE TESTSCENARIO_NO=%d AND TXNSPEC_NO=%d",
                              testscenario_no,
                              txnspec_no);

        query->SQL->Text = sql_statement;
        query->Open();

        if (query->RecordCount == 1)
        {
                        TStream*                payload_stream = query->CreateBlobStream(query->FieldByName("PAYLOAD"), bmRead);
            unsigned int        payload_size = payload_stream->Size;
            void*               payload = malloc(payload_size);

            payload_stream->ReadBuffer(payload, payload_stream->Size);

            PayloadGrid->Rows = (payload_size+15)/16;

            unsigned char *p = (unsigned char *)payload;
                        for (unsigned row=0; row<(payload_size+15)/16; row++)
                        {
                for (unsigned col=0; col<16; col++)
                {
                        AnsiString      abyte;
                    abyte.sprintf("%02X", *p);

                    PayloadGrid->Cell[col+1][row+1] = abyte;

                    p++;
                }
            }

            free(payload);
        }

        delete query;
    }
//      PayloadGrid

}
//---------------------------------------------------------------------------

void __fastcall TRunTestsForm::SaveTxnsToFileClick(TObject *Sender)
{
    TCursor Save_Cursor = Screen->Cursor;
    Screen->Cursor = crHourGlass;    // Show hourglass cursor

    try
    {
            AnsiString  sql_statement;

            TADOQuery   *query = new TADOQuery(this);
            query->Connection = Data_Module->IntegrationDBConnection;

            TADOQuery   *query2 = new TADOQuery(this);
            query2->Connection = Data_Module->IntegrationDBConnection;

            sql_statement="";
            sql_statement.sprintf("SELECT TXNSTORAGE_PATH "
                                  "FROM ITERATIONS "
                                  "WHERE PROJECT_CODE='%s' "
                                  "AND   ITERATION=%d ",
                                  m_currentproject.c_str(),
                                  m_currentiteration);

            query->SQL->Text = sql_statement;
                        query->Open();

            AnsiString  txnstorage_path = query->FieldByName("TXNSTORAGE_PATH")->AsString;

                        AnsiString      target_path;

            if (!m_user_gen_dir.IsEmpty() && (txnstorage_path[2] != ':') )
            {
                target_path  = m_user_gen_dir;
                target_path += "\\";
                target_path += txnstorage_path;
            }
            else
            {
                target_path = txnstorage_path;
            }

            if (access(target_path.c_str(), 0) == 0)
            {
                // Build a MASS Txn Map for fast lookup

                TXNIndexMap                                     mass_txns;

                sql_statement="";
                sql_statement.sprintf("SELECT NAME,UDTYPE,UDSUBTYPE "
                                      "FROM MASS_TXNS "
                                      "WHERE PROJECTCODE='%s' "
                                      "AND       ITERATION=%d ",
                                      m_currentproject.c_str(),
                                      m_currentiteration);

                query->SQL->Text = sql_statement;
                query->Open();
                while (!query->Eof)
                                {
                    unsigned short      udtype          = query->FieldByName("UDTYPE")->AsInteger;
                    unsigned short      udsubtype       = query->FieldByName("UDSUBTYPE")->AsInteger;
                    unsigned int        udindex         = (udtype << 16) + udsubtype;

                    TXNIndexPair        pair(udindex, query->FieldByName("NAME")->AsString);

                    mass_txns.insert(pair);

                    query->Next();
                }

                sql_statement="";
                sql_statement.sprintf("select testscenario_no,testcase_seqno,name "
                                      "from test_scenarios "
                                      "where project_code='%s' and iteration=%d "
                                      "and testcase_id='%s' "
                                      "order by testcase_seqno",
                                                                          m_currentproject.c_str(),
                                      m_currentiteration,
                                      m_testcase.c_str());
                query->SQL->Text = sql_statement;
                query->Open();
                while ( !query->Eof )
                {
                    unsigned int        testscenario_no = query->FieldByName("TESTSCENARIO_NO")->AsInteger;

                    // Determine the set of Transaction Specifications for the ordered
                    // set of test scenarios

                                        sql_statement="";
                    sql_statement.sprintf("select txnspec_no,seq_no,udtype,udsubtype,payload "
                                          "from transaction_specification "
                                          "where testscenario_no=%d "
                                          "order by seq_no",
                                          testscenario_no);
                    query2->SQL->Text = sql_statement;
                    query2->Open();
                    while (!query2->Eof)
                    {
                        TBlobField              *payload_field = dynamic_cast<TBlobField *>(query2->FieldByName("PAYLOAD"));

                        if (!payload_field->IsNull)
                        {
                            AnsiString  filename;

                            unsigned short  udtype              = query2->FieldByName("UDTYPE")->AsInteger;
                            unsigned short  udsubtype   = query2->FieldByName("UDSUBTYPE")->AsInteger;
                            unsigned int        udindex         = (udtype << 16) + udsubtype;

                            // Locate the MASS Txn based on UD Type and SubType

                            TXNIndexMap::iterator       txn_itr = mass_txns.find(udindex);

                            if (txn_itr != mass_txns.end())
                                                        {
                                string structure_name   = (*txn_itr).second.c_str();

                                AnsiString      target_directory;
                                                                target_directory.sprintf("%s/%s", target_path.c_str(), m_testcase.c_str());

                                if (access(target_directory.c_str(), 0) != 0)
                                {
                                        mkdir(target_directory.c_str());
                                }

                                if (access(target_directory.c_str(), 0) == 0)
                                {
                                    filename.sprintf("%s/%s/%s_%03d_%02d_%s.xdr",
                                                     target_path.c_str(),
                                                     m_testcase.c_str(),
                                                     m_testcase.c_str(),
                                                     query->FieldByName("TESTCASE_SEQNO")->AsInteger,
                                                     query2->FieldByName("SEQ_NO")->AsInteger,
                                                     structure_name.c_str()
                                                     );

                                                                        payload_field->SaveToFile(filename);
                                } // Found Target Directory
                            } // Found MASS Txn
                        } // if (!payload_field->IsNull)

                        query2->Next();
                    }

                                        query->Next();
                }

                delete query;
                                delete query2;

                AnsiString      msg;
                msg.sprintf("Generated Transactions to: %s" , target_path.c_str());

                MessageDlg(msg, mtInformation, TMsgDlgButtons() << mbOK, 0);
            }
            else
            {
                AnsiString      msg;
                msg.sprintf("Directory '%s' Not Found or Not Accessible", target_path.c_str());

                    MessageDlg(msg, mtInformation, TMsgDlgButtons() << mbOK, 0);
            }
    }
        __finally
        {
                Screen->Cursor = Save_Cursor;
        }
}
//---------------------------------------------------------------------------


void __fastcall TRunTestsForm::FormCreate(TObject *Sender)
{
#ifdef ADV_PROGRESS_BAR
        m_progressBar = new TAdvProgressBar( StatusBar );
        m_progressBar->Parent                           = StatusBar;
        m_progressBar->Steps                            = 10;
        m_progressBar->Position                         = 0;
        m_progressBar->ShowBorder                       = false;
        m_progressBar->ShowGradient                     = true;
        m_progressBar->ShowPercentage           = true;
        m_progressBar->Stacked                          = false;
        m_progressBar->CompletionSmooth         = false;
        m_progressBar->Visible                          = false;

//      m_progressBar->Level0Color                      = Graphics::TColor( 0x006AA676 );
//      m_progressBar->Level0ColorTo            = Graphics::TColor( 0x00BAE3C3 );
        m_progressBar->Level0Color                      = Graphics::TColor( 0x00C961AD );
        m_progressBar->Level0ColorTo            = Graphics::TColor( 0x00FFBCEF );
        m_progressBar->Level1Color                      = Graphics::TColor( 0x00C961AD );
        m_progressBar->Level1ColorTo            = Graphics::TColor( 0x00FFBCEF );
        m_progressBar->Level2Color                      = Graphics::TColor( 0x00C961AD );
        m_progressBar->Level2ColorTo            = Graphics::TColor( 0x00FFBCEF );
        m_progressBar->Level3Color                      = Graphics::TColor( 0x00C961AD );
        m_progressBar->Level3ColorTo            = Graphics::TColor( 0x00FFBCEF );
#else
        m_progressBarOld = new TProgressBar ( StatusBar );
        m_progressBarOld->Parent = StatusBar;
        m_progressBarOld->Step     = 10;
        m_progressBarOld->Max      = 100;
        m_progressBarOld->Position = 0;
        m_progressBarOld->Visible = false;
#endif
}
//---------------------------------------------------------------------------

void __fastcall TRunTestsForm::StatusBarResize(TObject *Sender)
{
        RECT Rect;
        StatusBar->Perform( SB_GETRECT, 0, (LPARAM)&Rect );

        const int progressPanel = 2;
        int offset = 0;
        for ( int i = 0; i < progressPanel; i++ )
        {
                offset += StatusBar->Panels->Items[ i ]->Width;
        }

#ifdef ADV_PROGRESS_BAR
        m_progressBar->Top = Rect.top + 2;
        m_progressBar->Left = Rect.left + offset + 4;
        m_progressBar->Width = StatusBar->Panels->Items[ progressPanel ]->Width - 6;
        m_progressBar->Height = Rect.bottom - Rect.top - 4;
#else
        m_progressBarOld->Top = Rect.top;
        m_progressBarOld->Left = Rect.left + offset + 2;
        m_progressBarOld->Width = StatusBar->Panels->Items[ progressPanel ]->Width - 2;
        m_progressBarOld->Height = Rect.bottom - Rect.top;
#endif
}
//---------------------------------------------------------------------------