TestUnit TestHarness.lsl

From Second Life Wiki
Revision as of 11:49, 26 September 2007 by Periapse Linden (talk | contribs)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
///////////////////////////////////////////////////////////////////////////////////
///////
///////
///////
///////            TestUnit_TestHarness
///////             
///////       
///////
///////  This is the inteface script that talks to the Coordinator. It should be included
///////  in each TestUnit. It communicates with the TestScripts via linked message. 
///////      
///////              
//////////////////////////////////////////////////////////////////////////////////////    

//TestUnit_TestHarness    .1 -> initial framework  6.23.2007
//TestUnit_TestHarness    .2 -> testing and minor bugfixes  7.2.2007


//////////////////////////////////////////////////////////////////////////////////////
//  General Specification for TestUnit from https://wiki.secondlife.com/wiki/LSLTest
//////////////////////////////////////////////////////////////////////////////////////

//Each test unit will have a small amount of boiler plate code to talk to the controller and understand the communication enough to change to another channel, start tests, and report test results.
//[edit] Requirements

//    * All test units reset to a default test broadcast channel of 0.
//    * All test units will be in a test group and the unit knows the group name.
//    * All test units have a name.
//    * Register to a coordinator on announcement of registration.
//    * Change communication channel on request of the coordinator
//    * Run its tests on the request of the coordinator
//    * Report test results with multiple levels of output
//          o verbose: everything
//          o normal: failures and summary information
//          o quiet: summary information only 


//////////////////////////////////////////////////////////////////////////////////////
//
//                  Command Protocol
//
//////////////////////////////////////////////////////////////////////////////////////
//
//   All commmands, input,output,chat, or linked message will be :: seperated 
//   lists in string form.
//
//////////////////////////////////////////////
//        CHAT commands
//////////////////////////////////////////////
//
//  Chat commands will be on the specified controlChannel
//
//////// INPUT ///////////
//
//    The first element of a chat command can be only one of three things. 
//   
//   ALL - A general indicator for all testUnits to process the command
//   unitName - The specific name of this unit
//   groupName - The specfic name of the group this unit belongs to
//
//   This first element of the chat input is parsed, and the remainder of the command
//   is sent to the parseCommand function. The follow are the current input commands   
//
////
//   Reset - sends link message toAllChannel calling for reset, and then resets this script
//   format example -> ALL::Reset
//
//   RegisterUnit - sends out chat on controlChannel unit registration information
//   format example -> ALL::RegisterUnit
//
//   RunTest - clears passFail and sends out linked message to TestScript 
//   format example -> ALL::RunTest
//
//   Report - sends out linked message to TestScript with broadcastChannel information
//   format example -> ALL::Report
//
//   SetReportType - sends out linked message to TestScript with Report Level change
//   format example -> ALL::SetReportType::NORMAL
//
//   UpdateUnitStatus - sends out unit status information on chat controlChannel 
//   format example -> ALL::UpdateUnitStatus
//
//   SetControlChannel - changes controlChannel to value provided
//   format example -> ALL::SetControlChannel::-1234
//
//
//////// OUTPUT ///////////
//   
// Registration - Response to RegisterUnit command, send registration information to Coordinator
// format example -> Registration::unitKey::00000-0000-0000-00000::unitName::TestUnit1::groupName::Group1
//
// UpdateUnitStatus - Response to request to send out unit status information
// format example -> UpdateUnitStatus::unitKey::00000-0000-0000-00000::unitStatus::PASS
//
//
//
//////////////////////////////////////////////
//        LINK MESSAGE commands
//////////////////////////////////////////////
//
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel
//
//////// INPUT ///////////
//
//  passFail - status of test sent by TestScript
//  format example -> PASS
//
//////// OUTPUT ///////////
//
//  RunTest - activation command to start test
//  format example -> RunTest
//
//  Reset - calls for script resets on toAllChannel
//  format example -> Reset
//
//  Report - sends channel and report type to TestScript
//  format example -> Report::controlChannel::0::reportType::NORMAL
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////





// Global Variables

integer toAllChannel = 255;           // general channel - linked message
integer passFailChannel = -355;        // test scripts channel for cummunicating pass/fail - linked message

integer controlChannel = 1234;            // command communication channel - chat

integer controlChannelListen;          // handler for the listener event

integer debug = 0;                     // level of debug message
integer debugChannel = DEBUG_CHANNEL;  // output channel for debug messages

integer notecardLines;                 //
key notecardRequestKey;                // notecard globals 
key notecardLineRequest;               // notecard stores UnitName and GroupName
integer currentNoteLine;               //

string groupName = "UNKNOWN";          // name of TestUnit group, used by Coordinator 
                                       // to select multiple units simultaneously 

string unitName = "UNKNOWN";           // name of this TestUnit, used by Coordinator 
                                       // to select this unit specifically 

string reportType = "NORMAL";          // determines length and content of report type
                                       // NORMAL - failures and summary information
                                       // QUITE - summary information only
                                       // VERBOSE - everything

string passFail = "FAIL";              // current status of test script
                                       // FAIL - default untill successful completion of test
                                       // PASS - successful test completed
                                       

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////
//////////      Function:   ParseCommand
//////////
//////////      Input:      string message - command to be parsed
//////////                    
//////////      Output:     no return value
//////////                    
//////////      Purpose:    This function calls various other functions or sets globals
//////////                    depending on message string. Allows external command calls
//////////                  from chat controlChannel
//////////                    
//////////      Issues:        no known issues 
//////////                    
//////////                    
/////////////////////////////////////////////////////////////////////////////////////////////////
ParseCommand(string message)
{
    if(debug > 1)llSay(debugChannel, llGetScriptName()+ "->ParseCommand: " + message);
        
    //reset all scripts 
    if(message == "reset")
    {
        //broadcast to other scripts reset command
        llMessageLinked(LINK_SET, toAllChannel, "reset", NULL_KEY); 
        //reset this script as well 
        llResetScript();                   
    }
    
    //RegisterUnit()
    else if(message == "RegisterUnit")
    {
        //Example output on controlChannel -> Registration::unitKey::00000-0000-0000-00000::unitName::TestUnit1::groupName::Group1
        llSay(controlChannel, "Registration::unitKey::" + (string)llGetKey() 
                                         + "::unitName::" + unitName
                                         + "::groupName::" + groupName);    
        
        llMessageLinked(LINK_SET, toAllChannel, "Registered", NULL_KEY);
                                              
    }

    //RunTest()
    else if(message == "RunTest")
    {
        //send link message on general channel initiating Test Scripts
        llMessageLinked(LINK_SET, toAllChannel, "RunTest", NULL_KEY);
    }

    //Report()
    else if(message == "Report")
    {
        //send link message on general channel initiating report function from Test Scripts
        //Example output on toAllChannel channel -> Report::controlChannel::0::reportType::NORMAL
        llMessageLinked(LINK_SET, toAllChannel, "Report::controlChannel::" + (string)controlChannel
                                             + "::reportType::" + reportType, NULL_KEY);
    }
    else if(llSubStringIndex(message, "SetReportType::") != -1)
    {
        //parse value from string by deleting message upto index of ::
        //and set global reportType variable
        reportType = llDeleteSubString( message, 0, llSubStringIndex(message, "::") + 1);
    }    
    // UpdateUnitStatus()
    else if(message == "UpdateUnitStatus")
    {
        //send chat message on control channel updating Coordinator with unit test status
        //Example output on control channel -> UpdateUnitStatus::unitKey::00000-0000-0000-00000::unitStatus::PASS
        llSay(controlChannel, "UpdateUnitStatus::unitKey::" + (string)llGetKey() + "::unitStatus::" + passFail );        
    }   
    
    //SetControlChannel()
    //example SetControlChannel::1
    else if(llSubStringIndex(message, "SetControlChannel::") != -1)
    {
        //parse value from string by deleting message upto index of ::
        //and set global controlChannel variable
        controlChannel = (integer)llDeleteSubString( message, 0, llSubStringIndex(message, "::") + 1);
        ActivateUnit();
    }
    
} //end ParseCommand

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////
//////////      Function:   Initialize
//////////
//////////      Input:      no input paramaters
//////////                    
//////////      Output:     no return value
//////////                    
//////////      Purpose:    This function initializes any variables or functions necessary
//////////                  to get us started
//////////                    
//////////      Issues:        no known issues 
//////////                    
//////////                    
/////////////////////////////////////////////////////////////////////////////////////////////////
Initialize()
{
    //initiate data server call to begin reading notecard
    notecardRequestKey = llGetNumberOfNotecardLines("TestUnit_nc");
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////
//////////      Function:   ActivateUnit
//////////
//////////      Input:      no input paramaters
//////////                    
//////////      Output:     no return value
//////////                    
//////////      Purpose:    This function activates any variables or functions necessary to get
//////////                  us running
//////////                    
//////////      Issues:        no known issues 
//////////                    
//////////                    
/////////////////////////////////////////////////////////////////////////////////////////////////
ActivateUnit()
{
    //remove possible listeners
    llListenRemove(controlChannel);
    //create new listeners
    controlChannelListen = llListen(controlChannel,"",NULL_KEY,"");
}

///////////////////////////////////////////////////////////////////////////////////////
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//
///////////////////////////////////////////////////////////////////////////////////////
//                                                                                   //
//                                                                                   //
//                          DEFAULT STATE                                            //
//                                                                                   //
//                                                                                   //
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
default
{
///////////////////////////////////////////////////////
//  State Entry of default state                     //
///////////////////////////////////////////////////////
   state_entry()
    {
        Initialize();
    }
////////////////////////////////////////////////////////
//  On Rez of default state                           //
////////////////////////////////////////////////////////    
    on_rez(integer start_param)
    {
        Initialize();
    }

///////////////////////////////////////////////////////
//  Listen of default state                          //
///////////////////////////////////////////////////////
    listen(integer channel, string name, key id, string message)
    {
        
     if(debug > 0){llSay(debugChannel, llGetScriptName()+ ":listen:" + message);}
     if(debug > 0){llSay(debugChannel, llGetScriptName()+ ":channel:" + (string)channel);}
        
    //from Coordinator
    if(channel == controlChannel)
    {
        //parse :: seperated list
        list commandCheck = llParseString2List( message, ["::"], [""] );
        
        //expect ALL, groupName, or unitName before first ::
        //Example ALL::RegisterUnit
        if( ( llList2String( commandCheck, 0 ) == "ALL" )
         || ( llList2String( commandCheck, 0 ) == groupName )
         || ( llList2String( commandCheck, 0 ) == unitName ) )
         {
             //send message to ParseCommand
                         //in string format
                                             // leave out variable before first ::
                                                                         //and send rest of message to last list element
                                             // put it back together with a :: seperators
            ParseCommand(llDumpList2String( 
                                            llList2List(commandCheck, 1, 
                                                                         llGetListLength(commandCheck) - 1 ) 
                                           , "::" )
                         ); //end parseCommand
         } // end || if   
    } //end channel if
    
} //end of listen
    
///////////////////////////////////////////////////////
//  Link Message of default state                    //
///////////////////////////////////////////////////////   
    link_message(integer sender_number, integer number, string message, key id)
    {
        //if link message is on the correct channel
        if(number == passFailChannel)
        {
            //update the passFail status with incomming message
            passFail = message;
            //notify Coordinator of new status for this unit
            ParseCommand("UpdateUnitStatus");
            
        }
        
    } //end of link message
    
///////////////////////////////////////////////////////
//  data server of default                           //
///////////////////////////////////////////////////////   
    dataserver(key queryid, string data)
    {
        if(queryid == notecardRequestKey) // line number request
        {
            notecardLines = (integer)data;
            currentNoteLine = 0;
            notecardLineRequest = llGetNotecardLine("TestUnit_nc", currentNoteLine);
        } //end line number request
        
        if(queryid == notecardLineRequest) //reading a line from the notecard
        {
            // if the string "UnitName:" exists in the data string, parse the unitName from between the []
            if(llSubStringIndex(data,"UnitName:") > -1)
            {
                unitName = llGetSubString(data, llSubStringIndex(data,"[") + 1,llSubStringIndex(data,"]") - 1);                
            }
            // if the string "GroupName:" exists in the data string, parse the groupName from between the []
            else if(llSubStringIndex(data,"GroupName:") > -1)
            {
                groupName = llGetSubString(data, llSubStringIndex(data,"[") + 1,llSubStringIndex(data,"]") - 1);
            }            
            
            //if additional lines on the notecard
            if(currentNoteLine < notecardLines - 1)
            {
                currentNoteLine += 1;
                //initiate another line request from the dataserver
                notecardLineRequest = llGetNotecardLine("TestUnit_nc", currentNoteLine);
            }else
            {
                // Done setting up, turn on listener
                ActivateUnit();
            }
            
        } //end line request
    } //end data server
    

    

} // end default