diff -r 7fdc9a71d314 -r 8ad140f3dd41 stif/TestServer/src/TestServer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stif/TestServer/src/TestServer.cpp Wed Oct 13 16:17:58 2010 +0300 @@ -0,0 +1,976 @@ +/* +* Copyright (c) 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: This module contains implementation of CTestServer +* class member functions. +* +*/ + +// INCLUDE FILES +#include +#include +#include "TestEngineClient.h" +#include +#include +#include "TestServer.h" +#include "TestServerCommon.h" +#include + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS + +// MACROS + +// LOCAL CONSTANTS AND MACROS + +// MODULE DATA STRUCTURES + +// Struct to pass parameters to server thread +struct TThreadStartTestServer + { + TFileName iName; // Server name + RThread iServerThread; // The server thread + RSemaphore iStarted; // Startup syncronisation semaphore + TBool iInNewThread; // Is thread running in new process? + TInt iStartupResult;// Start-up result + TBool iUiTesting; // Is it testserver for UI testing + CTestThreadContainerRunnerFactory* iTestThreadContainerRunnerFactory; // Pointer to CTestThreadContainerRunner. Defined when + // iUiTesting is true + }; + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + +// ==================== LOCAL FUNCTIONS ======================================= + +// None + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: PanicServer + + Description: Panics the server. + + Parameters: const TTestServerPanic aPanic: in: Panic code + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestServer::PanicServer( const TTestServerPanic aPanic ) + { + +#ifdef USE_LOGGER + // Check if logger is available, if so, use it. + CStifLogger* log = (CStifLogger*) Dll::Tls(); + if ( log ) + { + log->Log( CStifLogger::ERed, _L("TestServer.DLL Panic %d"), aPanic); + } +#endif + + RDebug::Print( _L( "CTestServer::PanicServer" ) ); + _LIT( KTxtTestServer,"CTestServer" ); + User::Panic( KTxtTestServer,aPanic ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: NewL + + Description: Returns new CTestServer object + + Parameters: const TFileName& aName: in: Server name + + Return Values: None + + Errors/Exceptions: Leaves if memory allocation, ConstructL or StartL leaves. + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestServer* CTestServer::NewL( const TFileName& aName ) + { + + CTestServer* self = new( ELeave ) CTestServer(); + CleanupStack::PushL( self ); + + // Construct the server + self->ConstructL( aName ); + + // Start the server + self->StartL( aName ); + + CleanupStack::Pop( self ); + + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: ConstructL + + Description: Second level constructor. Obtains pointer to library + entrypoint. + + Parameters: const TFileName& aName: in: Server name + + Return Values: None + + Errors/Exceptions: Leaves if entrypoint can't be obtained. + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestServer::ConstructL( const TFileName& aName ) + { + // Construct heap buffer for configuration file + iModuleNameBuffer = HBufC::NewL( aName.Length() ); + iModuleName.Set ( iModuleNameBuffer->Des() ); + iModuleName.Copy ( aName ); + + iContainerIndex = CObjectConIx::NewL(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: CTestServer + + Description: Constructor. + + Initialises non-zero member variables and base class with correct + priority. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestServer::CTestServer() : CServer2( CTestServer::ETestServerPriority ), + iModuleName(0, 0), + iSessionCount( 0 ) + { + iFirstTime = ETrue; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: ~CTestServer + + Description: Destructor + Frees memory. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestServer::~CTestServer() + { + + delete iModuleNameBuffer; + iModuleNameBuffer = NULL; + + delete iContainerIndex; + iContainerIndex = NULL; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: NewContainerL + + Description: Returns new container. Used to store subsessions + + Parameters: None + + Return Values: CObjectCon* New object container + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CObjectCon* CTestServer::NewContainerL() + { + + CObjectCon* container = iContainerIndex->CreateL(); + + iSessionCount++; + + return container; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: DeleteContainer + + Description: Deletes a container. + + Parameters: CObjectCon* aContainer: in: Container to be removed + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestServer::DeleteContainer( CObjectCon* aContainer ) + { + iContainerIndex->Remove( aContainer ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: SessionClosed + + Description: Inform Server that session is closed. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestServer::SessionClosed() + { + // Decrease session count + iSessionCount--; + + // Check if last session is closed + if ( iSessionCount <= 0 ) + { + // Stop the active scheduler + // Execution will continue in ThreadFunction() + CActiveScheduler::Stop(); + } + + } +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: NewSessionL + + Description: Returns new session. + + Parameters: const TVersion &aVersion: in: Version required + + Return Values: CSharableSession* New session + + Errors/Exceptions: Leaves if invalid version or CTestModule construction + leaves + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CSession2* CTestServer::NewSessionL( const TVersion& aVersion, + const RMessage2& /*aMessage*/ ) const + { + // check version is ok + TVersion v( KTestServerMajorVersionNumber, + KTestServerMinorVersionNumber, + KTestServerBuildVersionNumber + ); + if( !User::QueryVersionSupported( v,aVersion ) ) + { + User::Leave( KErrNotSupported ); + } + + return CTestModule::NewL( ( CTestServer* ) this ); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: ModuleName + + Description: Returns module name + + Parameters: None + + Return Values: const TDesC&* Module name + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +const TDesC& CTestServer::ModuleName() const + { + return iModuleName; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: FirstTime + + Description: Is module already once initialised. + + Parameters: None + + Return Values: TBool Has module initialized? + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +//@spe const TBool CTestServer::FirstTime() const +TBool CTestServer::FirstTime() const + { + return iFirstTime; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: ClearFirstTime + + Description: Clear module first time flag. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestServer::ClearFirstTime() + { + iFirstTime = EFalse; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: ThreadFunction + + Description: The thread function, where Test Server lives in + + Parameters: TAny* aStarted: in: Start-up information + + Return Values: TInt Result from test module + + Errors/Exceptions: Clean-up stack can't be created because cannot + leave, error checks are done locally. + Panics if: + invalid start-up information + Test Server can't be started + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestServer::ThreadFunction( TAny* aStarted ) + { + + __UHEAP_MARK; + + TInt error( KErrNone ); + + // Get start-up information + TThreadStartTestServer* startInfo = ( TThreadStartTestServer* ) aStarted; + __ASSERT_ALWAYS( startInfo,PanicServer( ENoStartupInformation ) ); + + // Create clean-up stack + CTrapCleanup* tc = CTrapCleanup::New(); + __ASSERT_ALWAYS( tc, PanicServer(ECreateTrapCleanup)); + + // Construct the logger + TName path = _L("C:\\logs\\testframework\\testserver\\"); + TFileName name = _L("testserver_"); + name.Append ( startInfo->iName ); + + // Create logger, in Wins use HTML in HW default logger + TLoggerSettings loggerSettings; + + // Directory must create by hand if test server log wanted + loggerSettings.iCreateLogDirectories = EFalse; + + loggerSettings.iOverwrite = ETrue; + loggerSettings.iTimeStamp = ETrue; + loggerSettings.iLineBreak = ETrue; + loggerSettings.iEventRanking = EFalse; + loggerSettings.iThreadId = EFalse; + loggerSettings.iHardwareFormat = CStifLogger::ETxt; +#ifndef FORCE_STIF_INTERNAL_LOGGING_TO_RDEBUG + loggerSettings.iEmulatorFormat = CStifLogger::EHtml; + loggerSettings.iHardwareOutput = CStifLogger::EFile; + loggerSettings.iEmulatorOutput = CStifLogger::EFile; +#else + RDebug::Print( _L( "STIF Test Server logging forced to RDebug" ) ); + loggerSettings.iEmulatorFormat = CStifLogger::ETxt; + loggerSettings.iHardwareOutput = CStifLogger::ERDebug; + loggerSettings.iEmulatorOutput = CStifLogger::ERDebug; +#endif + loggerSettings.iUnicode = EFalse; + loggerSettings.iAddTestCaseTitle = EFalse; + + CStifLogger* logger = NULL; + TRAP ( error, logger = CStifLogger::NewL( path, name, loggerSettings ) ); + + // Thread Local Storage is used for get pointer to logger. + Dll::SetTls ( logger ); + + __TRACE( KInit,( _L( "TestServer.DLL server starting" ) ) ); + __TRACE( KInit,( CStifLogger::EBold, _L( "Loading module: %S"), &startInfo->iName ) ); + + RLibrary module; + TInt ret = KErrNone; + + TFileName newNameBuffer; + TInt check = CheckModuleName( startInfo->iName, newNameBuffer ); + if( check == KErrNone ) + { + // Load the module(TestScripter) + ret = module.Load( newNameBuffer ); + } + else + { + RemoveOptionalIndex(startInfo->iName, newNameBuffer); + __TRACE(KInit, (CStifLogger::EBold, _L( "Valid module name is [%S] (extracted from [%S])"), &newNameBuffer, &startInfo->iName)); + // Load the module(Others) + ret = module.Load(newNameBuffer); + } + + // If test module loading fails, do not start server + if( ret != KErrNone ) + { + __TRACE( KError,( CStifLogger::ERed, _L( "Test module loading failed, code = %d" ), ret ) ); + __TRACE( KError,( _L( "Check that module is compiled properly and stored to correct directory and all DLLs that it requires are available" ) ) ); + + // Error will be handled in StartNewServer + startInfo->iStartupResult = ret; + startInfo->iStarted.Signal(); + if ( !startInfo->iInNewThread ) + { + startInfo->iStarted.Close(); + } + module.Close(); + Dll::FreeTls(); + // Delete logger + delete logger; + logger = NULL; + // Delete clean-up stack + delete tc; + tc = NULL; + __UHEAP_MARKEND; + return ret; + } + else + { + __TRACE( KInit,( _L( "Test module loaded correctly" ) ) ); + } + + // Verify that there is function + CTestInterfaceFactory libEntry = ( CTestInterfaceFactory ) module.Lookup( 1 ); + if( libEntry == NULL ) + { + // Error will be handled in StartNewServer + __TRACE( KError,( CStifLogger::ERed, _L( "Can't find entrypoint from test module" ) ) ); + + startInfo->iStartupResult = KErrNotFound; + startInfo->iStarted.Signal(); + if ( !startInfo->iInNewThread ) + { + startInfo->iStarted.Close(); + } + module.Close(); + Dll::FreeTls(); + // Delete logger + delete logger; + logger = NULL; + // Delete clean-up stack + delete tc; + tc = NULL; + __UHEAP_MARKEND; + return KErrNotFound; + } + + module.Close(); + + // Construct and install active scheduler + CActiveScheduler* scheduler = new CActiveScheduler; + __ASSERT_ALWAYS( scheduler, PanicServer( EMainSchedulerError ) ); + CActiveScheduler::Install( scheduler ); + + // Construct server + CTestServer* server = NULL; + TRAPD( err, server = CTestServer::NewL( startInfo->iName ) ); + __ASSERT_ALWAYS( !err, PanicServer( ESvrCreateServer ) ); + + server->iUiTesting = startInfo->iUiTesting; + server->iTestThreadContainerRunnerFactory = startInfo->iTestThreadContainerRunnerFactory; + + // Inform that we are up and running + startInfo->iStartupResult = KErrNone; + startInfo->iStarted.Signal(); + if ( !startInfo->iInNewThread ) + { + startInfo->iStarted.Close(); + } + + // Start handling requests + CActiveScheduler::Start(); + + // Execution continues from here after CActiveScheduler::Stop + + __TRACE( KVerbose,( _L( "TestServer.DLL active scheduler stopped" ) ) ); + + // Delete the server + delete server; + server = NULL; + __TRACE( KVerbose,( _L( "TestServer.DLL server object deleted" ) ) ); + + delete scheduler; + scheduler = NULL; + __TRACE( KVerbose,( _L( "Active scheduler deleted" ) ) ); + + __TRACE ( KInit, (_L("TestServer.DLL ThreadFunction exiting, server closing")) ); + + Dll::FreeTls(); + // Delete logger + delete logger; + logger = NULL; + // Delete clean-up stack + delete tc; + tc = NULL; + + __UHEAP_MARKEND; + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: GetServerThreadId + + Description: Returns server thread id + + Parameters: None + + Return Values: TInt : thread id + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestServer::GetServerThreadId() + { + RThread thread; + return thread.Id(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: GetTestThreadContainerRunnerFactory + + Description: Returns server thread id + + Parameters: None + + Return Values: TInt : thread id + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestThreadContainerRunnerFactory* CTestServer::GetTestThreadContainerRunnerFactory() + { + + return iTestThreadContainerRunnerFactory; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: UiTesting + + Description: Gets information if testserver supports UI testing + + Parameters: None + + Return Values: True if testserver supports UI testing, False if not. + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TBool CTestServer::UiTesting() + { + + return iUiTesting; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestServer + + Method: GetUiEnvProxy + + Description: Gets UIEnvProxy + + Parameters: None + + Return Values: Pointer to UIEnvProxy. + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CUiEnvProxy* CTestServer::GetUiEnvProxy() + { + + return iTestThreadContainerRunnerFactory->GetUiEnvProxy(); + } + + +// ================= OTHER EXPORTED FUNCTIONS ================================= + +/* +------------------------------------------------------------------------------- + + Class: - + + Method: StartNewServer + + Description: Starts a new server. Server will be running its own + thread and this functions returns when server is up and running or + server start-up fails. + + Parameters: const TFileName& aModuleFileName: in: Module name + TFileName& aServerName: in: Server name + const TBool aInNewThread: in: Is new thread + RSemaphore aSynchronisation: in: For synchronisation + TBool aUiTestingServer: in: Indicates if testserver should support UI testing + CTestThreadContainerRunnerFactory* aTestThreadContainerRunnerFactory: in: Pointer to runner factory + + Return Values: TInt: Symbian error code + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +EXPORT_C TInt StartNewServer( const TFileName& aModuleFileName, + TFileName& aServerName, + const TBool aInNewThread, + RSemaphore aSynchronisation, + TBool aUiTestingServer, + CTestThreadContainerRunnerFactory* aTestThreadContainerRunnerFactory + ) + { + + __UHEAP_MARK; + + //Check server not already started + TFindServer findServer( aModuleFileName ); + TFullName name; + if( findServer.Next( name ) == KErrNone ) + { + // Server already started, nothing to do + aServerName = aModuleFileName; + __UHEAP_MARKEND; + return KErrAlreadyExists; + } + + // Construct start-up information object + TThreadStartTestServer* startInfo = new TThreadStartTestServer(); + if( startInfo == NULL ) + { + __UHEAP_MARKEND; + return KErrNoMemory; + } + + // Fill the start-up information + startInfo->iName = aModuleFileName; + startInfo->iStartupResult = KErrNone; + startInfo->iStarted = aSynchronisation; + startInfo->iInNewThread = aInNewThread; + startInfo->iUiTesting = aUiTestingServer; + startInfo->iTestThreadContainerRunnerFactory = aTestThreadContainerRunnerFactory; + + // EKA1 + if ( aInNewThread ) + { + // Create thread + TInt res = startInfo->iServerThread.Create( + startInfo->iName , // Name of thread + CTestServer::ThreadFunction, // Thread function + KDefaultStackSize, // Stack size + KDefaultHeapSize, // Heap initial size + KMaxHeapSize, // Heap start max size + startInfo // Parameter to thread function + ); + + // If thread creation failed + if( res != KErrNone ) + { + startInfo->iStarted.Close(); // Close semaphore + delete startInfo; + startInfo = NULL; + __UHEAP_MARKEND; + return res; + } + + // Now start thread + startInfo->iServerThread.SetPriority( EPriorityMuchMore ); + startInfo->iServerThread.Resume(); + + // Wait until the thread is started + startInfo->iStarted.Wait(); + + // Server is started( or it has returned error ) + + + } + + // EKA2 and EKA1's HW + else + { + // Call directly thread function, this starts server and + // blocks this thread. + // Priority is default, not known reason why should be greater + // than default priority (Work over a year). + CTestServer::ThreadFunction( startInfo ); + } + + // Set server name + aServerName = aModuleFileName; + + // Free memory + TInt r = startInfo->iStartupResult; + startInfo->iServerThread.Close(); + startInfo->iStarted.Close(); + delete startInfo; + startInfo = NULL; + + __UHEAP_MARKEND; + + // Return start-up result. + return r; + + } + +/* +------------------------------------------------------------------------------- + + Class: - + + Method: StartNewServer + + Description: Starts a new server. Server will be running its own + thread and this functions returns when server is up and running or + server start-up fails. + + Parameters: const TFileName& aModuleFileName: in: Module name + TFileName& aServerName: in: Server name + const TBool aInNewThread: in: Is new thread + RSemaphore aSynchronisation: in: For synchronisation + + Return Values: TInt: Symbian error code + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +EXPORT_C TInt StartNewServer( const TFileName& aModuleFileName, + TFileName& aServerName, + const TBool aInNewThread, + RSemaphore aSynchronisation + ) + { + + return StartNewServer( aModuleFileName, aServerName, aInNewThread, aSynchronisation, false, NULL ); + } + + +/* +------------------------------------------------------------------------------- + + Class: - + + Method: StartNewServer + + Description: Starts a new server. Server will be running its own + thread and this functions returns when server is up and running or + server start-up fails. + + Parameters: const TFileName& aName: in: Module name to be used + TFileName& aServerName: out: The name of the server + + Return Values: TInt Error code / KErrNone + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +EXPORT_C TInt StartNewServer( const TFileName& aModuleFileName, + TFileName& aServerName + ) + { + + __UHEAP_MARK; + + RMutex startupMutex; + TInt ret( KErrNone ); + // Global mutex already created(see CTestEngineServer::ThreadFunction). + // Open global mutex. + ret = startupMutex.OpenGlobal( KStifTestServerStartupMutex ); + if( ret != KErrNone ) + { + // Not able to open mutex + return ret; + } + + startupMutex.Wait(); + + //Check server not already started + TFindServer findServer( aModuleFileName ); + TFullName name; + if( findServer.Next( name ) == KErrNone ) + { + // Server already started, nothing to do + aServerName = aModuleFileName; + + // release startupmutex + startupMutex.Signal(); + startupMutex.Close(); + + __UHEAP_MARKEND; + return KErrAlreadyExists; + } + + RSemaphore startupSemaphore; + startupSemaphore.CreateLocal( 0 ); + + // Start server in new thread + TInt r = StartNewServer ( aModuleFileName, aServerName, ETrue, startupSemaphore ); + + // startupSemaphore will be closed inside StartNewServer when start-up is done. + + // release startupmutex + startupMutex.Signal(); + startupMutex.Close(); + + __UHEAP_MARKEND; + + // Return start-up result. + return r; + + } + +// End of File