// Copyright (c) 2007-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:
//
/**
@file
@test
@internalComponent - Internal Symbian test code
*/
#include <ssm/ssmcommandlist.h>
#include "ssmswppolicyframe.h"
#include "ssmswptransitionengine.h"
#include "ssmatest_utils.h"
#include "tssm_step_swptransitionengine.h"
#include "tssm_swppolicy_generic.h"
#include "tssm_swppolicy_generic.hrh"
#include <e32debug.h>
// Keys and values used for testing the transition engines
static const TUint KSwpTestKey1 = 0xE5325221;
const TInt KTestErrorBadCategory = -911;
const TInt KTestErrorBadFunction = -912;
/**
*/
static TInt StopScheduler(TAny* aSsmSwpTransitionEngineTest)
{
CSsmSwpTransitionEngineTest* ssmSwpRequestEngineTest = static_cast<CSsmSwpTransitionEngineTest*>(aSsmSwpTransitionEngineTest);
ssmSwpRequestEngineTest->StopActiveScheduler();
return KErrNone;
}
//--------------------- Thread creation framework ---------------------
/**
Test framework to check for panic scenarios
It requires to create a separate thread so we can check the panic category and code.
*/
TInt StartTestInThreadL(TInt aFunction)
{
RThread thread;
// Give each thread a unique name to avoid KErrAlreadyExists error on thread creation
_LIT(KThreadNamePrefix, "SsmTestThread");
RBuf threadName;
CleanupClosePushL(threadName);
threadName.CreateL(KThreadNamePrefix().Length() + 4); // 4 digit thread number
threadName = KThreadNamePrefix;
threadName.AppendNumFixedWidth(aFunction, EDecimal, 4);
const TInt KMinHeapSize = 0xc800; // 50k - NOTE just an arbitrary value, please feel free to change it
const TInt KMaxHeapSize = 0x19000; // 100k - NOTE just an arbitrary value, please feel free to change it
User::LeaveIfError(thread.Create(threadName, ThreadStartFn, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, (TAny*)aFunction));
CleanupStack::PopAndDestroy(&threadName);
TRequestStatus status;
thread.Logon(status);
TBool jit = User::JustInTime();
User::SetJustInTime(EFalse);
thread.Resume();
User::WaitForRequest(status);
// always expecting a transition engine panic
TExitCategoryName category = thread.ExitCategory();
RDebug::Print(_L("***** Exit Category = %S *****"),&category);
if (category.Compare(KPanicSysStateMgr) != 0)
{
User::Leave(KTestErrorBadCategory);
}
const TInt exitReason = thread.ExitReason();
thread.Close();
User::SetJustInTime(jit);
// return the exit reason for the caller to verify the expected panic value
return exitReason;
}
TInt ThreadStartFn(TAny* aPtr)
{
CTrapCleanup* trapCleanup = CTrapCleanup::New();
if (!trapCleanup)
{
return KErrNoMemory;
}
TInt function = (TInt)aPtr;
TRAPD(err, ThreadDispatchFunctionL(function));
delete trapCleanup;
return err;
}
void ThreadDispatchFunctionL(TInt aFunction)
{
switch (aFunction)
{
case EThreadSubmitTwice:
ThreadSubmitTwiceL();
break;
default:
User::Leave(KTestErrorBadFunction);
break;
}
}
void ThreadSubmitTwiceL()
{
CSsmSwpTransitionEngineTest* step = new (ELeave) CSsmSwpTransitionEngineTest();
CActiveScheduler* activeScheduler = new(ELeave) CActiveScheduler;
CleanupStack::PushL(activeScheduler);
CActiveScheduler::Install(activeScheduler);
CAsyncCallBack* asyncStopScheduler = new(ELeave) CAsyncCallBack(CActive::EPriorityIdle);
TCallBack stop(StopScheduler, step);
asyncStopScheduler->Set(stop);
CleanupStack::Pop(activeScheduler);
// ssmswppolicyproxy is created and set by the individualtransitionscheduler, since
// we are submitting the request directly to the engine the ssmswppolicyproxy should be
// created and set in the engine
CSsmSwpPolicyCliSession* ssmSwpPolicySession = CSsmSwpPolicyCliSession::NewL();
CleanupStack::PushL(ssmSwpPolicySession);
// Setting the cle session as we have to execute the publishswp command.
// published swp value is used to stop the scheduler.
CCleSessionProxy* cleSession = CCleSessionProxy::NewL();
CleanupStack::PushL(cleSession);
const TSsmSwp swpValue(KSwpTestKey1, ESwpGenericDoNothing);
CSsmSwpPolicyFrame* policy = step->GetSwpPolicyL(swpValue);
CleanupStack::PushL(policy);
CSsmSwpTransitionEngine* engine = CSsmSwpTransitionEngine::NewL(swpValue);
engine->SetCleSessionProxy(cleSession);
engine->SetSwpPolicyFrame(policy);
engine->SetSsmSwpPolicySession(ssmSwpPolicySession);
CleanupStack::Pop(policy);
CleanupStack::PushL(engine);
engine->Submit();
engine->Submit();
// etc, etc, etc..
// don't bother to continue here. All being well the second SubmitL will cause a panic!
//Cleanup test
CleanupStack::PopAndDestroy(3, ssmSwpPolicySession); // and engine
}
//----------------- CTestStep implemenation --------------------
/**
*/
CSsmSwpTransitionEngineTest::~CSsmSwpTransitionEngineTest()
{
iProperty.Close();
delete iAsyncStopScheduler;
delete iActiveScheduler;
}
/**
*/
CSsmSwpTransitionEngineTest::CSsmSwpTransitionEngineTest()
{
SetTestStepName(KTSsmSwpTransitionEngineStep);
}
/**
*/
TVerdict CSsmSwpTransitionEngineTest::doTestStepPreambleL()
{
iActiveScheduler = new(ELeave) CActiveScheduler;
CActiveScheduler::Install (iActiveScheduler);
iAsyncStopScheduler = new(ELeave) CAsyncCallBack(CActive::EPriorityIdle);
TCallBack stop(StopScheduler, this);
iAsyncStopScheduler->Set(stop);
return CTestStep::doTestStepPreambleL();
}
/**
Old Test CaseID APPFWK-SSM-0007
New Test CaseID DEVSRVS-SSMA-SSM-0007
*/
TVerdict CSsmSwpTransitionEngineTest::doTestStepL()
{
INFO_PRINTF1(_L("CSsmSwpTransitionEngineTest started...."));
__UHEAP_MARK;
doTestSwpTransitionEngineTestForMemoryLeaksL();
doTestRequestSimpleL();
doTestRequestCancelL();
doTestRequestSubmitTwiceL();
__UHEAP_MARKEND;
INFO_PRINTF1(_L("....CSsmSwpTransitionEngineTest completed!!"));
return TestStepResult();
}
/**
*/
TVerdict CSsmSwpTransitionEngineTest::doTestStepPostambleL()
{
return CTestStep::doTestStepPostambleL();
}
/**
*/
void CSsmSwpTransitionEngineTest::doTestSwpTransitionEngineTestForMemoryLeaksL()
{
INFO_PRINTF1(_L("Checking for destructor memoryleaks in CSsmSwpTransitionEngine"));
__UHEAP_MARK;
// ssmswppolicyproxy is created and set by the individualtransitionscheduler, since
// we are submitting the request directly to the engine the ssmswppolicyproxy should be
// created and set in the engine
CSsmSwpPolicyCliSession* ssmSwpPolicySession = CSsmSwpPolicyCliSession::NewL();
CleanupStack::PushL(ssmSwpPolicySession);
// Setting the cle session as we have to execute the publishswp command.
// published swp value is used to stop the scheduler.
CCleSessionProxy* cleSession = CCleSessionProxy::NewL();
CleanupStack::PushL(cleSession);
const TSsmSwp swpValue(KSwpTestKey1, ESwpGenericDoNothing);
CSsmSwpPolicyFrame* policy = this->GetSwpPolicyL(swpValue);
CleanupStack::PushL(policy);
CSsmSwpTransitionEngine* engine = CSsmSwpTransitionEngine::NewL(swpValue);
engine->SetCleSessionProxy(cleSession);
engine->SetSwpPolicyFrame(policy);
engine->SetSsmSwpPolicySession(ssmSwpPolicySession);
CleanupStack::Pop(policy);
//Cleanup test
CleanupStack::PopAndDestroy(2, ssmSwpPolicySession);
delete engine;
__UHEAP_MARKEND;
}
/**
Takes CSsmSwpTransitionEngine through the simple swp transition.
*/
void CSsmSwpTransitionEngineTest::doTestRequestSimpleL()
{
INFO_PRINTF1(_L("Checking requesthandler with a single request"));
__UHEAP_MARK;
// ssmswppolicyproxy is created and set by the individualtransitionscheduler, but
// we are submitting the request directly to the engine the ssmswppolicyproxy should be
// created and set in the engine
CSsmSwpPolicyCliSession* ssmSwpPolicySession = CSsmSwpPolicyCliSession::NewL();
CleanupStack::PushL(ssmSwpPolicySession);
// Setting the cle session as we have to execute the publishswp command.
// published swp value is used to stop the scheduler.
CCleSessionProxy* cleSession = CCleSessionProxy::NewL();
CleanupStack::PushL(cleSession);
// Define and set the rproperty
TEST(KErrNone == iProperty.Define(RProcess().SecureId(), KSwpTestKey1, RProperty::EInt));
TEST(KErrNone == iProperty.Set(RProcess().SecureId(), KSwpTestKey1, 0));
TInt value;
TEST(KErrNone == iProperty.Get(RProcess().SecureId(), KSwpTestKey1, value));
TEST(value == 0);
const TSsmSwp swpValue(KSwpTestKey1, ESwpGenericDoNothing);
CSsmSwpPolicyFrame* policy = this->GetSwpPolicyL(swpValue);
CleanupStack::PushL(policy);
CSsmSwpTransitionEngine* engine = CSsmSwpTransitionEngine::NewL(swpValue);
engine->SetCleSessionProxy(cleSession);
engine->SetSwpPolicyFrame(policy);
engine->SetSsmSwpPolicySession(ssmSwpPolicySession);
engine->PerformCommandListValidation(EFalse);
CleanupStack::Pop(policy);
CleanupStack::PushL(engine);
engine->Submit();
//this callback will not run until the test is finished because it has priority idle
iAsyncStopScheduler->CallBack();
//run engine
iActiveScheduler->Start();
TEST(KErrNone == iProperty.Get(RProcess().SecureId(), KSwpTestKey1, value));
TEST(value == ESwpGenericDoNothing);
TEST(KErrNone == iProperty.Delete(RProcess().SecureId(), KSwpTestKey1));
//Cleanup test
CleanupStack::PopAndDestroy(3, ssmSwpPolicySession); // and engine
__UHEAP_MARKEND;
}
/**
Takes CSsmSwpTransitionEngine through the simple swp transition and cancels it.
*/
void CSsmSwpTransitionEngineTest::doTestRequestCancelL()
{
INFO_PRINTF1(_L("Checking requesthandler with a cancel request"));
__UHEAP_MARK;
// ssmswppolicyproxy is created and set by the individualtransitionscheduler, but
// we are submitting the request directly to the engine the ssmswppolicyproxy should be
// created and set in the engine
CSsmSwpPolicyCliSession* ssmSwpPolicySession = CSsmSwpPolicyCliSession::NewL();
CleanupStack::PushL(ssmSwpPolicySession);
// Setting the cle session as we have to execute the publishswp command.
// published swp value is used to stop the scheduler.
CCleSessionProxy* cleSession = CCleSessionProxy::NewL();
CleanupStack::PushL(cleSession);
// Define and set the rproperty
TEST(KErrNone == iProperty.Define(RProcess().SecureId(), KSwpTestKey1, RProperty::EInt));
TEST(KErrNone == iProperty.Set(RProcess().SecureId(), KSwpTestKey1, -5));
TInt value;
TEST(KErrNone == iProperty.Get(RProcess().SecureId(), KSwpTestKey1, value));
TEST(value == -5);
const TSsmSwp swpValue(KSwpTestKey1, ESwpGenericDoNothing);
CSsmSwpPolicyFrame* policy = this->GetSwpPolicyL(swpValue);
CleanupStack::PushL(policy);
CSsmSwpTransitionEngine* engine = CSsmSwpTransitionEngine::NewL(swpValue);
engine->SetCleSessionProxy(cleSession);
engine->SetSwpPolicyFrame(policy);
engine->SetSsmSwpPolicySession(ssmSwpPolicySession);
engine->PerformCommandListValidation(EFalse);
CleanupStack::Pop(policy);
CleanupStack::PushL(engine);
engine->Submit();
engine->Cancel();
//this callback will not run until the test is finished because it has priority idle
iAsyncStopScheduler->CallBack();
//run engine
iActiveScheduler->Start();
TEST(KErrNone == iProperty.Get(RProcess().SecureId(), KSwpTestKey1, value));
TEST(value == -5);
TEST(KErrNone == iProperty.Delete(RProcess().SecureId(), KSwpTestKey1));
//Cleanup test
CleanupStack::PopAndDestroy(3, ssmSwpPolicySession); // and engine
__UHEAP_MARKEND;
}
void CSsmSwpTransitionEngineTest::doTestRequestSubmitTwiceL()
{
INFO_PRINTF1(_L("Checking requesthandler with two consecutive requests"));
TInt exitReason(0);
TRAPD(err, exitReason = StartTestInThreadL(EThreadSubmitTwice));
TEST(err == KErrNone);
INFO_PRINTF2(_L(" 3-- StartTestInThreadL method completed with '%d'."), err);
TEST(exitReason == ESwpTransitionEngineError3);
INFO_PRINTF3(_L(" 3-- received panic '%d', expected was '%d'."), exitReason, ESwpTransitionEngineError3);
// this test raises panics due to negative testing - close them to clear the screen.
CloseAllPanicWindowsL();
}
void CSsmSwpTransitionEngineTest::StopActiveScheduler()
{
// We would stop the sceduler once all the required transitions are completed
//Verify that the expected calls were made
TInt value;
TEST(KErrNone == iProperty.Get(RProcess().SecureId(), KSwpTestKey1, value));
// We have to stop the scheduler in case of Cancel test code, so testing property's initial value.
if (value == ESwpGenericDoNothing || value == -5)
{
CActiveScheduler::Stop();
}
else
{
iAsyncStopScheduler->CallBack();
}
}
//----------------- MPolicyResolverProxy implementation --------------------
CSsmSwpPolicyFrame* CSsmSwpTransitionEngineTest::CreatePolicyLC(const RLibrary& aLibrary) const
{
__ASSERT_DEBUG( KNullHandle != aLibrary.Handle(), PanicNow(KPanicSysStateMgr, ESwpPolicyResolverLibraryNotLoaded));
CSsmSwpPolicyFrame* frame = NULL;
TRAPD(err, frame = CSsmSwpPolicyFrame::NewL(aLibrary.Lookup(1)));
if (err != KErrNone)
{
TFileName name = aLibrary.FileName();
DEBUGPRINT3(_L("Error %d when calling first function in State Policy DLL %S."), err, &name);
}
User::LeaveIfError(err);
CleanupStack::PushL(frame);
return frame;
}
/**
*/
CSsmSwpPolicyFrame* CSsmSwpTransitionEngineTest::GetSwpPolicyL(const TSsmSwp& aSwp)
{
RLibrary library;
const TInt fileErr = library.Load(KTestSwpPolicyGenericFile);
if (fileErr != KErrNone)
{
RDebug::Print(_L("Failed to load library file %S, file error-code: %d"), &KTestSwpPolicyGenericFile(), fileErr);
User::Leave(fileErr);
}
// make a process-owned copy of the handle as it has to be used by SsmSwpPolicyServer,
// which runs in a separate thread
User::LeaveIfError(library.Duplicate(RThread(), EOwnerProcess));
CSsmSwpPolicyFrame* policy = CreatePolicyLC(library);
CleanupStack::Pop(policy);
policy->SetLibrary(library); // takes ownership of open library handle
policy->SetSwpKey(aSwp.Key());
RDebug::Print(_L("Created Swp Policy DLL %S"), &KTestSwpPolicyGenericFile());
return policy;
}