TestUnit TestHarness.lsl
Jump to navigation
Jump to search
///////////////////////////////////////////////////////////////////////////////////
///////
///////
///////
/////// TestUnit_TestHarness
///////
///////
///////
/////// This is the interface 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 commands, input,output,chat, or linked message will be :: separated
// 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 specific 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 communicating 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 until 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 parameters
//////////
////////// 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 parameters
//////////
////////// 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 :: separated 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 :: separators
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 incoming 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