kerneltest/e32test/power/t_domain.cpp
changeset 0 a41df078684a
child 6 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/power/t_domain.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2265 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// e32test\power\t_domain.cpp
+// Overview:
+// Domain manager tests
+// API Information:
+// RDmDomain, RDmDomainManager CDmDomain, CDmDomainManager
+// Details:
+// - Test a variety of domain transitions, check the expected number of
+// notifications and the first expected ordinal. Verify results are
+// as expected.
+// - Test system standby, check the expected number of notifications and 
+// the first expected ordinal. Use a timer to request a wakeup event.
+// Verify results are as expected.
+// - Test domain related simple error situations, verify results are
+// as expected.
+// - Perform platform security tests: launch a separate process with no 
+// capabilities, verify that results are as expected.
+// - Test domain transitions by connecting to two domain hierarchies 
+// simultaneously, add some test and power hierarchy members, verify
+// the expected target state, notifications and leaf nodes. Verify results.
+// - Verify that the same hierarchy can not be connected to more than once.
+// - Request a positive transition and request that the test domain use 
+// ETraverseParentsFirst. Verify results are as expected and verify 
+// domains are in the correct state.
+// - Request a negative transition and request that the test domain use 
+// ETraverseChildrenFirst. Verify results are as expected.
+// - Request a positive transition with zero acknowledgements. Verify 
+// results are as expected.
+// - Request a positive transition with error acknowledgements. Verify 
+// results are as expected.
+// - Perform a variety of negative tests and verify results are as expected.
+// - Perform various tests on domain transitions with activated observer.
+// Verify results are as expected.
+// Platforms/Drives/Compatibility:
+// All.
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+// 
+//
+
+#include <e32test.h>
+#include <domainmember.h>
+#include <domainmanager.h>
+#include <domainobserver.h>
+#include "domainpolicytest.h"
+#include <e32debug.h>
+#include <f32file.h>
+
+LOCAL_D RTest test(_L(" T_DOMAIN "));
+_LIT(KThreadName, "t_domain_panic_thread");
+
+#ifdef _DEBUG
+#define __PRINT(x) {RDebug::Print x;}
+#else
+#define __PRINT(x) 
+#endif
+
+class CDmTestMember;
+
+// interface for test domain memebers.
+// Any test memeber should derive from this interface 
+class MDmDomainMember
+	{
+public:
+	virtual TDmHierarchyId HierarchyId() = 0;
+	virtual TDmDomainId	DomainId() = 0;
+	virtual TDmDomainState State() = 0;
+	virtual TInt Status() = 0;
+	virtual TUint32 Ordinal() = 0;
+	virtual TInt Notifications() = 0;
+	};
+
+class MDmTest
+	{
+public:
+	virtual void Perform() = 0;
+	virtual void Release() = 0;
+	virtual TInt TransitionNotification(MDmDomainMember& aDomainMember) = 0;
+	virtual void TransitionRequestComplete() = 0;
+	};
+
+// for the test hierarchy, we generate an ordinal for each domain
+// each byte of which describes the exact location of the domain in the hierarchy
+#define ORDINAL_FROM_DOMAINID0(id) (id)
+#define ORDINAL_FROM_DOMAINID1(parent, id) ((parent << 8) | (id))
+#define ORDINAL_FROM_DOMAINID2(grandparent, parent, id) ((grandparent << 16) | (parent << 8) | id)
+#define ORDINAL_FROM_DOMAINID3(greatgrandparent, grandparent, parent, id) ((greatgrandparent << 24) | (grandparent << 16) | (parent << 8) | id)
+#define PARENT_ORDINAL(id) (id >> 8)
+
+#define ORDINAL_LEVEL(ordinal)			\
+	((ordinal & 0xFF00) == 0) ? 1 :			\
+	((ordinal & 0xFF0000) == 0) ? 2 :		\
+	((ordinal & 0xFF000000) == 0) ? 3 : 4;
+
+
+// get the least significant domain id character (for debugging purposes)
+TBool GetDomainChar(TDmDomainId aDomainId, TChar& aChar)
+	{
+	TBool found = ETrue;
+	switch(aDomainId)
+		{
+		
+		case KDmIdTestA:	aChar = 'A'; break;
+		case KDmIdTestB:	aChar = 'B'; break;
+		case KDmIdTestC:	aChar = 'C'; break;
+		case KDmIdTestAA:	aChar = 'A'; break;
+		case KDmIdTestAB:	aChar = 'B'; break;
+		case KDmIdTestBA:	aChar = 'A'; break;
+		case KDmIdTestCA:	aChar = 'A'; break;
+		case KDmIdTestABA:	aChar = 'A'; break;
+		case KDmIdTestABB:	aChar = 'B'; break;
+		case KDmIdTestCAA:	aChar = 'A'; break;
+		// domain char not found 
+		case KDmIdNone:
+		case KDmIdRoot:		
+		default:			
+			found = EFalse;
+		}
+	return found;
+	}
+
+// prints the 4-character domain string into the passed descriptor (for debugging purposes)
+// e.g. "CAA" for KDmIdTestCAA
+void GetDomainDesc(TUint32 aOrdinal, TDes& aDes)
+	{
+	if (aOrdinal == KDmIdRoot)
+		{
+		aDes.Append(_L("root"));
+		return;
+		}
+
+	TUint32 val =  aOrdinal;
+
+	for (TInt n=0; n<4; n++)
+		{
+		TDmDomainId domainId = (TDmDomainId) (val >> 24);
+		TChar ch;
+		TBool found = GetDomainChar(domainId, ch);
+		if (found)
+			aDes.Append(ch);
+		val = val << 8;
+		}
+
+	}
+
+
+class CDmTestMember : public CActive, public MDmDomainMember
+	{
+public:	
+	// from CActive
+	void RunL();
+	// from MDmDomainMember
+	inline TDmHierarchyId HierarchyId() {return iHierarchy;};
+	inline TDmDomainId	DomainId() {return iId;};
+	inline TDmDomainState State() {return iState;};
+	inline TInt Status() {return iStatus.Int();};
+	inline TUint32 Ordinal() {return iOrdinal;};
+	inline TInt Notifications() {return iNotifications;};
+
+	CDmTestMember(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest*);
+	~CDmTestMember();
+	void Acknowledge();
+
+protected:
+	// from CActive
+	virtual void DoCancel();
+
+
+public:
+	TDmHierarchyId iHierarchy;
+	TDmDomainId	iId;
+	TDmDomainState iState;
+	TUint32		iOrdinal;
+	MDmTest*	iTest;	
+	TInt		iNotifications;
+	RDmDomain	iDomain;
+	};
+
+
+
+CDmTestMember::CDmTestMember(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest* aTest) : CActive(CActive::EPriorityStandard), 
+	iHierarchy(aHierarchy), iId(aId), iOrdinal(aOrdinal), iTest(aTest)
+	{
+	TInt r;
+
+	if (iHierarchy == KDmHierarchyIdPower)
+		 r = iDomain.Connect(iId);
+	else
+		 r = iDomain.Connect(iHierarchy, iId);
+
+	test(r == KErrNone);
+
+	CActiveScheduler::Add(this);
+
+	iDomain.RequestTransitionNotification(CActive::iStatus);
+	CActive::SetActive();
+	}
+
+CDmTestMember::~CDmTestMember()
+	{
+	CActive::Cancel();
+	iDomain.Close();
+	}
+
+void CDmTestMember::Acknowledge()
+	{
+	iDomain.AcknowledgeLastState();
+	}
+
+void CDmTestMember::RunL()
+	{
+
+	iNotifications++;
+
+	iState = iDomain.GetState();
+
+	TInt ackError = iTest->TransitionNotification(*this);
+	if (ackError == KErrNone)
+		iDomain.AcknowledgeLastState();
+	else if (ackError == KErrAbort)	// don't acknowledge
+		;
+	else
+		iDomain.AcknowledgeLastState(ackError);
+
+	
+	// request another notification (even if we didn't acknowledge the last one)
+	iDomain.RequestTransitionNotification(CActive::iStatus);
+	CActive::SetActive();
+	}
+
+void CDmTestMember::DoCancel()
+	{
+	iDomain.CancelTransitionNotification();
+	}
+
+
+// CDomainMemberAo
+class CDomainMemberAo : public CDmDomain, public MDmDomainMember
+	{
+public:	
+	static CDomainMemberAo* NewL(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest*);
+	~CDomainMemberAo();
+
+	// from CActive
+	void RunL();
+
+	// from MDmDomainMember
+	inline TDmHierarchyId HierarchyId() {return iHierarchy;};
+	inline TDmDomainId	DomainId() {return iId;};
+	inline TDmDomainState State() {return iState;};
+	inline TInt Status() {return iStatus.Int();};
+	inline TUint32 Ordinal() {return iOrdinal;};
+	inline TInt Notifications() {return iNotifications;};
+
+private:
+	CDomainMemberAo(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest*);
+
+public:
+	TDmHierarchyId iHierarchy;
+	TDmDomainId	iId;
+	TDmDomainState iState;
+	TUint32		iOrdinal;
+	MDmTest*	iTest;	
+	TInt		iNotifications;
+	};
+
+CDomainMemberAo* CDomainMemberAo::NewL(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest* aTest)
+	{
+	CDomainMemberAo* self=new (ELeave) CDomainMemberAo(aHierarchy, aId, aOrdinal, aTest);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+
+	self->RequestTransitionNotification();
+
+	CleanupStack::Pop();
+	return self;
+	}
+
+CDomainMemberAo::CDomainMemberAo(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest* aTest) : 
+	CDmDomain(aHierarchy, aId), 
+	iHierarchy(aHierarchy), iId(aId), iOrdinal(aOrdinal), iTest(aTest)
+	{
+	}
+
+CDomainMemberAo::~CDomainMemberAo()
+	{
+	Cancel();
+	}
+
+void CDomainMemberAo::RunL()
+	{
+	iNotifications++;
+
+	iState = GetState();
+
+	TInt ackError = iTest->TransitionNotification(*this);
+	if (ackError == KErrNone)
+		AcknowledgeLastState(ackError);
+	else if (ackError == KErrAbort)	// don't acknowledge
+		;
+	else
+		AcknowledgeLastState(ackError); 
+	if (ackError != KErrAbort)	
+		AcknowledgeLastState(ackError);
+
+	
+	// request another notification (even if we didn't acknowledge the last one)
+	RequestTransitionNotification();
+	}
+
+
+// CDomainManagerAo
+class CDomainManagerAo : public CDmDomainManager
+	{
+public:	
+	~CDomainManagerAo();
+	static CDomainManagerAo* NewL(TDmHierarchyId aHierarchy, MDmTest& aTest);
+
+	// from CActive
+	void RunL();
+
+private:
+	CDomainManagerAo(TDmHierarchyId aHierarchy, MDmTest& aTest);
+
+private:
+	MDmTest& iTest;
+	};
+
+
+CDomainManagerAo* CDomainManagerAo::NewL(TDmHierarchyId aHierarchy, MDmTest& aTest)
+	{
+	CDomainManagerAo* self=new (ELeave) CDomainManagerAo(aHierarchy, aTest);
+	CleanupStack::PushL(self);
+
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CDomainManagerAo::CDomainManagerAo(TDmHierarchyId aHierarchy, MDmTest& aTest) : 
+	CDmDomainManager(aHierarchy), iTest(aTest)
+	{
+	}
+
+CDomainManagerAo::~CDomainManagerAo()
+	{
+	}
+
+void CDomainManagerAo::RunL()
+	{
+	iTest.TransitionRequestComplete();
+	}
+
+
+class CDmTest1 : public CActive, public MDmTest
+	{
+public: // from CActive
+	void RunL();
+
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete() {};
+
+	CDmTest1 (TDmDomainId aId, TDmDomainState aState) : CActive(CActive::EPriorityStandard), iDomainId(aId), iState((TPowerState) aState) {}
+
+protected:
+	// from CActive
+	virtual void DoCancel();
+
+private:
+	enum { KMembersMax = 16 };
+	CDmTestMember*		iMembers[KMembersMax]; 
+	RDmDomainManager	iManager;
+	TDmDomainId			iDomainId;
+	TPowerState			iState;
+	TBool				iAcknowledge;
+	TInt				iMembersCount;
+	TInt				iCount;
+	TUint32				iOrdinal;
+	};
+
+void CDmTest1::Perform()
+	{
+	//
+	// Test domain transitions
+	//
+
+	test.Next(_L("Test 1"));
+	test.Printf(_L("Domain id = 0x%x Target State = 0x%x\n"), iDomainId, iState);
+	iMembers[0] = new CDmTestMember(KDmHierarchyIdPower, KDmIdRoot, 0, this);
+	test(iMembers[0] != NULL);
+	iMembers[1] = new CDmTestMember(KDmHierarchyIdPower, KDmIdRoot, 0, this);
+	test(iMembers[1] != NULL);
+	iMembers[2] = new CDmTestMember(KDmHierarchyIdPower, KDmIdApps, 1, this);
+	test(iMembers[2] != NULL);
+	iMembers[3] = new CDmTestMember(KDmHierarchyIdPower, KDmIdApps, 1, this);
+	test(iMembers[3] != NULL);
+	iMembers[4] = new CDmTestMember(KDmHierarchyIdPower, KDmIdUiApps, 1, this);
+	test(iMembers[4] != NULL);
+	iMembers[5] = new CDmTestMember(KDmHierarchyIdPower, KDmIdUiApps, 1, this);
+	test(iMembers[5] != NULL);
+	
+	// expected number of notifications
+	iMembersCount = (iDomainId == KDmIdRoot) ? 6 : 2;
+	// first expected ordinal
+	iOrdinal = (iState == EPwActive) ? 0 : 1;
+
+	TInt r = iManager.Connect();
+	test(r == KErrNone);
+
+	CActiveScheduler::Add(this);
+
+	iManager.RequestDomainTransition(iDomainId, iState, CActive::iStatus);
+	CActive::SetActive();
+
+	CActiveScheduler::Start();
+	}
+
+TInt CDmTest1::TransitionNotification(MDmDomainMember& aDomainMember)
+	{
+	++iCount;
+	if (aDomainMember.State() == EPwActive)
+		{
+		if(aDomainMember.Ordinal() < iOrdinal)
+			{
+			// Making the test to fail in RunL function inorder to complete the cleanup from domain manager.
+			test.Printf(_L("Making test to fail as Ordinal Mismatch Expected : %d, Returned : %d"), aDomainMember.Ordinal(), iOrdinal);
+			iCount--;
+			}
+		}
+	else
+		{
+		if(aDomainMember.Ordinal() > iOrdinal)
+			{
+			//Making the test to fail in RunL function inorder to complete the cleanup from domain manager.
+			test.Printf(_L("Making test to fail as Ordinal Mismatch Expected : %d, Returned : %d"), aDomainMember.Ordinal(), iOrdinal);
+			iCount--;
+			}
+		}
+	iOrdinal = aDomainMember.Ordinal();
+
+	// acknowledge one from two
+	iAcknowledge = !iAcknowledge;
+	return iAcknowledge?KErrNone:KErrGeneral;
+	}
+
+void CDmTest1::RunL()
+	{
+	CActiveScheduler::Stop();
+
+	iManager.Close();
+
+	CDmTestMember** mp;
+	for (mp = iMembers; *mp; ++mp)
+		delete *mp;
+	test(iCount == iMembersCount);
+	}
+
+void CDmTest1::DoCancel()
+	{
+	test(0);
+	}
+
+void CDmTest1::Release()
+	{
+	delete this;
+	}
+
+class CDmTest2Timer : public CTimer
+	{
+public: // fomr CTimer
+   void RunL();
+public:
+	CDmTest2Timer() : CTimer(0) 
+		{
+		TRAPD(r,
+			ConstructL());
+		test(r == KErrNone);
+		CActiveScheduler::Add(this);
+		}
+	};
+
+void CDmTest2Timer::RunL()
+	{
+	test.Printf(_L("Tick count after CDmTest2Timer::RunL() = %d\n"), User::NTickCount());
+
+	// kick the timer again in case power down hasn't happened yet
+	TTime wakeup;
+	wakeup.HomeTime();
+	wakeup += TTimeIntervalSeconds(3);
+	At(wakeup);
+	}
+
+class CDmTest2 : public CActive, public MDmTest
+	{
+public: // from CActive
+	void RunL();
+
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete() {};
+	CDmTest2 (TDmDomainState aState) : CActive(CActive::EPriorityStandard), iState((TPowerState) aState) {}
+
+protected:
+	// from CActive
+	virtual void DoCancel();
+
+private:
+	enum { KMembersMax = 16 };
+	CDmTestMember*		iMembers[KMembersMax]; 
+	RDmDomainManager	iManager;
+	TPowerState			iState;
+	TBool				iAcknowledge;
+	TInt				iMembersCount;
+	TInt				iCount;
+	TUint32				iOrdinal;
+	CDmTest2Timer*		iTimer;
+	};
+
+
+void CDmTest2::Perform()
+	{
+	//
+	// Test system standby
+	//
+
+	test.Next(_L("Test 2"));
+	test.Printf(_L("Target State = 0x%x\n"), iState);
+	iMembers[0] = new CDmTestMember(KDmHierarchyIdPower, KDmIdRoot, 0, this);
+	test(iMembers[0] != NULL);
+	iMembers[1] = new CDmTestMember(KDmHierarchyIdPower, KDmIdRoot, 0, this);
+	test(iMembers[1] != NULL);
+	iMembers[2] = new CDmTestMember(KDmHierarchyIdPower, KDmIdApps, 1, this);
+	test(iMembers[2] != NULL);
+	iMembers[3] = new CDmTestMember(KDmHierarchyIdPower, KDmIdApps, 1, this);
+	test(iMembers[3] != NULL);
+	iMembers[4] = new CDmTestMember(KDmHierarchyIdPower, KDmIdUiApps, 1, this);
+	test(iMembers[4] != NULL);
+	iMembers[5] = new CDmTestMember(KDmHierarchyIdPower, KDmIdUiApps, 1, this);
+	test(iMembers[5] != NULL);
+	
+	// expected number of notifications
+	iMembersCount = 12;
+	// first expected ordinal
+	iOrdinal = (iState == EPwActive) ? 0 : 1;
+
+	TInt r = iManager.Connect();
+	test(r == KErrNone);
+
+	CActiveScheduler::Add(this);
+
+	// Use an absolute timer to request a wakeup event
+	iTimer = new CDmTest2Timer();
+	TTime wakeup;
+	wakeup.HomeTime();
+	wakeup += TTimeIntervalSeconds(5);
+	test.Printf(_L("Tick count before timer = %d\n"), User::NTickCount());
+	iTimer->At(wakeup);
+	
+	iManager.RequestSystemTransition(iState, CActive::iStatus);
+	CActive::SetActive();
+
+	CActiveScheduler::Start();
+	}
+
+TInt CDmTest2::TransitionNotification(MDmDomainMember& aDomainMember)
+	{
+	++iCount;
+	if (aDomainMember.State() == EPwActive)
+		{
+		if(aDomainMember.Ordinal() < iOrdinal)
+			{
+			// Making the test to fail in RunL function inorder to complete the cleanup from domain manager.
+			test.Printf(_L("Making test to fail as Ordinal Mismatch Expected : %d, Returned : %d, State : %d"), 
+																		aDomainMember.Ordinal(), iOrdinal, aDomainMember.State());
+			iCount--;
+			}
+		}
+	else
+		{
+		if(aDomainMember.Ordinal() > iOrdinal)
+			{
+			// Making the test to fail in RunL function inorder to complete the cleanup from domain manager.
+			test.Printf(_L("Making test to fail as Ordinal Mismatch Expected : %d, Returned : %d, State: %d"), 
+																		aDomainMember.Ordinal(), iOrdinal, aDomainMember.State());
+			iCount--;
+			}
+		}
+	iOrdinal = aDomainMember.Ordinal();
+
+	// acknowledge one from two
+	iAcknowledge = !iAcknowledge;
+	return iAcknowledge?KErrNone:KErrAbort;
+	}
+
+void CDmTest2::RunL()
+	{
+	test.Printf(_L("Tick count after CDmTest2::RunL() = %d\n"), User::NTickCount());
+
+	iTimer->Cancel();	
+	CActiveScheduler::Stop();
+
+	iManager.Close();
+
+	CDmTestMember** mp;
+	for (mp = iMembers; *mp; ++mp)
+		delete *mp;
+	test(CActive::iStatus == KErrTimedOut);
+	test(iCount == iMembersCount);
+	}
+
+void CDmTest2::DoCancel()
+	{
+	test(0);
+	}
+
+void CDmTest2::Release()
+	{
+	if (iTimer)
+		{
+		iTimer->Cancel();
+		delete iTimer;
+		}
+	delete this;
+	}
+
+class CDmTest3 : public MDmTest
+	{
+public: 
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete() {};
+	};
+
+void CDmTest3::Perform()
+	{
+	//
+	// Test simple error situation
+	//
+	RDmDomainManager manager;
+	TInt r = manager.Connect();
+	test(r == KErrNone);
+
+	RDmDomainManager manager1;
+	r = manager1.Connect();
+	test(r == KErrInUse);
+
+	RDmDomain domain;
+	r = domain.Connect(KDmIdNone);
+	test(r == KDmErrBadDomainId);
+	CDmTestMember*		testMember;
+	testMember = new CDmTestMember(KDmHierarchyIdPower, KDmIdApps, 1, this);
+	test (testMember != NULL);
+
+	TRequestStatus status;
+	manager.RequestDomainTransition(KDmIdApps, EPwStandby, status);
+	test(status.Int() == KRequestPending);
+
+	TRequestStatus status1;
+	manager.RequestDomainTransition(KDmIdApps, EPwActive, status1);
+	User::WaitForRequest(status1);
+	test(status1.Int() == KDmErrBadSequence);
+	User::WaitForRequest(status);
+	test(status.Int() == KErrTimedOut);
+
+	// Since this test doesn't start the active scheduler, a domain member's RunL() will 
+	// not get called so we need to re-request a domain transition notification manually
+	User::WaitForRequest(testMember->iStatus);
+	test(testMember->iStatus.Int() == KErrNone);
+	testMember->iDomain.RequestTransitionNotification(testMember->iStatus);
+
+	manager.RequestDomainTransition(KDmIdApps, EPwActive, status);
+	test(status.Int() == KRequestPending);
+	manager.CancelTransition();
+	test(status.Int() == KErrCancel);
+	manager.CancelTransition();
+	User::WaitForRequest(status);
+	test(status.Int() == KErrCancel);
+
+	testMember->iDomain.CancelTransitionNotification();
+
+	delete testMember;
+	
+	domain.Close();
+	manager.Close();
+	}
+
+TInt CDmTest3::TransitionNotification(MDmDomainMember& /*aDomainMember*/)
+	{
+	test(0);
+	return KErrAbort;	// don't acknowledge
+	}
+
+void CDmTest3::Release()
+	{
+	delete this;
+	}
+
+class CDmTest4 : public MDmTest
+	{
+public: 
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete() {};
+private:
+	void ExecSlave(TUint arg);
+	};
+
+_LIT(KSecuritySlavePath, "t_domain_slave.exe");
+
+void CDmTest4::ExecSlave(TUint aArg)
+	{
+	RProcess proc;
+	TInt r = proc.Create(KSecuritySlavePath, TPtrC((TUint16*) &aArg, sizeof(aArg)/sizeof(TUint16)));
+	test(r == KErrNone);
+	TRequestStatus status;
+	proc.Logon(status);
+	proc.Resume();
+	User::WaitForRequest(status);
+
+    RDebug::Printf("CDmTest4::ExecSlave(%d) ExitType %d", aArg, proc.ExitType() );
+    RDebug::Printf("CDmTest4::ExecSlave(%d) ExitReason %d", aArg, proc.ExitReason() );
+	test(proc.ExitType() == EExitKill);
+//	test(proc.ExitReason() == KErrPermissionDenied);
+
+	CLOSE_AND_WAIT(proc);
+	}
+
+//! @SYMTestCaseID PBASE-T_DOMAIN-4
+//! @SYMTestType CT
+//! @SYMTestCaseDesc Dmain manager security tests
+//! @SYMREQ 3722
+//! @SYMTestActions Launches a separate process with no capabilities
+//! @SYMTestExpectedResults  DM APIs should fail with KErrPermissionDenied
+//! @SYMTestPriority High
+//! @SYMTestStatus Defined
+void CDmTest4::Perform()
+	{
+	//
+	// Security tests
+	//
+
+	ExecSlave(0);
+
+    ExecSlave(1);
+
+	}
+
+TInt CDmTest4::TransitionNotification(MDmDomainMember& /*aDomainMember*/)
+	{
+	test(0);
+	return KErrNone;
+	}
+
+void CDmTest4::Release()
+	{
+	delete this;
+	}
+
+// Test hierarchy tests
+class CDmTestStartupMember : public CDmTestMember
+	{
+public:
+	CDmTestStartupMember(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest*);
+
+public:
+private:
+	};
+
+CDmTestStartupMember::CDmTestStartupMember(TDmHierarchyId aHierarchy, TDmDomainId aId, TUint32 aOrdinal, MDmTest* aTest) 
+	: CDmTestMember(aHierarchy, aId, aOrdinal, aTest)
+	{
+	}
+
+// Simultaneously testing of test domain defined in DomainPolicy99.dll
+// and the power domain defined in DomainPolicy.dll
+class CDmTest5 : public CActive, public MDmTest
+	{
+public: 
+	// from CActive
+	void RunL();
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete();
+	CDmTest5(TDmDomainId aPowerId, TDmDomainId aTestId, TDmDomainState aPowerState, TDmDomainState aTestState) : 
+		CActive(CActive::EPriorityStandard), 
+		iPowerDomainId(aPowerId), iTestDomainId(aTestId), iPowerState(aPowerState), iTestState(aTestState) {}
+protected:
+	// from CActive
+	virtual void DoCancel();
+
+private:
+	enum { KMembersMax = 16 };
+	enum TAckMode{ KAckAlways, KAckNever, KAckError, KAckOddDomainsOnly };
+
+	CDmTestMember*		iTestMembers[KMembersMax]; 
+	CDomainMemberAo*	iPowerMembers[KMembersMax]; 
+
+	RDmDomainManager	iTestDomainManager;
+	
+	TDmDomainId			iPowerDomainId;
+	TDmDomainId			iTestDomainId;
+
+	TDmDomainState		iPowerState;
+	TDmDomainState		iTestState;
+
+	// level number for iTestDomainId. E.g 1 for KDmIdRoot, 2 for KDmIdTestA, etc.
+	TInt				iTestDomainLevel;	
+
+	TDmTraverseDirection iTraverseDirection;
+
+	TAckMode			iAckMode;
+
+public:
+	TInt				iTestNotifications;
+	TInt				iPowerNotifications;
+	TInt				iTestNotificationsExpected;
+	TInt				iPowerNotificationsExpected;
+
+	TInt				iTransitionsCompleted;
+	TInt				iTransitionsExpected;
+	};
+
+
+
+//! @SYMTestCaseID PBASE-T_DOMAIN-5
+//! @SYMTestType CT
+//! @SYMTestCaseDesc Connects to two domain hierarchies simulteneously and perform various tests
+//! @SYMREQ 3704,3705,3706,3707,3708,3709,3710,3711,3720,3721,3724,3725,3726,3727
+//! @SYMTestActions Open two hiearchies simultaneously and perform various actions.
+//! @SYMTestExpectedResults  All tests should pass
+//! @SYMTestPriority High
+//! @SYMTestStatus Defined
+void CDmTest5::Perform()
+	{
+
+ 	__UHEAP_MARK;
+
+	//
+	// Test domain transitions
+	//
+	CActiveScheduler::Add(this);
+
+	TInt r = RDmDomainManager::AddDomainHierarchy(KDmHierarchyIdTest);
+
+    RDebug::Printf("RDmDomainManager::AddDomainHierarchy returns %d", r );
+
+	test(r == KErrNone);
+
+	CDomainManagerAo* powerDomainManager = NULL;
+	TRAP(r, powerDomainManager = CDomainManagerAo::NewL(KDmHierarchyIdPower, *this));
+	test (powerDomainManager != NULL);
+
+	r = CDomainManagerAo::AddDomainHierarchy(KDmHierarchyIdPower);
+	test(r == KErrNone);
+
+	//*************************************************
+	//	Test 5a - connect to two domain hierarchies simultaneously
+	//*************************************************
+	test.Next(_L("Test 5a - connect to two domain hierarchies simultaneously"));
+
+	test.Printf(_L("Domain id = 0x%x, Target State = 0x%x\n"), iTestDomainId, iTestState);
+
+	TInt testMemberCount = 0;
+
+	// Add some test hierarchy members - these use the RDmDomain API
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdRoot, ORDINAL_FROM_DOMAINID0(KDmIdRoot), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdRoot, ORDINAL_FROM_DOMAINID0(KDmIdRoot), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row 1
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestA, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestA), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestB, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestB), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestC, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestC), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row2
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestAA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestA, KDmIdTestAA), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestAB, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestA, KDmIdTestAB), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestBA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestB, KDmIdTestBA), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestCA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestC, KDmIdTestCA), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row 3
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestABA, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestA, KDmIdTestAB, KDmIdTestABA), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestABB, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestA, KDmIdTestAB, KDmIdTestABB), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+	iTestMembers[testMemberCount] = new CDmTestMember(KDmHierarchyIdTest, KDmIdTestCAA, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestC, KDmIdTestCA, KDmIdTestCAA), this);
+	test(iTestMembers[testMemberCount++] != NULL);
+
+	// add some power hierarchy members - these use the CDmDomain AO API
+	TInt powerMemberCount = 0;
+	TRAP(r, iPowerMembers[powerMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdPower, KDmIdRoot, KDmIdRoot, this));
+	test(iTestMembers[powerMemberCount++] != NULL);
+	TRAP(r, iPowerMembers[powerMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdPower, KDmIdApps, KDmIdApps, this));
+	test(iTestMembers[powerMemberCount++] != NULL);
+	TRAP(r, iPowerMembers[powerMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdPower, KDmIdUiApps, KDmIdUiApps, this));
+	test(iTestMembers[powerMemberCount++] != NULL);
+
+
+	RArray<const TTransitionFailure> testFailures;
+	TInt testFailureCount;
+	RArray<const TTransitionFailure> powerFailures;
+	TInt powerFailureCount;
+
+
+
+	// calculate the expected number of notifications
+	TInt expectedTestNotifications = 0;
+	TInt leafNodes = 0;
+	
+
+	// work out the domain level, the number of leaf nodes and the expected number of 
+	// notifications for the domain that is being transitioned
+	switch(iTestDomainId)
+		{
+		case KDmIdRoot		:	iTestDomainLevel = 1; leafNodes = 5; expectedTestNotifications = testMemberCount; break;
+		case KDmIdTestA		:	iTestDomainLevel = 2; leafNodes = 3; expectedTestNotifications = 5; break;
+		case KDmIdTestB		:	iTestDomainLevel = 2; leafNodes = 1; expectedTestNotifications = 2; break;
+		case KDmIdTestC		:	iTestDomainLevel = 2; leafNodes = 1; expectedTestNotifications = 3; break;
+
+		case KDmIdTestAA	:	iTestDomainLevel = 3; leafNodes = 1; expectedTestNotifications = 1; break;
+		case KDmIdTestAB	:	iTestDomainLevel = 3; leafNodes = 2; expectedTestNotifications = 3; break;
+		case KDmIdTestBA	:	iTestDomainLevel = 3; leafNodes = 1; expectedTestNotifications = 1; break;
+		case KDmIdTestCA	:	iTestDomainLevel = 3; leafNodes = 1; expectedTestNotifications = 2; break;
+
+		case KDmIdTestABA	:	iTestDomainLevel = 4; leafNodes = 1; expectedTestNotifications = 1; break;
+		case KDmIdTestABB	:	iTestDomainLevel = 4; leafNodes = 1; expectedTestNotifications = 1; break;
+		case KDmIdTestCAA	:	iTestDomainLevel = 4; leafNodes = 1; expectedTestNotifications = 1; break;
+		default:
+			test(0);
+		}
+	test.Printf(_L("Test Domain id = 0x%x, Level = %d, Target State = 0x%x, expected notifications = %d, leafNodes = %d\n"), 
+		iTestDomainId, iTestDomainLevel, iTestState, expectedTestNotifications, leafNodes);
+
+	TInt expectedPowerNotifications = 0;
+	switch(iPowerDomainId)
+		{
+		case KDmIdRoot		:	expectedPowerNotifications = powerMemberCount; break;
+		case KDmIdApps		:	expectedPowerNotifications = 1; break;
+		case KDmIdUiApps	:	expectedPowerNotifications = 1; break;
+		default:
+			test(0);
+		}
+
+
+
+	// connect to the test hierarchy
+	r = iTestDomainManager.Connect(KDmHierarchyIdTest);
+	test(r == KErrNone);
+
+	// verify that we can't connect to the same hierarchy more than once
+	RDmDomainManager	domainManager;
+	r = domainManager.Connect(KDmHierarchyIdTest);
+	test(r == KErrInUse);
+
+
+
+	//*************************************************
+	// Test 5b - request a positive transition
+	// issue a positive  transition (i.e. transition state increases)
+	// and request that the test domain use ETraverseParentsFirst
+	//*************************************************
+	test.Next(_L("Test 5b - request a positive transition"));
+	iAckMode = KAckAlways;
+
+	iTransitionsCompleted = iTestNotifications = iPowerNotifications = 0;
+	iPowerNotificationsExpected = 0;
+	iTestNotificationsExpected = expectedTestNotifications;
+	iTransitionsExpected = 1;
+
+	// DON'T request any domain transition on the power hierarchy
+	// powerDomainManager->RequestDomainTransition(iPowerDomainId, EPwActive);
+	// request a domain transition on the test hierarchy
+	iTraverseDirection = ETraverseParentsFirst;
+	if (iTestDomainId == KDmIdRoot)
+		iTestDomainManager.RequestSystemTransition(iTestState, ETraverseDefault, CActive::iStatus);
+	else
+		iTestDomainManager.RequestDomainTransition(iTestDomainId, iTestState, ETraverseDefault, CActive::iStatus);
+	CActive::SetActive();
+
+	CActiveScheduler::Start();
+	test(powerDomainManager->iStatus == KErrNone);
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test(iPowerNotifications == iPowerNotificationsExpected);
+
+	//*************************************************
+	// Test 5c- verify domains are in correct state
+	//*************************************************
+	test.Next(_L("Test 5c- verify domains are in correct state"));
+	RDmDomain domainMember;
+	r = domainMember.Connect(KDmHierarchyIdTest, iTestDomainId);
+	test (r == KErrNone);
+	TDmDomainState state = domainMember.GetState();
+	domainMember.Close();
+	test (state == iTestState);
+
+	// if the transition request is not on the root, verify that that 
+	// the root domain and the transition domain are in different states
+	if (iTestDomainId != KDmIdRoot && iTestState != EStartupCriticalStatic)
+		{
+		r = domainMember.Connect(KDmHierarchyIdTest, KDmIdRoot);
+		test (r == KErrNone);
+		TDmDomainState state = domainMember.GetState();
+		domainMember.Close();
+		test (state != iTestState);
+		}
+
+
+	//*************************************************
+	// Test 5d- request a negative transition
+	// issue a negative transition (i.e. transition state decreases)
+	// and request that the test domain use ETraverseChildrenFirst
+	//*************************************************
+	test.Next(_L("Test 5d- request a negative transition"));
+	iAckMode = KAckAlways;
+	iTestState--;	// EStartupCriticalStatic;
+	iPowerState--;	// EPwStandby
+
+	iTransitionsCompleted = iTestNotifications = iPowerNotifications = 0;
+	iPowerNotificationsExpected = expectedPowerNotifications;
+	iTestNotificationsExpected = expectedTestNotifications;
+	iTransitionsExpected = 2;
+
+	// DO request a domain transition on the power hierarchy
+	powerDomainManager->RequestDomainTransition(iPowerDomainId, iPowerState, ETraverseDefault);
+
+	// request a domain transition on the test hierarchy
+	iTraverseDirection = ETraverseChildrenFirst;
+	iTestDomainManager.RequestDomainTransition(iTestDomainId, iTestState, iTraverseDirection, CActive::iStatus);
+	CActive::SetActive();
+
+	// wait for all test & power transitions to complete
+	CActiveScheduler::Start();
+	test(powerDomainManager->iStatus == KErrNone);
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test(iPowerNotifications == iPowerNotificationsExpected);
+	
+
+	//*************************************************
+	// Test 5e- request a positive transition, with zero acknowledgements
+	// issue a positive transition with no members acknowledging the transition
+	//*************************************************
+	test.Next(_L("Test 5e- request a positive transition, with zero acknowledgements"));
+	iAckMode = KAckNever;
+	iTestState++;		// EStartupCriticalDynamic;
+	iPowerState++;		// EPwActive
+
+	// power hierarchy should continue on failure, so we all power domains should transition
+	// test hierarchy should stop on failure, so should get notifications from all leaf nodes
+	iTransitionsCompleted = iTestNotifications = iPowerNotifications = 0;
+	iPowerNotificationsExpected = expectedPowerNotifications;
+	iTestNotificationsExpected = leafNodes;	// 5 leaf nodes for root domain
+	iTransitionsExpected = 2;
+
+	// DO request a domain transition on the power hierarchy
+	powerDomainManager->RequestDomainTransition(iPowerDomainId, iPowerState, ETraverseDefault);
+
+	// request a domain transition on the test hierarchy
+	iTraverseDirection = ETraverseChildrenFirst;
+	iTestDomainManager.RequestDomainTransition(iTestDomainId, iTestState, iTraverseDirection, CActive::iStatus);
+	CActive::SetActive();
+
+	// wait for all test & power transitions to complete
+	CActiveScheduler::Start();
+	test(powerDomainManager->iStatus == KErrTimedOut);
+	test(iStatus == KErrTimedOut);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test(iPowerNotifications == iPowerNotificationsExpected);
+	
+	// get the failures on the test hierarchy
+	testFailureCount = iTestDomainManager.GetTransitionFailureCount();
+	test (testFailureCount == 1);
+
+	r = iTestDomainManager.GetTransitionFailures(testFailures);
+	test(r == KErrNone);
+	test(testFailureCount == testFailures.Count());
+
+	test.Printf(_L("Test failures = %d\n"), testFailureCount);
+	TInt i;
+	for (i=0; i<testFailureCount; i++)
+		{
+		test.Printf(_L("%d: iDomainId %d, iError %d\n"), 
+			i, testFailures[i].iDomainId, testFailures[i].iError);
+		test(testFailures[i].iError == KErrTimedOut);
+		}
+
+	// get the failures on the power hierarchy
+	powerFailureCount = powerDomainManager->GetTransitionFailureCount();
+	test (powerFailureCount == expectedPowerNotifications);
+
+	r = powerDomainManager->GetTransitionFailures(powerFailures);
+	test(r == KErrNone);
+	test(powerFailureCount == powerFailures.Count());
+
+	test.Printf(_L("Power failures = %d\n"), powerFailureCount);
+	for (i=0; i<powerFailureCount; i++)
+		{
+		test.Printf(_L("%d: iDomainId %d, iError %d\n"), 
+			i, powerFailures[i].iDomainId, powerFailures[i].iError);
+		test(powerFailures[i].iError == KErrTimedOut);
+		}
+
+	
+	//*************************************************
+	// Test 5f- request a positive transition, with error acknowledgements
+	// issue a positive transition with all members nack'ing the transition
+	//*************************************************
+	test.Next(_L("Test 5f- request a positive transition, with error acknowledgements"));
+	iAckMode = KAckError;
+	iTestState++;		
+	iPowerState++;		
+
+	// power hierarchy should continue on failure, so all power domains should transition
+	// test hierarchy should stop on failure, so should get notifications from 
+	// anything from 1 to all the leaf nodes
+	iTransitionsCompleted = iTestNotifications = iPowerNotifications = 0;
+	iPowerNotificationsExpected = expectedPowerNotifications;
+	iTestNotificationsExpected = leafNodes;	// 5 leaf nodes for root domain
+	iTransitionsExpected = 2;
+
+	// DO request a domain transition on the power hierarchy
+	powerDomainManager->RequestDomainTransition(iPowerDomainId, iPowerState, ETraverseDefault);
+
+	// request a domain transition on the test hierarchy
+	iTraverseDirection = ETraverseChildrenFirst;
+	iTestDomainManager.RequestDomainTransition(iTestDomainId, iTestState, iTraverseDirection, CActive::iStatus);
+	CActive::SetActive();
+
+	// wait for all test & power transitions to complete
+	CActiveScheduler::Start();
+	test(powerDomainManager->iStatus == KErrGeneral);
+	test(iStatus == KErrGeneral);
+	test(iTestNotifications <= iTestNotificationsExpected);
+	test(iPowerNotifications == iPowerNotificationsExpected);
+	
+	// get the failures on the test hierarchy
+	testFailureCount = iTestDomainManager.GetTransitionFailureCount();
+	test (testFailureCount == 1);
+
+	r = iTestDomainManager.GetTransitionFailures(testFailures);
+	test(r == KErrNone);
+	test(testFailureCount == testFailures.Count());
+
+	test.Printf(_L("Test failures = %d\n"), testFailureCount);
+	for (i=0; i<testFailureCount; i++)
+		{
+		test.Printf(_L("%d: iDomainId %d, iError %d\n"), 
+			i, testFailures[i].iDomainId, testFailures[i].iError);
+		test(testFailures[i].iError == KErrGeneral);
+		}
+
+	// get the failures on the power hierarchy
+	powerFailureCount = powerDomainManager->GetTransitionFailureCount();
+	test (powerFailureCount == expectedPowerNotifications);
+
+	r = powerDomainManager->GetTransitionFailures(powerFailures);
+	test(r == KErrNone);
+	test(powerFailureCount == powerFailures.Count());
+
+	test.Printf(_L("Power failures = %d\n"), powerFailureCount);
+	for (i=0; i<powerFailureCount; i++)
+		{
+		test.Printf(_L("%d: iDomainId %d, iError %d\n"), 
+			i, powerFailures[i].iDomainId, powerFailures[i].iError);
+		test(powerFailures[i].iError == KErrGeneral);
+		}
+
+	
+	// cleanup
+
+	testFailures.Reset();
+	powerFailures.Reset();
+
+	iTestDomainManager.Close();
+	delete powerDomainManager;
+	powerDomainManager = NULL;
+
+	CDmTestMember** mt;
+	for (mt = iTestMembers; *mt; ++mt)
+		delete *mt;
+
+	CDomainMemberAo** mp;
+	for (mp = iPowerMembers; *mp; ++mp)
+		delete *mp;
+
+
+	// restore the domain hierarchies to their initial state so as not to 
+	// upset any subsequent tests which rely on this
+	{
+	RDmDomainManager manager;
+	TInt r = manager.Connect();
+	test (r == KErrNone);
+	TRequestStatus status;
+	manager.RequestDomainTransition(KDmIdRoot, EPwActive, status);
+	test(status.Int() == KRequestPending);
+	User::WaitForRequest(status);
+	test(status.Int() == KErrNone);
+	manager.Close();
+	
+	r = manager.Connect(KDmHierarchyIdTest);
+	test (r == KErrNone);
+	manager.RequestDomainTransition(KDmIdRoot, EStartupCriticalStatic, ETraverseDefault, status);
+	test(status.Int() == KRequestPending);
+	User::WaitForRequest(status);
+	test(status.Int() == KErrNone);
+	manager.Close();
+	}
+
+ 	__UHEAP_MARKEND;
+	}
+
+// This handles a transition notification from either a power domain member or 
+// a test domain member.
+// Verifies that the domain state is as expected.
+// Updates the number of notifications for each hierarchy and verifies that all parent 
+// domains have transitioned already (for parent-to-child transitions) or that all child 
+// domains have been transitioned already (for child-to-parent transitions).
+
+TInt CDmTest5::TransitionNotification(MDmDomainMember& aDomainMember)
+	{
+	if (aDomainMember.HierarchyId() == KDmHierarchyIdPower)
+		iPowerNotifications++;
+	else
+		iTestNotifications++;
+
+	if (aDomainMember.HierarchyId() == KDmHierarchyIdPower)
+		{
+		__PRINT((_L("CDmTest5::TransitionNotification(), Hierarchy = %d, iOrdinal = 0x%08X, state = 0x%x, status = %d\n"), 
+			aDomainMember.HierarchyId(), aDomainMember.Ordinal(), aDomainMember.State(), aDomainMember.Status()));
+		test(aDomainMember.State() == iPowerState);
+		}
+	else if (aDomainMember.HierarchyId() == KDmHierarchyIdTest)
+		{
+		TBuf16<4> buf;
+		GetDomainDesc(aDomainMember.Ordinal(), buf);
+
+		__PRINT((_L("CDmTest5::TransitionNotification(), Hierarchy = %d, domain = %S, iOrdinal = 0x%08X, state = 0x%x, status = %d\n"), 
+			aDomainMember.HierarchyId(), &buf, aDomainMember.Ordinal(), aDomainMember.State(), aDomainMember.Status()));
+		test(aDomainMember.State() == iTestState);
+		}
+	else
+		{
+		test(0);
+		}
+
+	// if we're going from parent to child, 
+	// check that each parent domain has received a notification already
+	// if not, check that each child domain has received a notification already
+
+	CDmTestMember** mp;
+
+	if (aDomainMember.HierarchyId() == KDmHierarchyIdTest && iAckMode == KAckAlways)
+		{
+
+		if (iTraverseDirection == ETraverseParentsFirst)
+			{
+			TUint ordThis = aDomainMember.Ordinal();
+			TUint ordParent = PARENT_ORDINAL(ordThis);
+
+			TInt levelParent = ORDINAL_LEVEL(ordParent);
+
+			TBuf16<4> buf;
+			GetDomainDesc(ordParent, buf);
+			if (levelParent >= iTestDomainLevel)
+				{
+				__PRINT((_L("Searching for parent domain = %S, ordinal = %08X \n"), &buf, ordParent));
+				for (mp = iTestMembers; *mp; ++mp)
+					{
+					if ((*mp)->Ordinal() == ordParent)
+						{
+						TBuf16<4> buf;
+						GetDomainDesc((*mp)->Ordinal(), buf);
+						__PRINT((_L("Found parent (%S). notification = %d\n"), &buf, (*mp)->Notifications()));
+						test ((*mp)->Notifications() == aDomainMember.Notifications());
+						break;
+						}
+					}
+				}
+			}
+		else
+			{
+			__PRINT((_L("Searching for children\n")));
+			for (mp = iTestMembers; *mp; ++mp)
+				{
+
+				TUint ordParent = PARENT_ORDINAL((*mp)->Ordinal());
+				if (ordParent == aDomainMember.Ordinal())
+					{
+					TBuf16<4> buf;
+					GetDomainDesc((*mp)->Ordinal(), buf);
+					__PRINT((_L("Found child (%S). notification = %d\n"), &buf, (*mp)->Notifications()));
+					test ((*mp)->Notifications() == aDomainMember.Notifications());
+					}
+				}
+			}
+		}
+
+	TInt ackError;
+	switch (iAckMode)
+		{
+		case KAckNever:
+			ackError = KErrAbort;
+			break;
+		case KAckError:		// return an error to the DM
+			ackError = KErrGeneral;
+			break;
+		case KAckOddDomainsOnly:
+			ackError = (aDomainMember.DomainId() & 1)?KErrNone:KErrAbort;
+			break;
+		case KAckAlways:
+		default:
+			ackError = KErrNone;
+			break;
+		}
+	return ackError;
+	}
+
+void CDmTest5::RunL()
+	{
+	iTransitionsCompleted++;
+
+	__PRINT((_L("CDmTest5::RunL(), error = %d, iTestNotifications %d, iPowerNotifications %d\n"), 
+		iStatus.Int(), iTestNotifications , iPowerNotifications));
+
+	if (iTransitionsCompleted == iTransitionsExpected)
+		CActiveScheduler::Stop();
+	}
+
+void CDmTest5::TransitionRequestComplete()
+	{
+	iTransitionsCompleted++;
+
+	__PRINT((_L("CDmTest5::TransitionRequestComplete(), error = %d, iTestNotifications %d, iPowerNotifications %d\n"), 
+		iStatus.Int(), iTestNotifications , iPowerNotifications));
+	
+	if (iTransitionsCompleted == iTransitionsExpected)
+		CActiveScheduler::Stop();
+	}
+
+void CDmTest5::DoCancel()
+	{
+	test(0);
+	}
+
+void CDmTest5::Release()
+	{
+	delete this;
+	}
+
+const TInt KMembersMax = 16;
+
+// Negative testing 
+class CDmTest6 : public CActive, public MDmTest
+	{
+public:
+	enum 
+	{
+	ENegTestTransitionNoConnect,
+	ENegTestGetStateNoConnect,
+	ENegTestTransitionInvalidMode
+	};
+
+	class TData 
+		{
+	public:
+		inline TData(TInt aTest) : iTest(aTest){};
+		TInt iTest;
+		};
+
+public: 
+	// from CActive
+	void RunL();
+ 
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete();
+
+
+	CDmTest6() : CActive(CActive::EPriorityStandard) {}
+
+protected:
+	// from CActive
+	virtual void DoCancel();
+
+private:
+	static TInt PanicThreadFunc(TAny* aData);
+	void PanicTest(TInt aTestNumber);
+
+
+	CDomainMemberAo*	iTestMembers[KMembersMax]; 
+	CDomainManagerAo*	iTestDomainManager;
+	
+	TDmDomainId			iTestDomainId;
+	TDmDomainState		iTestState;
+
+public:
+	TInt				iTestNotifications;
+	TInt				iTestNotificationsExpected;
+
+	TInt				iTransitionsCompleted;
+	TInt				iTransitionsExpected;
+	};
+
+TInt CDmTest6::PanicThreadFunc(TAny* aData)
+	{
+	const TData* data = (const TData*)aData;
+	switch (data->iTest)
+		{
+		case ENegTestTransitionNoConnect:
+			{
+			// request a transition notification without connecting first (should panic)
+			RDmDomain domainMember;
+			TRequestStatus status;
+			User::SetJustInTime(EFalse);
+			domainMember.RequestTransitionNotification(status);
+			}
+			break;
+		case ENegTestGetStateNoConnect:
+			{
+			// Get the domain state without connecting (should panic)
+			RDmDomain domainMember;
+			User::SetJustInTime(EFalse);
+			domainMember.GetState();
+			}
+			break;
+		case ENegTestTransitionInvalidMode:
+			{
+			RDmDomainManager manager;
+			TRequestStatus status;
+			TInt r = manager.Connect(KDmHierarchyIdTest);
+			test(r == KErrNone);
+
+			User::SetJustInTime(EFalse);
+			manager.RequestDomainTransition(KDmIdRoot, 0, TDmTraverseDirection(-1), status);
+			}
+			break;
+		default:
+			break;
+		}
+	return KErrNone;
+	}
+
+void CDmTest6::PanicTest(TInt aTestNumber)
+	{
+	test.Printf(_L("panic test number %d\n"), aTestNumber);
+
+	TBool jit = User::JustInTime();
+
+	TData data(aTestNumber);
+
+	TInt KHeapSize=0x2000;
+
+	RThread thread;
+	TInt ret = thread.Create(KThreadName, PanicThreadFunc, KDefaultStackSize, KHeapSize, KHeapSize, &data);
+	test(KErrNone == ret);
+	TRequestStatus stat;
+	thread.Logon(stat);
+	thread.Resume();
+	User::WaitForRequest(stat);
+
+	User::SetJustInTime(jit);
+
+	// The thread must panic
+	test(thread.ExitType() == EExitPanic);
+	TInt exitReason = thread.ExitReason();
+	test.Printf(_L("panic test exit reason = %d\n"), exitReason);
+
+	switch(aTestNumber)
+		{
+		case ENegTestTransitionNoConnect:
+			test (exitReason == EBadHandle);
+			break;
+		case ENegTestGetStateNoConnect:
+			test (exitReason == EBadHandle);
+			break;
+		case ENegTestTransitionInvalidMode:
+			break;
+		default:
+			break;
+		}
+
+	CLOSE_AND_WAIT(thread);
+	}
+
+
+//! @SYMTestCaseID PBASE-T_DOMAIN-6
+//! @SYMTestType CT
+//! @SYMTestCaseDesc Negative testing
+//! @SYMPREQ 810
+//! @SYMTestActions Various negative tests
+//! @SYMTestExpectedResults  All tests should pass
+//! @SYMTestPriority High
+//! @SYMTestStatus Defined
+void CDmTest6::Perform()
+	{
+
+ 	__UHEAP_MARK;
+
+	CActiveScheduler::Add(this);
+
+	CDomainManagerAo* iTestDomainManager = NULL;
+	TRAP_IGNORE(iTestDomainManager = CDomainManagerAo::NewL(KDmHierarchyIdTest, *this));
+	test (iTestDomainManager != NULL);
+
+	TInt r = CDomainManagerAo::AddDomainHierarchy(KDmHierarchyIdTest);
+	test(r == KErrNone);
+
+	//*************************************************
+	// Test 6a - Connect to the same hierarchy twice
+	//*************************************************
+	test.Next(_L("Test 6a - Connect to the same hierarchy twice"));
+
+	// verify that we can't connect to the same hierarchy more than once
+	CDomainManagerAo* testDomainManager = NULL;
+	TRAP(r, testDomainManager = CDomainManagerAo::NewL(KDmHierarchyIdTest, *this));
+	test(r == KErrInUse);
+	test (testDomainManager == NULL);
+
+
+	TInt testMemberCount = 0;
+
+	// Add some test hierarchy members
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdRoot, ORDINAL_FROM_DOMAINID0(KDmIdRoot), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdRoot, ORDINAL_FROM_DOMAINID0(KDmIdRoot), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row 1
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestA, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestB, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestB), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestC, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestC), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row2
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestAA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestA, KDmIdTestAA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestAB, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestA, KDmIdTestAB), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestBA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestB, KDmIdTestBA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestCA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestC, KDmIdTestCA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row 3
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestABA, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestA, KDmIdTestAB, KDmIdTestABA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestABB, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestA, KDmIdTestAB, KDmIdTestABB), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestCAA, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestC, KDmIdTestCA, KDmIdTestCAA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+
+
+	//*************************************************
+	// Test 6b change to current state
+	//*************************************************
+	test.Next(_L("Test 6b change to current state"));
+	iTestState =  EStartupCriticalStatic;
+	iTestDomainId = KDmIdRoot;
+
+	iTransitionsCompleted = iTestNotifications = 0;
+	iTestNotificationsExpected = testMemberCount;
+	iTransitionsExpected = 1;
+
+	// request a domain transition
+	iTestDomainManager->RequestDomainTransition(iTestDomainId, iTestState, ETraverseDefault);
+
+	// wait for test transitions to complete
+	CActiveScheduler::Start();
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	
+
+	// cancel a member notification request 
+	//*************************************************
+	// Test 6c cancel a member notification request
+	//*************************************************
+	test.Next(_L("Test 6c cancel a member notification request"));
+	RDmDomain domainMember;
+	TRequestStatus status;
+	domainMember.Connect(KDmHierarchyIdTest, iTestDomainId);
+	domainMember.RequestTransitionNotification(status);
+	domainMember.CancelTransitionNotification();
+	User::WaitForRequest(status);
+	domainMember.Close();
+
+	//*************************************************
+	// Test 6d cancel a member notification request without having first requested a notification
+	//*************************************************
+	test.Next(_L("Test 6d cancel a member notification request without having first requested a notification"));
+	domainMember.Connect(KDmHierarchyIdTest, iTestDomainId);
+	domainMember.CancelTransitionNotification();
+	domainMember.Close();
+
+	//*************************************************
+	// Test 6e domain controller adds invalid hierarchy
+	//*************************************************
+	test.Next(_L("Test 6e domain controller connects to invalid hierarchy"));
+	r = RDmDomainManager::AddDomainHierarchy(TDmHierarchyId(-1));
+	test(r == KErrBadHierarchyId);
+
+	//*************************************************
+	// Test 6f domain member connects to invalid hierarchy
+	//*************************************************
+	test.Next(_L("Test 6f domain member connects to invalid hierarchy"));
+	r = domainMember.Connect(TDmHierarchyId(-1), TDmDomainId(KDmIdRoot));
+	test (r == KErrBadHierarchyId);
+
+	//*************************************************
+	// Test 6g domain member connects to valid hierarchy but invalid domain
+	//*************************************************
+	test.Next(_L("Test 6g domain member connects to valid hierarchy but invalid domain"));
+	r = domainMember.Connect(KDmHierarchyIdTest, TDmDomainId(-1));
+	test (r == KDmErrBadDomainId);
+
+	delete iTestDomainManager;
+	iTestDomainManager = NULL;
+
+	// Panic tests
+
+	//*************************************************
+	// Test 6h request a transition notification without connecting first
+	//*************************************************
+	test.Next(_L("Test 6h request a transition notification without connecting first"));
+	PanicTest(ENegTestTransitionNoConnect);
+
+	//*************************************************
+	// Test 6i Get the domain state without connecting
+	//*************************************************
+	test.Next(_L("Test 6i Get the domain state without connecting"));
+	PanicTest(ENegTestGetStateNoConnect);
+
+	//*************************************************
+	// Test 6j request a transition notification with an invalid transition mode
+	//*************************************************
+	test.Next(_L("Test 6j request a transition notification with an invalid transition mode"));
+	PanicTest(ENegTestTransitionInvalidMode);
+
+
+	// cleanup
+
+	CDomainMemberAo** mt;
+	for (mt = iTestMembers; *mt; ++mt)
+		delete *mt;
+
+ 	__UHEAP_MARKEND;
+	}
+
+// This handles a transition notification from a test domain member.
+TInt CDmTest6::TransitionNotification(MDmDomainMember& aDomainMember)
+	{
+	TInt status = aDomainMember.Status();
+		
+	iTestNotifications++;
+
+	test (aDomainMember.HierarchyId() == KDmHierarchyIdTest);
+
+	TBuf16<4> buf;
+	GetDomainDesc(aDomainMember.Ordinal(), buf);
+
+	test.Printf(_L("CDmTest6::TransitionNotification(), Hierarchy = %d, domain = %S, iOrdinal = 0x%08X, state = 0x%x, status = %d\n"), 
+		aDomainMember.HierarchyId(), &buf, aDomainMember.Ordinal(), aDomainMember.State(), status);
+
+
+	return KErrNone;
+	}
+
+void CDmTest6::RunL()
+	{
+	iTransitionsCompleted++;
+
+	TInt error = iStatus.Int();
+
+	test.Printf(_L("CDmTest6::RunL(), error = %d, iTestNotifications %d\n"), 
+		error, iTestNotifications);
+
+	if (iTransitionsCompleted == iTransitionsExpected)
+		CActiveScheduler::Stop();
+	}
+
+void CDmTest6::TransitionRequestComplete()
+	{
+	iTransitionsCompleted++;
+
+	TInt error = iStatus.Int();
+	
+	test.Printf(_L("CDmTest6::TransitionRequestComplete(), error = %d, iTestNotifications %d\n"), 
+		error, iTestNotifications);
+	
+	if (iTransitionsCompleted == iTransitionsExpected)
+		CActiveScheduler::Stop();
+	}
+
+void CDmTest6::DoCancel()
+	{
+	test(0);
+	}
+
+void CDmTest6::Release()
+	{
+	delete this;
+	}
+
+// Transition progress Observer testing
+class CDmTest7 : public CActive, public MDmTest, public MHierarchyObserver
+	{
+public: 
+	// from CActive
+	void RunL();
+ 
+	// from MDmTest
+	void Perform();
+	void Release();
+	TInt TransitionNotification(MDmDomainMember& aDomainMember);
+	void TransitionRequestComplete();
+
+	// from MHierarchyObserver
+	virtual void TransProgEvent(TDmDomainId aDomainId, TDmDomainState aState);
+	virtual void TransFailEvent(TDmDomainId aDomainId, TDmDomainState aState, TInt aError);
+	virtual void TransReqEvent(TDmDomainId aDomainId, TDmDomainState aState);
+
+
+
+	CDmTest7(TDmDomainId aDomainId) : CActive(CActive::EPriorityStandard), iObservedDomainId(aDomainId) {}
+
+protected:
+	// from CActive
+	virtual void DoCancel();
+
+private:
+	void TestForCompletion();
+
+
+private:
+
+	enum { KMembersMax = 16 };
+
+	CDomainMemberAo*	iTestMembers[KMembersMax]; 
+	CDomainManagerAo*	iTestDomainManager;
+	
+	TDmDomainId			iTestDomainId;
+	TDmDomainState		iTestState;
+	TDmDomainId			iObservedDomainId;
+
+public:
+	TInt				iTestNotifications;
+	TInt				iTestNotificationsExpected;
+
+	TInt				iTransitionsCompleted;
+	TInt				iTransitionsExpected;
+
+	TInt				iTransProgEvents;
+	TInt				iTransFailEvents;
+	TInt				iTransReqEvents;
+
+	TInt				iTransProgEventsExpected;
+	TInt				iTransFailEventsExpected;
+	TInt				iTransReqEventsExpected;
+	};
+
+//! @SYMTestCaseID PBASE-T_DOMAIN-7
+//! @SYMTestType CT
+//! @SYMTestCaseDesc Transition progress Observer testing
+//! @SYMREQ REQ3723
+//! @SYMTestActions Various negative tests
+//! @SYMTestExpectedResults  All tests should pass
+//! @SYMTestPriority High
+//! @SYMTestStatus Defined
+void CDmTest7::Perform()
+	{
+
+ 	__UHEAP_MARK;
+
+	//
+	// Test domain transitions with activated observer
+	//
+	CActiveScheduler::Add(this);
+
+	TInt r = RDmDomainManager::AddDomainHierarchy(KDmHierarchyIdTest);
+	test(r == KErrNone);
+
+	CDomainManagerAo* iTestDomainManager = NULL;
+	TRAP_IGNORE(iTestDomainManager = CDomainManagerAo::NewL(KDmHierarchyIdTest, *this));
+	test (iTestDomainManager != NULL);
+
+	r = CDomainManagerAo::AddDomainHierarchy(KDmHierarchyIdTest);
+	test(r == KErrNone);
+
+	//*************************************************
+	// Test 7a - Testing observer notifications
+	//*************************************************
+	
+	test.Next(_L("Test 7a - Testing observer notifications"));
+
+	TInt testMemberCount = 0;
+
+	// Add some test hierarchy members
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdRoot, ORDINAL_FROM_DOMAINID0(KDmIdRoot), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row 1
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestA, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestB, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestB), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestC, ORDINAL_FROM_DOMAINID1(KDmIdRoot, KDmIdTestC), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row2
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestAA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestA, KDmIdTestAA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestAB, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestA, KDmIdTestAB), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestBA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestB, KDmIdTestBA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestCA, ORDINAL_FROM_DOMAINID2(KDmIdRoot, KDmIdTestC, KDmIdTestCA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	
+	// row 3
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestABA, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestA, KDmIdTestAB, KDmIdTestABA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestABB, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestA, KDmIdTestAB, KDmIdTestABB), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+	TRAP(r, iTestMembers[testMemberCount] = CDomainMemberAo::NewL(KDmHierarchyIdTest, KDmIdTestCAA, ORDINAL_FROM_DOMAINID3(KDmIdRoot, KDmIdTestC, KDmIdTestCA, KDmIdTestCAA), this));
+	test(iTestMembers[testMemberCount++] != NULL);
+
+	// create an observer
+	CHierarchyObserver* observer = NULL;
+	TRAP(r, observer = CHierarchyObserver::NewL(*this, KDmHierarchyIdTest));
+	test (r == KErrNone);
+	test(observer != NULL);
+	observer->StartObserver(iObservedDomainId, EDmNotifyAll);
+	
+	// request a state change
+	iTestState =  EStartupCriticalDynamic;
+	iTestDomainId = KDmIdRoot;
+	iTransitionsCompleted = iTestNotifications = 0;
+	iTestNotificationsExpected = testMemberCount;
+	iTransitionsExpected = 1;
+
+	iTransProgEvents = iTransFailEvents = iTransReqEvents = 0;
+	
+	iTransReqEventsExpected = iTransProgEventsExpected = observer->ObserverDomainCount();
+	iTransFailEventsExpected = 0;
+
+
+	iTestDomainManager->RequestDomainTransition(iTestDomainId, iTestState, ETraverseDefault);
+
+	// wait for test transitions to complete
+	CActiveScheduler::Start();
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test (iTransProgEvents == iTransProgEventsExpected);
+	test (iTransFailEvents == iTransFailEventsExpected);
+	test (iTransReqEvents == iTransReqEventsExpected);
+
+
+	// cleanup
+	delete observer; 
+	observer = NULL;
+
+	//*************************************************
+	// Test 7b - start & stop the observer
+	//*************************************************
+	test.Next(_L("Test 7b - start & stop the observer"));
+
+	// create an observer, start it stop and then start it again
+	TRAP(r, observer = CHierarchyObserver::NewL(*this, KDmHierarchyIdTest));
+	test (r == KErrNone);
+	test(observer != NULL);
+	observer->StartObserver(iObservedDomainId, EDmNotifyAll);
+	observer->StopObserver();
+	observer->StartObserver(iObservedDomainId, EDmNotifyAll);
+
+	// request a state change
+	iTestState++;
+	iTestDomainId = KDmIdRoot;
+	iTransitionsCompleted = iTestNotifications = 0;
+	iTestNotificationsExpected = testMemberCount;
+	iTransitionsExpected = 1;
+
+	iTransProgEvents = iTransFailEvents = iTransReqEvents = 0;
+	
+	iTransProgEventsExpected = iTransReqEventsExpected = observer->ObserverDomainCount();
+	iTransFailEventsExpected = 0;
+
+	iTestDomainManager->RequestDomainTransition(iTestDomainId, iTestState, ETraverseDefault);
+
+	// wait for test transitions to complete
+	CActiveScheduler::Start();
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test (iTransProgEvents == iTransProgEventsExpected);
+	test (iTransFailEvents == iTransFailEventsExpected);
+	test (iTransReqEvents == iTransReqEventsExpected);
+
+	// stop the observer & request another state change
+	observer->StopObserver();
+	iTestState++;
+	iTestDomainId = KDmIdRoot;
+	iTransitionsCompleted = iTestNotifications = 0;
+	iTestNotificationsExpected = testMemberCount;
+	iTransitionsExpected = 1;
+
+	iTransProgEvents = iTransFailEvents = iTransReqEvents = 0;
+	
+	iTransProgEventsExpected = 0;
+	iTransFailEventsExpected = 0;
+	iTransReqEventsExpected = 0;
+
+	iTestDomainManager->RequestDomainTransition(iTestDomainId, iTestState, ETraverseDefault);
+	// wait for test transitions to complete
+	CActiveScheduler::Start();
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test (iTransProgEvents == iTransProgEventsExpected);
+	test (iTransFailEvents == iTransFailEventsExpected);
+	test (iTransReqEvents == iTransReqEventsExpected);
+
+	// Start the observer again on a different domain and only ask for transition requests
+	// Then request another state change
+	observer->StartObserver((iObservedDomainId == KDmIdRoot)?KDmIdTestCA:KDmIdRoot, EDmNotifyTransRequest);
+	iTestState++;
+	iTestDomainId = KDmIdRoot;
+	iTransitionsCompleted = iTestNotifications = 0;
+	iTestNotificationsExpected = testMemberCount;
+	iTransitionsExpected = 1;
+
+	iTransProgEvents = iTransFailEvents = iTransReqEvents = 0;
+	
+	iTransReqEventsExpected = observer->ObserverDomainCount();
+	iTransProgEventsExpected = 0;
+	iTransFailEventsExpected = 0;
+
+
+	iTestDomainManager->RequestDomainTransition(iTestDomainId, iTestState, ETraverseDefault);
+	// wait for test transitions to complete
+	CActiveScheduler::Start();
+	test(iStatus == KErrNone);
+	test(iTestNotifications == iTestNotificationsExpected);
+	test (iTransProgEvents == iTransProgEventsExpected);
+	test (iTransFailEvents == iTransFailEventsExpected);
+	test (iTransReqEvents == iTransReqEventsExpected);
+
+	delete observer; 
+	observer = NULL;
+
+	//*************************************************
+	// Test 7c - invalid arguments testing for observer
+	//*************************************************
+	test.Next(_L("Test 7c - Invalid arguments testing for observer"));
+	
+	const TDmHierarchyId	KDmHierarchyIdInvalid = 110;
+	
+	test.Printf(_L("Test 7c.1 - create observer with invalid hierarchy Id\n"));
+	
+	// create an observer
+	TRAP(r, observer = CHierarchyObserver::NewL(*this, KDmHierarchyIdInvalid));
+	test (r == KErrBadHierarchyId);
+	
+	
+	test.Printf(_L("Test 7c.2 - Starting the observer with wrong domain Id\n"));
+	TRAP(r, observer = CHierarchyObserver::NewL(*this, KDmHierarchyIdTest));
+	test (r == KErrNone);
+	test(observer != NULL);
+
+	//Wrong domain Id
+	const TDmDomainId	KDmIdInvalid	= 0x0f;
+	r= observer->StartObserver(KDmIdInvalid, EDmNotifyAll);
+	test(r==KDmErrBadDomainId);
+
+	test.Printf(_L("Test 7c.3 - Trying to create second observer on the same hierarchy\n"));
+	TRAP(r, CHierarchyObserver::NewL(*this, KDmHierarchyIdTest));
+	test (r == KDmErrBadSequence);
+
+	
+	
+	//*************************************************
+	// Test 7d - Wrong sequence of API calls for observer
+	//*************************************************
+	test.Next(_L("Test 7d - Observer wrong sequence of calls"));
+	
+	test.Printf(_L("Test 7d.1 - Stopping Observer before starting it\n"));
+	r = observer->StopObserver();
+	test(r==KDmErrBadSequence);
+	
+	test.Printf(_L("Test 7d.2 - Starting Observer twice\n"));
+	r= observer->StartObserver(KDmIdRoot, EDmNotifyAll);
+	test(r==KErrNone);
+
+	r= observer->StartObserver(KDmIdRoot, EDmNotifyAll);
+	test(r==KDmErrBadSequence);
+
+	
+	delete observer;
+
+	/***************************************/
+
+	delete iTestDomainManager;
+	iTestDomainManager = NULL;
+
+	CDomainMemberAo** mt;
+	for (mt = iTestMembers; *mt; ++mt)
+		delete *mt;
+
+
+	// restore the domain hierarchies to their initial state so as not to 
+	// upset any subsequent tests which rely on this
+	{
+	RDmDomainManager manager;
+	TRequestStatus status;
+	TInt r = manager.Connect(KDmHierarchyIdTest);
+	test (r == KErrNone);
+	manager.RequestDomainTransition(KDmIdRoot, EStartupCriticalStatic, ETraverseDefault, status);
+	test(status.Int() == KRequestPending);
+	User::WaitForRequest(status);
+	test(status.Int() == KErrNone);
+	manager.Close();
+	}
+
+ 	__UHEAP_MARKEND;
+	}
+
+// This handles a transition notification from a test domain member.
+TInt CDmTest7::TransitionNotification(MDmDomainMember& aDomainMember)
+	{
+		
+	iTestNotifications++;
+
+	test (aDomainMember.HierarchyId() == KDmHierarchyIdTest);
+
+	TBuf16<4> buf;
+	GetDomainDesc(aDomainMember.Ordinal(), buf);
+
+	__PRINT((_L("CDmTest7::TransitionNotification(), Hierarchy = %d, domain = %S, iOrdinal = 0x%08X, state = 0x%x, status = %d\n"), 
+		aDomainMember.HierarchyId(), &buf, aDomainMember.Ordinal(), aDomainMember.State(), aDomainMember.Status()));
+
+	return KErrNone;
+	}
+
+void CDmTest7::RunL()
+	{
+	iTransitionsCompleted++;
+
+	__PRINT((_L("CDmTest7::RunL(), error = %d, iTestNotifications %d\n"), 
+		iStatus.Int(), iTestNotifications));
+
+	TestForCompletion();
+	}
+
+void CDmTest7::TransitionRequestComplete()
+	{
+	iTransitionsCompleted++;
+
+	__PRINT((_L("CDmTest7::TransitionRequestComplete(), error = %d, iTestNotifications %d\n"), 
+		iStatus.Int(), iTestNotifications));
+	
+	TestForCompletion();
+	}
+
+void CDmTest7::DoCancel()
+	{
+	test(0);
+	}
+
+void CDmTest7::Release()
+	{
+	delete this;
+	}
+
+void CDmTest7::TestForCompletion()
+	{
+
+	if (iTransitionsCompleted == iTransitionsExpected &&
+		iTransProgEvents == iTransProgEventsExpected && 
+		iTransFailEvents == iTransFailEventsExpected &&
+		iTransReqEvents == iTransReqEventsExpected)
+		{
+		CActiveScheduler::Stop();
+		}
+	}
+
+#ifdef _DEBUG
+void CDmTest7::TransProgEvent(TDmDomainId aDomainId, TDmDomainState aState)
+#else
+void CDmTest7::TransProgEvent(TDmDomainId /*aDomainId*/, TDmDomainState /*aState*/)
+#endif
+	{
+	iTransProgEvents++;
+	__PRINT((_L("CDmTest7::TransProgEvent(), aDomainId = %d, aState %d, iTransProgEvents %d\n"), 
+		aDomainId, aState, iTransProgEvents));
+	TestForCompletion();
+	}
+
+#ifdef _DEBUG
+void CDmTest7::TransFailEvent(TDmDomainId aDomainId, TDmDomainState aState, TInt aError)
+#else
+void CDmTest7::TransFailEvent(TDmDomainId /*aDomainId*/, TDmDomainState /*aState*/, TInt /*aError*/)
+#endif
+
+	{
+	iTransFailEvents++;
+	__PRINT((_L("CDmTest7::TransFailEvent(), aDomainId = %d, aState %d aError %d, iTransFailEvents %d\n"), 
+		aDomainId, aState, iTransFailEvents, aError));
+	TestForCompletion();
+	}
+
+#ifdef _DEBUG
+void CDmTest7::TransReqEvent(TDmDomainId aDomainId, TDmDomainState aState)
+#else
+void CDmTest7::TransReqEvent(TDmDomainId /*aDomainId*/, TDmDomainState /*aState*/)
+#endif
+	{
+	iTransReqEvents++;
+	__PRINT((_L("CDmTest7::TransReqEvent(), aDomainId = %d, aState %d, iTransReqEvents %d\n"), 
+		aDomainId, aState, iTransReqEvents));
+	TestForCompletion();
+	}
+
+GLDEF_C TInt E32Main()
+	{
+	CTrapCleanup* trapHandler=CTrapCleanup::New();
+	test(trapHandler!=NULL);
+
+	CActiveScheduler* scheduler = new CActiveScheduler();
+	test(scheduler != NULL);
+	CActiveScheduler::Install(scheduler);
+
+	// Turn off evil lazy dll unloading
+	RLoader l;
+	test(l.Connect()==KErrNone);
+	test(l.CancelLazyDllUnload()==KErrNone);
+	l.Close();
+
+	//
+	// Perform the number of iterations specifed by the command line argument.
+	//
+	// If no arguments - perform two iterations
+	//
+//  TInt iter = 2;
+    TInt iter = 1;
+
+	TInt len = User::CommandLineLength();
+	if (len)
+		{
+		// Copy the command line in a buffer
+		HBufC* hb = HBufC::NewMax(len);
+		test(hb != NULL);
+		TPtr cmd((TUint16*) hb->Ptr(), len);
+		User::CommandLine(cmd);
+		// Extract the number of iterations
+		TLex l(cmd);
+		TInt i;
+		TInt r = l.Val(i);
+		if (r == KErrNone)
+			iter = i;
+		else
+			// strange command - silently ignore
+			{} 
+		delete hb;
+		}
+
+	test.Title();
+	test.Start(_L("Testing"));
+
+	test.Printf(_L("Go for %d iterations\n"), iter);
+
+	// Remember the number of open handles. Just for a sanity check ....
+	TInt start_thc, start_phc;
+	RThread().HandleCount(start_phc, start_thc);
+
+	while (iter--)
+		{
+		MDmTest* tests[] = 
+			{
+
+			new CDmTest1(KDmIdRoot, EPwStandby),
+			new CDmTest1(KDmIdRoot, EPwOff),
+			new CDmTest1(KDmIdRoot, EPwActive),
+			new CDmTest1(KDmIdApps, EPwStandby),
+			new CDmTest1(KDmIdApps, EPwOff),
+			new CDmTest1(KDmIdApps, EPwActive),
+			new CDmTest1(KDmIdUiApps, EPwStandby),
+			new CDmTest1(KDmIdUiApps, EPwOff),
+			new CDmTest1(KDmIdUiApps, EPwActive),
+			new CDmTest2(EPwStandby),
+			new CDmTest3(),
+	
+			// platform security tests
+			new CDmTest4(),
+
+			// PREQ810 tests :
+			// note that we use a fictitious power state to prevent any 
+			new CDmTest5(KDmIdRoot, KDmIdRoot, EPwActive+10, EStartupCriticalDynamic),
+			new CDmTest5(KDmIdUiApps, KDmIdTestAB, EPwActive+10, EStartupCriticalDynamic),
+
+        // negative tests
+			new CDmTest6(),
+
+
+			// observer tests
+     		new CDmTest7(KDmIdTestA),
+			new CDmTest7(KDmIdRoot),
+			
+			};
+
+		for (unsigned int i = 0; i < sizeof(tests)/sizeof(*tests); ++i)
+			{
+			test(tests[i] != NULL);
+			tests[i]->Perform();
+			tests[i]->Release();
+			}
+
+		}
+
+	test.End();
+
+	// Sanity check for open handles and for pending requests ...
+	TInt end_thc, end_phc;
+	RThread().HandleCount(end_phc, end_thc);
+	test(start_thc == end_thc);
+	test(start_phc == end_phc);
+	test(RThread().RequestCount() >= 0);
+
+	delete scheduler;
+	delete trapHandler;
+
+	return KErrNone;
+	}