testexecmgmt/ucc/GenericService/TestDriverService/src/CTestDriverService.cpp
changeset 0 3da2a79470a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecmgmt/ucc/GenericService/TestDriverService/src/CTestDriverService.cpp	Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,597 @@
+/*
+* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+* CTestDriverService.h
+*
+*/
+
+
+
+#include <stdlib.h>
+
+#include "CAThread.h"
+#include "CListeningServer.h"
+#include "CTestDriverService.h"
+#include "CUCCIniFile.h"
+
+// Parameters names
+const char	KPlatform[]				= { "PLATFORM" };
+const char	KBuild[]				= { "BUILD" };
+const char	KSuite[]				= { "SUITE" };
+const char	KTransport[]			= { "TRANSPORT" };
+const char	KLogging[]				= { "LOGGING" };
+
+// Ini file names
+const char	KTDServiceIni[]			= { ".\\TestDriverService.ini" };
+const char	KIniSectionName[]		= { "TestDriverService" };
+const char	KIniPort[]				= { "Port" };
+const char	KIniExeLocation[]		= { "Exe" };
+const char	KIniPollInterval[]		= { "Poll" };
+
+// TestDriver parameters and flags
+const char	KTDConnection[]			= { "localhost" };
+const char	KDefaultExe[]			= { "C:\\apps\\engtools\\testdriver2\\testdriver" };
+const char	KTDBuild[]				= { " build " };
+const char	KTDRun[]				= { " run " };
+const char	KPlatformFlag[]			= { " -p " };
+const char	KBuildFlag[]			= { " -b " };
+const char	KSuiteFlag[]			= { " -s " };
+const char	KTransportFlag[]		= { " -t " };
+const char	KLoggingFlag[]			= { " -l " };
+const char	KSocketFlag[]			= { " -f " };
+
+// TCP Port for TestDriver to use to contact the TestDriverService listening socket
+const int	KDefaultPort			= 3002;
+const int	KContinuePollingValue	= 1;
+
+// Default polling timeout for the Listening Server
+const int	KDefaultPoll			= 5; // 5 seconds
+
+// Static values to control the thread(s) execution
+static bool			iServerRunning;
+static bool			iTestDriverRunning;
+static int			iTDStartResult;
+static int			iTDCompleteResult;
+static bool			iTDContinuePolling;
+static bool			iTDRunSetupComplete;
+static char*		iRunCommandLine;
+static CAThread*	iServer;
+static CAThread*	iTestDriverRun;
+static HANDLE		iServerMutex;
+static HANDLE		iTDRunMutex;
+
+static string		iExe;
+static int			iPort;
+static int			iPollInterval;
+
+CService* Service() { return new CTestDriverService(); }
+
+/*
+ *	Constructor
+ */
+CTestDriverService::CTestDriverService()
+	{
+	iServerRunning = false;
+	iTestDriverRunning = false;
+	iTDStartResult = 0;
+	iTDCompleteResult = 0;
+	iTDContinuePolling = false;
+	iTDRunSetupComplete = false;
+	iServer = NULL;
+	iRunCommandLine = NULL;
+	iServerMutex = NULL;
+	iTDRunMutex = NULL;
+	iExe = KDefaultExe;
+	iPort = KDefaultPort;
+	iPollInterval = KDefaultPoll;
+	}
+
+/*
+ *	Destructor
+ */
+CTestDriverService::~CTestDriverService()
+	{
+	// Let the Listening Server clean itself up
+	Wait( iServerMutex );
+	if( iServerRunning )
+		{
+		iServerRunning = false;
+		}
+	iServer->WaitForThread( -1 );
+	if( iServer != NULL )
+		{
+		delete iServer;
+		iServer = NULL;
+		}
+	Release( iServerMutex );
+	ReleaseMutex( iServerMutex );
+	CloseHandle( iServerMutex );
+
+	// Clean up the TestDriver thread
+	Wait( iTDRunMutex );
+	if( iTestDriverRunning )
+		{
+		iTestDriverRunning = false;
+		}
+	iTestDriverRun->WaitForThread( -1 );
+	if( iTestDriverRun != NULL )
+		{
+		delete iTestDriverRun;
+		iTestDriverRun = NULL;
+		}
+
+	// Cleanup the shared command line
+	if( iRunCommandLine != NULL )
+		{
+		delete [] iRunCommandLine;
+		iRunCommandLine = NULL;
+		}
+	Release( iTDRunMutex );
+	ReleaseMutex( iTDRunMutex );
+	CloseHandle( iTDRunMutex );
+	}
+
+
+/*
+ *	Setup
+ *
+ *   Creates the mutex's requires by this service
+ */
+bool CTestDriverService::Setup()
+	{
+	bool ret = false;
+
+	// Read the ini file configuration if available, otherwise default
+	RetrieveConfig();
+
+	// Create the Listening Server and TestDrive run mutex
+	iServerMutex = CreateMutex( NULL, false, NULL );
+	iTDRunMutex = CreateMutex( NULL, false, NULL );
+
+	if( iServerMutex != NULL && iTDRunMutex != NULL )
+		{
+		ret = true;
+		}
+
+	return ret;
+	}
+
+/*
+ *	RunCommand
+ *
+ *   Extracts the call id and delegates to the required functionality
+ */
+int CTestDriverService::RunCommand( const CCall& aCall )
+	{
+	int		ret		= ERR_INVALID_CALL;
+	bool	callRet	= false;
+
+	// Retrieve the call id
+	int callID = -1;
+	callRet = aCall.CallID( callID );
+	if( callRet )
+		{
+		switch( callID )
+			{
+			case 1: // Build and initiate TestDriver (TestExecute) execution
+				{
+				ret = BuildAndRunTestDriver( aCall );
+				}
+				break;
+			case 2: // Retrieve the TestDriver run execution result
+				{
+				ret = RetrieveTestDriverRunResult();
+				}
+				break;
+			default:
+				{
+				ret = ERR_INVALID_CALL;
+				}
+				break;
+			}
+		}
+
+	return ret;
+	}
+
+/*
+ *	BuildAndRunTestDriver
+ *
+ *   Builds all of the dependancies and starts the execution via TestDriver
+ */
+int	CTestDriverService::BuildAndRunTestDriver( const CCall& aCall )
+	{
+	int ret = ERR_NONE;
+
+	// Test to see if the Listening Server is already running
+	// If running, we wait for it exit.
+	Wait( iServerMutex );
+	if( iServerRunning )
+		{
+		Release( iServerMutex );
+		RetrieveTestDriverRunResult();
+		//ret = ERR_TEST_DRIVER_ALREADY_RUNNING;
+		}
+	else 
+		{
+		Release( iServerMutex );
+		}
+
+	// Retrieve all the parameters
+	
+	// The build command line
+	string buildCommandLine;
+	buildCommandLine += iExe;
+	buildCommandLine += KTDBuild;
+	if( !ret )
+		{
+		ret = AppendCmdLineParams( aCall, buildCommandLine );
+		}
+
+	// The run command line
+	string runCommandLine;
+	runCommandLine += iExe;
+	runCommandLine += KTDRun;
+	if( !ret )
+		{
+		ret = AppendCmdLineParams( aCall, runCommandLine );
+		}
+
+	// Make the TestDriver build call
+	if( !ret )
+		{
+		int tdRet = system( buildCommandLine.c_str() );
+		if( tdRet )
+			{
+			ret = ERR_TEST_DRIVER_BUILD;
+			}
+		}
+
+	if( !ret )
+		{
+		// Append the details for the listening socket 
+		runCommandLine += KSocketFlag;
+		runCommandLine += KTDConnection;
+		runCommandLine += ":";
+		char	portBuf[20];
+		sprintf( portBuf, "%d", iPort );
+		runCommandLine += portBuf;
+
+		if( iRunCommandLine != NULL )
+			{
+			delete [] iRunCommandLine;
+			iRunCommandLine = NULL;
+			}
+
+		// Setup the command line for the execution thread
+		iRunCommandLine = new char[runCommandLine.length()+1];
+		strcpy( iRunCommandLine, runCommandLine.c_str() );
+		}
+
+	// Start the listening server in its own thread
+	if( !ret )
+		{
+		// Set the server running flag to true
+		iServerRunning = true;
+		// Kick off the Listening Server in its own thread
+		iServer = new CAThread( "CTestDriverService::ListeningServer" );
+		int err = 1;
+		TThreadError terr = iServer->StartThread( (void*)CTestDriverService::ListeningServer, NULL, &err ); 
+		if( terr != TE_NONE )
+			{
+			delete iServer;
+			iServer = NULL;
+			ret = ERR_TEST_DRIVER_RUN;
+			}
+		}
+
+	// Launch TestDriver in run mode in its own thread
+	if( !ret )
+		{
+		// Set the TestDriver running flag to true
+		iTestDriverRunning = true;
+		// Kick off TestDriver in its own thread
+		iTestDriverRun = new CAThread( "CTestDriverService::TestDriverRun" );
+		int err = 1;
+		TThreadError terr = iTestDriverRun->StartThread( (void*)CTestDriverService::TestDriverRun, NULL, &err ); 
+		if( terr != TE_NONE )
+			{
+			delete iTestDriverRun;
+			iTestDriverRun = NULL;
+			ret = ERR_TEST_DRIVER_RUN;
+			}
+		}
+
+	// Retrieve the TestDriver run startup result
+	if( !ret )
+		{
+		bool cont = false;
+		while( !cont && iTestDriverRunning )
+			{
+			Sleep( iPollInterval * 1000 );
+			Wait( iServerMutex );
+			iTDRunSetupComplete?cont=true:cont=false;
+			Release( iServerMutex );
+			}
+		Wait( iServerMutex );
+		iTDStartResult>0?ret=0:ret=ERR_TEST_DRIVER_RUN;
+		iTDRunSetupComplete = false;
+		Release( iServerMutex );
+		}
+
+	return ret;
+	}
+
+/*
+ *	RetrieveTestDriverRunResult
+ *
+ *   Retrieves the result upon the TestDriver run completion 
+ */
+int CTestDriverService::RetrieveTestDriverRunResult()
+	{
+	int ret = ERR_NONE;
+	
+	Wait( iServerMutex );
+	// Set the continue polling flag
+	iTDContinuePolling = true;
+	Release( iServerMutex );
+
+	// The ListeningServer thread will now issue TestDriver with the command
+	// to complete and cleanup and the return code will be set from the TestDriverRun
+	// thread when the executable completes.
+
+	// Wait for the TestDriverRun thread to complete
+	bool cont = false;
+	while( !cont )
+		{
+		Sleep( iPollInterval * 1000 );
+		Wait( iTDRunMutex );
+		iTestDriverRunning?cont=false:cont=true;
+		Release( iTDRunMutex );
+		}
+
+	// Cleanup the threads as they have now completed
+	Wait( iServerMutex );
+	iServerRunning = false;
+	Release( iServerMutex );
+
+	Wait( iTDRunMutex );
+	iTestDriverRunning = false;
+	Release( iTDRunMutex );
+
+	// Now the TestDriver executable has complete return the 
+	// appropriate error code
+	if( iTDCompleteResult < 0 )
+		{
+		ret = ERR_TEST_DRIVER_RUN_COMPLETE;
+		}
+
+	return ret;
+	}
+
+/*
+ *	ListeningServer
+ *
+ *    Runs the Listening Server
+ *      Controlled via the main/TestDriver run thread
+ */
+void CTestDriverService::ListeningServer( void )
+	{
+	// Create a new CListeningServer
+	CListeningServer* server = new CListeningServer();
+	if( server != NULL )
+		{
+		// Open it an wait until TestDriver has connected
+		int err = server->Open( iPort );
+
+		// Continue if TestDriver connected successfully and the server is set to running
+		// Retrieve the TestDriver execution startup result
+		// Loop until told to stop
+		if( !err )
+			{
+			int recvInt = 0;
+			iTDStartResult = 0;
+			bool cont = true;
+			while( cont )
+				{
+				Wait( iServerMutex );
+
+				// Attempt to recieve the TestDriver startup code
+				// This recieve call can timeout and we continue retrying
+				err = server->Recieve( recvInt );
+				if( !err )
+					{
+					// Set the TestDriver run startup result
+					iTDStartResult = recvInt;
+					iTDRunSetupComplete = true;
+					Release( iServerMutex );
+					break;
+					}
+				iServerRunning?cont=true:false;
+				Release( iServerMutex );
+				}
+			}
+
+		// Check to see that TestDriver has returned a run number.
+		// If it hasn't then the startup has failed.
+		if( iTDStartResult > 0 )
+			{
+			// Wait until the continue polling flag has been set
+			bool cont = true;
+			while( !err && cont )
+				{
+				Wait( iServerMutex );
+				if( iTDContinuePolling )
+					{
+					err = server->Send( KContinuePollingValue );
+					// Reset the polling flag
+					iTDContinuePolling = false;
+					Release( iServerMutex );
+					break;
+					}
+				Release( iServerMutex );
+				Sleep( iPollInterval * 1000 );
+				Wait( iServerMutex );
+				iServerRunning?cont=true:cont=false;
+				Release( iServerMutex );
+				}
+			}
+		server->Close();
+		}
+
+	delete server;
+	server = NULL;
+	Wait( iServerMutex );
+	iServerRunning = false;
+	Release( iServerMutex );
+	}
+
+/*
+ *	TestDriverRun
+ *
+ *    Executes the run command for TestDriver
+ */
+void CTestDriverService::TestDriverRun( void )
+	{
+	Wait( iTDRunMutex );
+	// Launch TestDriver
+	if( iRunCommandLine != NULL )
+		{
+		iTDCompleteResult = system( iRunCommandLine );
+		}
+	else
+		{
+		iTDCompleteResult = -1;
+		}
+
+	// Reset the status to not running
+	iTestDriverRunning = false;
+	Release( iTDRunMutex );
+	}
+
+/*
+ *	Wait
+ *
+ *    For synchronisation
+ */
+void CTestDriverService::Wait( HANDLE aMutexHandle )
+	{
+	WaitForSingleObject( aMutexHandle, INFINITE );
+	}
+
+/*
+ *	Release
+ *
+ *    For synchronisation
+ */
+void CTestDriverService::Release( HANDLE aMutexHandle )
+	{
+	ReleaseMutex( aMutexHandle );
+	}
+
+
+void CTestDriverService::RetrieveConfig()
+	{
+	bool ret = false;
+
+	// Load the configuration information file
+	CUCCIniFile iniFile( KTDServiceIni );
+
+	// Retrieve the port to be used
+	int port;
+	if( iniFile.KeyValue(KIniPort, KIniSectionName, port) )
+		{
+		iPort = port;
+		}
+
+	// Retrieve the exe location/filename
+	string exe;
+	if( iniFile.KeyValue(KIniExeLocation, KIniSectionName, exe) )
+		{
+		iExe = exe;
+		}
+
+	// Retrieve the poll interval
+	int pollInterval;
+	if( iniFile.KeyValue(KIniPollInterval, KIniSectionName, pollInterval) )
+		{
+		iPollInterval = pollInterval;
+		}
+	}
+
+
+int CTestDriverService::AppendCmdLineParams( const CCall& aCall, string &aCmdLine )
+	{
+	int ret = ERR_NONE;
+
+	int numParams = 0;
+	bool callRet = aCall.Params( numParams );
+	if( !ret && callRet && numParams >= 3 )
+		{
+		for( int index=0 ; index<numParams && callRet && !ret ; index++ )
+			{
+			// Retrieve the PLATFORM parameters
+			string name;
+			string value;
+			callRet = aCall.Name( index, name );
+			if( callRet )
+				{
+				callRet = aCall.Value( index, value );
+				}
+			
+			if( callRet )
+				{
+				if( name == KPlatform )
+					{
+					aCmdLine += KPlatformFlag;
+					aCmdLine += value;
+					}
+				else if( name == KBuild )
+					{
+					aCmdLine += KBuildFlag;
+					aCmdLine += value;
+					}
+				else if( name == KSuite )
+					{
+					aCmdLine += KSuiteFlag;
+					aCmdLine += value;
+					}
+				else if( name == KTransport )
+					{
+					aCmdLine += KTransportFlag;
+					aCmdLine += value;
+					}
+				else if( name == KLogging )
+					{
+					aCmdLine += KLoggingFlag;
+					aCmdLine += value;
+					}
+				else
+					{
+					ret = ERR_INVALIDARG;
+					}
+				}
+			else
+				{
+					ret = ERR_INVALIDARG;
+				}
+			}
+		}
+	else
+		{
+			ret = ERR_INVALIDARG;
+		}
+	
+	return ret;
+	}