testexecmgmt/ucc/Source/Uccs.v2/Core/UCCS_CBatchEngine.cpp
changeset 0 3da2a79470a7
equal deleted inserted replaced
-1:000000000000 0:3da2a79470a7
       
     1 /*
       
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 * Filename: UCCS_CBatchEngine.cpp
       
    16 * System Includes
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 
       
    22 #include <stdio.h>
       
    23 #include <stdlib.h>
       
    24 #include <assert.h>
       
    25 #include <io.h>
       
    26 
       
    27 
       
    28 /***********************************************************************************
       
    29  *
       
    30  * Local Includes
       
    31  *
       
    32  **********************************************************************************/
       
    33 #include "UCCS_CBatchEngine.h"
       
    34 #include "UCCS_ErrorCodes.h"
       
    35 
       
    36 
       
    37 /***********************************************************************************
       
    38  *
       
    39  * Definitions
       
    40  *
       
    41  **********************************************************************************/
       
    42 #define IS_WHITESPACE(c)			(((c) == '\t')||((c) == '\n')||((c) == ' '))
       
    43 #define MAXCOMMANDLENGTH			2048
       
    44 
       
    45 
       
    46 /***********************************************************************************
       
    47  *
       
    48  * Definitions
       
    49  *
       
    50  **********************************************************************************/
       
    51 DWORD WINAPI ThreadProc(LPVOID lpParameter);
       
    52 
       
    53 
       
    54 /***********************************************************************************
       
    55  *
       
    56  * PUBLIC METHOD: Construction
       
    57  *
       
    58  **********************************************************************************/
       
    59 CBatchEngine::CBatchEngine( IRetrieveCommand *aRetrieveCommand, IOutput *aOutput )
       
    60 {
       
    61 	// check parameters
       
    62 	assert( aRetrieveCommand != NULL );
       
    63 	assert( aOutput != NULL );
       
    64 
       
    65 	// init the vars
       
    66 	iRetrieveCommand = aRetrieveCommand;
       
    67 	iOutput = aOutput;
       
    68 
       
    69 	// set all other state
       
    70 	iExecutionThreadState = ETS_IDLE;
       
    71 	iControlThreadState = CTS_IDLE;
       
    72 
       
    73 	// the rest are set according to the state -- for idle their value is irrelevant 
       
    74 	// but I'd like to set them anyway for completeness
       
    75 	iLastError = 0;
       
    76 	iSync = NULL;
       
    77 	iUsecaseID = INVALID_USECASE_ID;
       
    78 	hThreadHandle = NULL;
       
    79 	iExecuteCommand = NULL;
       
    80 }
       
    81 
       
    82 
       
    83 /***********************************************************************************
       
    84  *
       
    85  * PUBLIC METHOD: Destruction
       
    86  *
       
    87  **********************************************************************************/
       
    88 CBatchEngine::~CBatchEngine()
       
    89 {
       
    90 	// clean up any memory holding state variables
       
    91 	if( iExecuteCommand != NULL ) {
       
    92 		delete iExecuteCommand;
       
    93 		iExecuteCommand = NULL;
       
    94 	}
       
    95 	if( hThreadHandle != NULL ) {
       
    96 		CloseHandle(hThreadHandle);
       
    97 		hThreadHandle = NULL;
       
    98 	}
       
    99 	if( iSync != NULL ) {
       
   100 		delete iSync;
       
   101 		iSync = NULL;
       
   102 	}
       
   103 }
       
   104 
       
   105 
       
   106 /***********************************************************************************
       
   107  *
       
   108  * PUBLIC METHOD: StartUseCase
       
   109  *
       
   110  **********************************************************************************/
       
   111 int CBatchEngine::StartUsecase( int aUsecaseID )
       
   112 {
       
   113 	int err;
       
   114 	DWORD dwThreadID;
       
   115 
       
   116 	// check that the control thread is currently in idle
       
   117 	if( iControlThreadState != CTS_IDLE ) {
       
   118 		return UCCS_ALREADYSTARTEDUSECASE;
       
   119 	}
       
   120 	assert( iExecutionThreadState == ETS_IDLE );
       
   121 
       
   122 	// ask the retriever to get the use-case description
       
   123 	err = iRetrieveCommand->StartUseCase( aUsecaseID );
       
   124 	if( err != UCCS_OK ) {
       
   125 		return err;
       
   126 	}
       
   127 
       
   128 	// set all the state appropriatley
       
   129 	assert( iSync == NULL );
       
   130 	iSync = new CSynchronisation( iOutput );
       
   131 	assert( iSync != NULL );
       
   132 	assert( iExecuteCommand == NULL );
       
   133 	iExecuteCommand = new CExecuteCommand( iSync, iOutput );
       
   134 	assert( iExecuteCommand != NULL );	
       
   135 	iLastError = 0;
       
   136 	iUsecaseID = aUsecaseID;
       
   137 
       
   138 	// set the state
       
   139 	iExecutionThreadState = ETS_EXECUTING_SCRIPT;
       
   140 	iControlThreadState = CTS_USECASE_STARTED;
       
   141 
       
   142 	// output that we have started
       
   143 	iOutput->StartUsecase( aUsecaseID );
       
   144 
       
   145 	// start the thread that goes and executes the steps
       
   146 #ifndef TESTCASEBATCH
       
   147 	hThreadHandle = CreateThread( NULL, 0, ThreadProc, this, 0,	&dwThreadID );		
       
   148 #else
       
   149 	hThreadHandle = 0;
       
   150 #endif
       
   151 	if( hThreadHandle == 0 ) {
       
   152 		delete iSync;
       
   153 		iSync = NULL;
       
   154 		delete iExecuteCommand;
       
   155 		iExecuteCommand = NULL;
       
   156 		iUsecaseID = INVALID_USECASE_ID;
       
   157 		iExecutionThreadState = ETS_IDLE;
       
   158 		iControlThreadState = CTS_IDLE;
       
   159 		return UCCS_FAILEDTOCREATEEXECUTETHREAD;
       
   160 	}
       
   161 
       
   162 	// done - return OK to the external controller
       
   163 	return UCCS_OK;
       
   164 }
       
   165 
       
   166 
       
   167 /***********************************************************************************
       
   168  *
       
   169  * PUBLIC METHOD: EndUsecase
       
   170  *
       
   171  **********************************************************************************/
       
   172 int CBatchEngine::EndUsecase( int aUsecaseID, int aResult, int *aScriptResult )
       
   173 {
       
   174 	int err;
       
   175 
       
   176 	// check that the control thread is in the correct state
       
   177 	if( iControlThreadState != CTS_USECASE_STARTED ) {
       
   178 		*aScriptResult = UCCS_NOUSECASERUNNING;
       
   179 		return UCCS_NOUSECASERUNNING;
       
   180 	}
       
   181 
       
   182 	// update the state of the control thread to ended -- this will cause the execution
       
   183 	// thread to exit on it's next iteration. 
       
   184 	iControlThreadState	= CTS_USECASE_ENDED;
       
   185 
       
   186 	// We clear the synchronisation so that if the execution thread is (or is just about 
       
   187 	// to) wait on a semaphore then it will not get stuck forever
       
   188 	iSync->ClearSynchronisation();
       
   189 
       
   190 	// Wait for the thread to really exit
       
   191 	err = WaitForSingleObject( hThreadHandle, INFINITE );
       
   192 	if( err != WAIT_OBJECT_0 ) {
       
   193 		iOutput->Error( UCCS_SYSTEMERROR, "An error occured while waiting for the executing script thread to finish." );
       
   194 	}
       
   195 	CloseHandle( hThreadHandle );
       
   196 	hThreadHandle = NULL;
       
   197 
       
   198 	// cleanup the rest of the state 
       
   199 	assert( iExecutionThreadState == ETS_IDLE );
       
   200 	iControlThreadState = CTS_IDLE;
       
   201 	delete iSync;	
       
   202 	iSync = NULL;
       
   203 	delete iExecuteCommand;
       
   204 	iExecuteCommand = NULL;
       
   205 	iUsecaseID = INVALID_USECASE_ID;
       
   206 	
       
   207 	// output that endusecase has been called
       
   208 	iOutput->EndUsecase( aUsecaseID, aResult );
       
   209 
       
   210 	// done -- return the information
       
   211 	*aScriptResult = iLastError;
       
   212 	iLastError = 0;
       
   213 	return UCCS_OK;
       
   214 }
       
   215 
       
   216 /***********************************************************************************
       
   217  *
       
   218  * PUBLIC METHOD: GetVariableName
       
   219  *
       
   220  **********************************************************************************/
       
   221 int CBatchEngine::GetEnvVariable( char *aVariableName, char *aOutputBuffer, int aOutputBufferLen ) 
       
   222 {
       
   223 	// check params
       
   224 	assert ( aVariableName != NULL );
       
   225 	assert ( aOutputBuffer != NULL );
       
   226 	assert ( aOutputBufferLen > 0 );
       
   227 
       
   228 	// check that there is an actual usecase running
       
   229 	if( iControlThreadState != CTS_USECASE_STARTED ) {
       
   230 		return UCCS_NOUSECASERUNNING;
       
   231 	}
       
   232 	
       
   233 	// check that there is actually a command around
       
   234 	if( iExecuteCommand == NULL ) {
       
   235 		return UCCS_COMMANDEXECUTIONNOTSTARTEDYET;
       
   236 	}
       
   237 
       
   238 	// change aVariableName to uppercase -a s it is stored in the data record as uppercase.
       
   239 	_strupr( aVariableName );
       
   240 
       
   241 	// now go get the environment var
       
   242 	return iExecuteCommand->GetEnvironmentVariable( aVariableName, aOutputBuffer, aOutputBufferLen );
       
   243 }
       
   244 
       
   245 /***********************************************************************************
       
   246  *
       
   247  * PUBLIC METHOD: RunCommand
       
   248  *
       
   249  **********************************************************************************/
       
   250 int CBatchEngine::RunCommand( char* aCommandLine )
       
   251 {
       
   252 	// check params
       
   253 	assert ( aCommandLine != NULL );
       
   254 
       
   255 	// check that there is actually a command around
       
   256 	if( iSync == NULL ) {
       
   257 		iSync = new CSynchronisation( iOutput );
       
   258 	}
       
   259 	if( iExecuteCommand == NULL ) {
       
   260 		iExecuteCommand = new CExecuteCommand( iSync, iOutput );
       
   261 	}
       
   262 
       
   263 	// now go get the environment var
       
   264 	return iExecuteCommand->ExecuteCommand( aCommandLine );
       
   265 }
       
   266 /***********************************************************************************
       
   267  *
       
   268  * PUBLIC METHOD: Signal
       
   269  *
       
   270  **********************************************************************************/
       
   271 
       
   272 int CBatchEngine::Signal( int aUsecaseID )
       
   273 {
       
   274 	// check that the state is valid
       
   275 	if( iControlThreadState != CTS_USECASE_STARTED ) {
       
   276 		return UCCS_NOUSECASERUNNING;
       
   277 	}
       
   278 	return iSync->SignalFromDevice();
       
   279 }
       
   280 
       
   281 
       
   282 /***********************************************************************************
       
   283  *
       
   284  * PUBLIC METHOD: Rendezvous
       
   285  *
       
   286  **********************************************************************************/
       
   287 int CBatchEngine::Rendezvous( int aUseCaseID )
       
   288 {
       
   289 	// check that the control state is valid
       
   290 	if( iControlThreadState != CTS_USECASE_STARTED ) {
       
   291 		return UCCS_NOUSECASERUNNING;
       
   292 	}
       
   293 
       
   294 	// check that the execution thread is still running
       
   295 	if( iExecutionThreadState != ETS_EXECUTING_SCRIPT ) {
       
   296 		return UCCS_SCRIPTFINISHED;
       
   297 	}
       
   298 
       
   299 	// do the sync
       
   300 	return iSync->RendezvousFromDevice();
       
   301 }
       
   302 
       
   303 
       
   304 /***********************************************************************************
       
   305  *
       
   306  * PUBLIC METHOD: Wait
       
   307  *
       
   308  **********************************************************************************/
       
   309 int CBatchEngine::Wait( int aUseCaseID )
       
   310 {
       
   311 	// check that the control state is valid
       
   312 	if( iControlThreadState != CTS_USECASE_STARTED ) {
       
   313 		return UCCS_NOUSECASERUNNING;
       
   314 	}
       
   315 
       
   316 	// check that the execution thread is still running
       
   317 	if( iExecutionThreadState != ETS_EXECUTING_SCRIPT ) {
       
   318 		return UCCS_SCRIPTFINISHED;
       
   319 	}
       
   320 
       
   321 	// do the sync
       
   322 	return iSync->WaitFromDevice();
       
   323 }
       
   324 
       
   325 
       
   326 /***********************************************************************************
       
   327  *
       
   328  * PUBLIC METHOD: ExecuteScript
       
   329  *
       
   330  **********************************************************************************/
       
   331 int CBatchEngine::ExecuteScript( void )
       
   332 {
       
   333 	int err;
       
   334 	char *c;
       
   335 	char command_buffer[MAXCOMMANDLENGTH];
       
   336 	int rv = 0;
       
   337 
       
   338 	// execute all the commands 
       
   339 	while( 1 ) {
       
   340 
       
   341 		// if the controller has ended the usecase then we stop executing commands
       
   342 		if( iControlThreadState != CTS_USECASE_STARTED ) {
       
   343 			break;
       
   344 		}
       
   345 
       
   346 		// get the next command to execute
       
   347 		err = iRetrieveCommand->GetNextCommand( command_buffer, MAXCOMMANDLENGTH );
       
   348 		if( err == UCCS_NOMORECOMMANDS ) {
       
   349 			iOutput->CompletedScript();
       
   350 			break;
       
   351 		} 
       
   352 		assert( err == UCCS_OK );
       
   353 		
       
   354 		// NOTE: the code below is the correct implementation of handling generic errors from the input 
       
   355 		// module. It has been taken out because the input modules don't return anything except UCCS_NOMORECOMMANDS
       
   356 		// and UCCS_OK so there is no way to test the condition (and it messes up our coverage results!). But
       
   357 		// if new error codes are put in this implementation should be used.
       
   358 //			else if( err != UCCS_OK ) {
       
   359 //			iOutput->Error( err, "GetNextCommand returned error. Stopping script execution." );
       
   360 //			rv = err;
       
   361 //			break;
       
   362 //		}
       
   363 
       
   364 		// if the first not whitespace char is 0, or #, or // then return the comment
       
   365 		for( c = command_buffer; IS_WHITESPACE(*c); c++ ) 
       
   366 			;
       
   367 		if( (*c == 0) || (*c == '#') || ((c[0] == '/') && (c[1] == '/'))) {
       
   368 			continue;
       
   369 		}
       
   370 
       
   371 		// now execute the command 
       
   372 		iOutput->ExecuteString( c );
       
   373 		err = iExecuteCommand->ExecuteCommand( c );
       
   374 		iOutput->ExecuteStringResult( err );
       
   375 		if( (err != UCCS_OK) && (err != UCCS_QUIT) ) {
       
   376 			iOutput->Error( err, NULL );
       
   377 		}
       
   378 
       
   379 		// if the return value from the command was quit (i.e. the script had a 
       
   380 		// quit command) then we print the message and break from the loop.
       
   381 		if( err == UCCS_QUIT ) {
       
   382 			iOutput->CompletedScript();
       
   383 			break;
       
   384 		}
       
   385 
       
   386 		// save the last error -- this is so we can notify the device is an error occured
       
   387 		if( err != UCCS_OK ) {
       
   388 			iLastError = err;
       
   389 		}
       
   390 
       
   391 		// if we do a require or requirenot that fails then make a point about it!
       
   392 		if( (err == UCCS_REQUIREDVALUEERROR) || (err == UCCS_REQUIREDVALUEINCORRECT) || (err == UCCS_REQUIREDNOTVALUEERROR) || (err == UCCS_REQUIREDNOTVALUEMATCH) ) {
       
   393 			// should break out here -- problem is that at the moment there are no reset calls so we can't recover!!
       
   394 		}		
       
   395 	}
       
   396 
       
   397 	// set the state of this thread to completed and clear the synchronisation state so that
       
   398 	// the control thread won't wait forever. The state of the execution thread should stop
       
   399 	// the control thread from being able to wait again
       
   400 	iExecutionThreadState = ETS_COMPLETED_SCRIPT;
       
   401 	iSync->ClearSynchronisation();
       
   402 
       
   403 	// tell the input module that we are done with it
       
   404 	err = iRetrieveCommand->EndUseCase();
       
   405 	assert( err == UCCS_OK );
       
   406 
       
   407 	// set the state to idle 
       
   408 	iExecutionThreadState = ETS_IDLE;
       
   409 
       
   410 	// done
       
   411 	return rv;
       
   412 }
       
   413 			
       
   414 
       
   415 /***********************************************************************************
       
   416  *
       
   417  * FUNCTION: Entry point for second thread -- call executescript on the passed
       
   418  * batch engine object.
       
   419  *
       
   420  **********************************************************************************/
       
   421 DWORD WINAPI ThreadProc(LPVOID lpParameter)
       
   422 {	
       
   423 	CBatchEngine* aLocalBatchEngine;
       
   424 	aLocalBatchEngine = (CBatchEngine*)lpParameter;
       
   425 	return aLocalBatchEngine->ExecuteScript();
       
   426 }
       
   427 
       
   428