phonebookengines/contactsmodel/tsrc/Integration/PerfFuncSuite/src/StateMachineStep.cpp
changeset 0 e686773b3f54
child 24 0ba2181d7c28
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/tsrc/Integration/PerfFuncSuite/src/StateMachineStep.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,714 @@
+// Copyright (c) 2006-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
+ @publishedAll
+ @released
+ */
+
+#include "StateMachineStep.h"
+#include "PerformanceFunctionalityDefs.h"
+#include <cntfilt.h>
+
+const static TInt KNumberOfContacts = 10;
+
+_LIT(KTestCase1,"OpeningRecovery");
+_LIT(KTestCase2,"OpeningAsync");
+_LIT(KTestCase3,"Writable");
+_LIT(KTestCase4,"DefaultRecovery");
+_LIT(KTestCase5,"DefaultCompress");
+_LIT(KTestCase6,"AsyncInteg");
+_LIT(KTestCase7,"TablesClosed");
+_LIT(KTestCase8,"WritableSpeed");
+
+_LIT(KTestCasePrint1, "Opening State statemachine Recovery tests");
+_LIT(KTestCasePrint2, "Opening State statemachine Asynchronous open tests");
+_LIT(KTestCasePrint3, "Writable State statemachine tests");
+_LIT(KTestCasePrint4, "Default State recovery statemachine tests");
+_LIT(KTestCasePrint5, "Default State compression statemachine tests");
+_LIT(KTestCasePrint6, "Asynchronous Integrity tests");
+_LIT(KTestCasePrint7, "Tables Closed State statemachine tests");
+_LIT(KTestCasePrint8, "Writable State statemachine speed dial tests");
+
+/**
+ * This class tests the internal implementation of the contact model server
+ * specifically it is designed to stress test the state machine
+ * so that all the major functionality of the state machine is exercised
+ * each test function usually encompasses one test case, the description for
+ * the test case is defined in the related test script file (StateMachineStep.script)
+ * each test step in the test script file usually call this test class with a non
+ * existent ini file section name, the section name correspond to the test case
+ * name stored within this class. The reasoning behind this is that each test case
+ * does not need to store any additional data within the ini file and as such a reference
+ * to an actual ini file section would be redundent.
+ */
+CStateMachineStep::CStateMachineStep()
+                        : CPerformanceFunctionalityBase( KNumberOfContacts )
+	{
+	SetTestStepName(KStateMachineStep);
+	}
+
+TVerdict CStateMachineStep::doTestStepPostambleL()
+	{
+	return CPerformanceFunctionalityBase::doTestStepPostambleL();
+	}
+
+void CStateMachineStep::InitializeL()
+	{
+	CPerformanceFunctionalityBase::InitializeL();
+	//set timeout to 0, to minimize waits within the test
+	iContactsDatabase->SetOperationTimeOutL(0);
+	}
+
+void CStateMachineStep::Cleanup()
+	{
+    //unload async opens
+    CLEAR( iContactOpenOperation1 );
+    CLEAR( iContactOpenOperation2 );
+	CPerformanceFunctionalityBase::Cleanup();
+	}
+
+void CStateMachineStep::PreTestL()
+	{
+	//does nothing
+	}
+
+TVerdict CStateMachineStep::doTestStepL()
+	{
+	__UHEAP_MARK;
+	InitializeL();
+	_LIT(KPrintStart, "CStateMachineStep::doTestStepL()");
+	INFO_PRINTF1(KPrintStart);  //Block start
+	iIterate->Reset();
+
+	const TDesC &KSection = ConfigSection();
+
+	if( KSection ==  KTestCase1 )
+		{
+		INFO_PRINTF1( KTestCasePrint1 );
+		OpeningStateRecoverTestsL();
+		}
+	else if( KSection ==  KTestCase2 )
+		{
+		INFO_PRINTF1( KTestCasePrint2 );
+		OpeningStateAsyncOpenTestsL();
+		}
+	else if( KSection ==  KTestCase3 )
+		{
+		INFO_PRINTF1( KTestCasePrint3 );
+		WritableStateTestsL();
+		}
+	else if( KSection ==  KTestCase4 )
+		{
+		INFO_PRINTF1( KTestCasePrint4 );
+		DefaultStateCompressionTestsL();
+		}
+	else if( KSection ==  KTestCase5 )
+		{
+		INFO_PRINTF1( KTestCasePrint5 );
+		DefaultStateRecoveryTestsL();
+		}
+	else if( KSection ==  KTestCase6 )
+		{
+		INFO_PRINTF1( KTestCasePrint6 );
+		AsynchronousIntegrityTestL();
+		}
+	else if( KSection ==  KTestCase7 )
+		{
+		INFO_PRINTF1( KTestCasePrint7 );
+		TablesClosedStateTestsL();
+		}
+	else if( KSection ==  KTestCase8 )
+		{
+		INFO_PRINTF1( KTestCasePrint8 );
+		WritableStateSpeedDialTestsL();
+		}
+	else
+		{
+		MissingTestPanic();
+		}
+
+	Cleanup();
+	__UHEAP_MARKEND;
+
+	return TestStepResult();
+
+	}
+
+void CStateMachineStep::OpeningStateRecoverTestsL()
+    {
+	TContactItemId con1 = iIterate->NextL();
+    CContactDatabase *database = CContactDatabase::OpenL();
+
+    iCompleteSteps = ETrue;
+    TInt error = KErrNone;
+    
+    //transition to opening state
+    TRAP( error, StartRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    
+    //open tables while in opening state
+    TRAP( error, database->OpenTablesL() );
+    #ifdef _DEBUG
+    	#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+    	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    	#else
+      	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+     	#endif     
+    #else
+    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    #endif
+    
+    //transition out of opening state
+    TRAP( error, EndRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+    CLEAR( database );
+
+    iCompleteSteps = ETrue;
+    //transition to opening state
+    TRAP( error, StartRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    //transition out of opening state, completing all recovery steps
+    TRAP( error, EndRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    iCompleteSteps = EFalse;
+    //transition to opening state
+    TRAP( error, StartRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    //transition out of opening state, cancelling recovery
+    TRAP( error, EndRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    iCompleteSteps = EFalse;
+    //transition to opening state
+    TRAP( error, StartRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    //can't access contacts as database is in recovery state
+    TRAP( error,
+            ReadL(con1);
+            CloseL( EFalse );
+        );
+
+    #ifdef _DEBUG
+    	#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    	#else
+	    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+     	#endif     
+    #else
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    #endif
+
+    TRAP( error,
+            OpenL(con1);
+            CloseL( ETrue );
+        );
+    #ifdef _DEBUG
+    	#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    	#else
+	    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+     	#endif         
+    #else
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    #endif
+    
+    //transition out of opening state, cancelling recovery
+    TRAP( error, EndRecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    //after recovery is complete it should be possible to access contact normally
+    TRAP( error,
+            ReadL(con1);
+            CloseL( EFalse );
+        );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    TRAP( error,
+            OpenL(con1);
+            CloseL( ETrue );
+        );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+
+    }
+
+void CStateMachineStep::OpeningStateAsyncOpenTestsL()
+    {
+    CContactDatabase *database1 = NULL;
+    CContactDatabase *database2 = NULL;
+
+    CLEAR( iContactsDatabase );
+    WaitForServerToExitL();
+
+    //open databases asynchronously *2
+    iContactOpenOperation1 = CContactDatabase::Open(iStatus1);
+    iContactOpenOperation2 = CContactDatabase::Open(iStatus2);
+    //cancel second async open first
+    CLEAR( iContactOpenOperation2 );
+    CLEAR( iContactOpenOperation1 );
+    //check that async opens were cancelled
+    if( iStatus1.Int() != KErrNone )
+        {
+        INTCOMPARE( KErrCancel, ==, iStatus1.Int(), 0, 0 );
+        }
+    if( iStatus2.Int() != KErrNone )
+        {
+        INTCOMPARE( KErrCancel, ==, iStatus2.Int(), 0, 0 );
+        }
+
+    //open databases asynchronously *2
+    iContactOpenOperation1 = CContactDatabase::Open(iStatus1);
+    iContactOpenOperation2 = CContactDatabase::Open(iStatus2);
+    //cancel first async open
+    CLEAR( iContactOpenOperation1 );
+    User::WaitForRequest(iStatus2);
+    //get opened database sessions
+    database1 = iContactOpenOperation2->TakeDatabase();
+    //check that databases have been opened
+    INTCOMPARE( reinterpret_cast<TInt>(database1), !=, NULL, 0, 0 );
+    //check that first async open was cancelled
+    INTCOMPARE( KErrCancel, ==, iStatus1.Int(), 0, 0 );
+    //check that second async opened was successful
+    INTCOMPARE( KErrNone, ==, iStatus2.Int(), 0, 0 );
+    //unload opened database sessions
+    CLEAR( database1 );
+    CLEAR( iContactOpenOperation2 );
+
+    WaitForServerToExitL();
+    //open databases asynchronously *2
+    iContactOpenOperation1 = CContactDatabase::Open(iStatus1);
+    iContactOpenOperation2 = CContactDatabase::Open(iStatus2);
+    //wait for async opens to complete
+    User::WaitForRequest(iStatus1);
+    User::WaitForRequest(iStatus2);
+
+    //get opened database sessions
+    database1 = iContactOpenOperation1->TakeDatabase();
+    database2 = iContactOpenOperation2->TakeDatabase();
+
+    //check that databases have been opened
+    INTCOMPARE( reinterpret_cast<TInt>(database1), !=, NULL, 0, 0 );
+    INTCOMPARE( reinterpret_cast<TInt>(database2), !=, NULL, 0, 0 );
+    //unload async opens
+    CLEAR( iContactOpenOperation1 );
+    CLEAR( iContactOpenOperation2 );
+    //unload opened database sessions
+    CLEAR( database1 );
+    CLEAR( database2 );
+    //check that async opens completed successfully
+    INTCOMPARE( KErrNone, ==, iStatus1.Int(), 0, 0 );
+    INTCOMPARE( KErrNone, ==, iStatus2.Int(), 0, 0 );
+
+
+    iContactsDatabase = CContactDatabase::OpenL();
+   	#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   		iContactsDatabase->DamageDatabaseL(0x666);
+ 	#endif
+    CLEAR( iContactsDatabase );
+
+    WaitForServerToExitL();
+    iActiveRecoverObserver.iCompressOrRecoverError = KErrNone;
+
+    //open databases asynchronously
+    iContactOpenOperation1 = CContactDatabase::Open(iStatus1);
+    //get partially opened database session
+    database1= iContactOpenOperation1->TakeDatabase();
+    //start async recovery
+    CContactActiveRecover*  recover = database1->CreateRecoverLC();
+	recover->SetObserver( &iActiveRecoverObserver );
+	//complete async recovery
+	while(recover->Step()){}
+	CleanupStack::PopAndDestroy( recover );
+	recover = NULL;
+
+    //unload async opens
+    CLEAR( iContactOpenOperation1 );
+    //unload opened database sessions
+    CLEAR( database1 );
+
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    iContactsDatabase = CContactDatabase::OpenL();
+    }
+
+void CStateMachineStep::WritableStateTestsL()
+    {
+	const TContactItemId KContactId = iIterate->NextL();
+	const TContactItemId KContactId2 = iIterate->NextL();
+    TInt error = KErrNone;
+
+    //set contact as own card
+    OpenL( KContactId );
+	TRAP( error, iContactsDatabase->SetOwnCardL( *iContactItem ) );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    CommitL( ETrue );
+    //check contact is set as own card
+    INTCOMPARE( iContactsDatabase->OwnCardId(), ==, KContactId, 0, 0 );
+
+    //set contact as own card again, to test internal functionality of state machine
+    OpenL( KContactId );
+	TRAP( error, iContactsDatabase->SetOwnCardL( *iContactItem ) );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    CommitL( ETrue );
+    //contact is still marked as own card
+    INTCOMPARE( iContactsDatabase->OwnCardId(), ==, KContactId, 0, 0 );
+
+    //read contact
+    ReadL( KContactId2 );
+    //set contact as own card using read contact
+	TRAP( error, iContactsDatabase->SetOwnCardL( *iContactItem ) );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    CloseL( EFalse );
+    //check that contact is set as own card
+    INTCOMPARE( iContactsDatabase->OwnCardId(), ==, KContactId2, 0, 0 );
+
+    //Perform recovery while in writeable state and database not damaged
+    TRAP( error,
+            //start async recovery
+            CContactActiveRecover*  recover = iContactsDatabase->CreateRecoverLC();
+        	recover->SetObserver( &iActiveRecoverObserver );
+        	//complete async recovery
+        	while(recover->Step()){}
+        	CleanupStack::PopAndDestroy( recover );
+        	recover = NULL;
+        );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    TRAP( error, iContactsDatabase->RecoverL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    }
+
+void CStateMachineStep::WritableStateSpeedDialTestsL()
+    {
+    _LIT(KFieldValue, "FieldValue");
+	const TContactItemId KContactId = iIterate->NextL();
+    TInt error = KErrNone;
+    iActiveRecoverObserver.iCompressOrRecoverError = KErrNone;
+
+    OpenL( KContactId );
+    const TInt KFieldCount = iFields->Count();
+    CloseL( ETrue );
+
+
+	OpenL( KContactId );
+    
+    //try setting an empty field as a SpeedDial
+    //no error should ensue
+    TRAP( error, iContactsDatabase->SetFieldAsSpeedDialL(*iContactItem, 1, 1) );
+
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+
+    //write some test data into all fields of the contact item
+    //parameter is used only for Text and Store type fields - others are created on the fly
+    SetAllFieldsL(KFieldValue);
+    CommitL( EFalse );    
+
+    for( TInt i = 0; i < KFieldCount; ++i)
+        {
+        OpenL( KContactId );
+        TRAP( error, iContactsDatabase->SetFieldAsSpeedDialL(*iContactItem, i, 1) );
+
+        //if field is text, set speed dial should be successful
+        if( (*iFields)[i].StorageType() == KStorageTypeText)
+            {
+            CloseL( ETrue );
+            INTCOMPARE( KErrNone, ==, error, i, 0 );
+            ReadL( KContactId );
+            TESTPRINTI( (*iFields)[i].IsSpeedDial(), i );
+            CloseL( EFalse );
+            }
+        //if field not text, set speed dial should fail
+        else
+            {
+            CloseL( ETrue );
+            INTCOMPARE( KErrArgument, ==, error, i, 0 );
+            ReadL( KContactId );
+            TESTPRINTI( !(*iFields)[i].IsSpeedDial(),  i );
+            CloseL( EFalse );
+            }
+        }
+
+    ReadL( KContactId );
+    //set speed dial for unopened/read contact
+    TRAP( error, iContactsDatabase->SetFieldAsSpeedDialL(*iContactItem, 1, 1) );
+    CloseL( EFalse );
+    //set speed dial should fail
+    INTCOMPARE( KErrAccessDenied, ==, error, 0, 0 );
+    ReadL( KContactId );
+    TESTPRINT( !(*iFields)[1].IsSpeedDial() );
+    CloseL( EFalse );
+
+    //set speed dial for system template - expect error here
+    CContactCard* contact = CContactCard::NewLC( iTemplate );
+    TRAP( error, iContactsDatabase->SetFieldAsSpeedDialL(*contact, 1, 1) );
+    INTCOMPARE( KErrArgument, ==, error, 0, 0 );
+    CleanupStack::PopAndDestroy(contact);
+
+    //set speed dial for contact with empty field set - expect error here too
+    contact = CContactCard::NewLC();
+    TRAP( error, iContactsDatabase->SetFieldAsSpeedDialL(*contact, 1, 1) );
+    INTCOMPARE( KErrArgument, ==, error, 0, 0 );
+    CleanupStack::PopAndDestroy(contact);
+    }
+
+/**
+Perform operations that are not supported by current state, so that default state is used
+all operations should be unsuccessfull
+*/
+void CStateMachineStep::DefaultStateCompressionTestsL()
+    {
+	const TContactItemId KContactId = iIterate->NextL();
+    TInt error = KErrNone;
+
+	OpenL( KContactId );
+    //transition into compress state
+    StartCompressL();
+
+    //perform unsupported operations
+    TRAP( error, iContactsDatabase->CloseTables() );//non leaving function
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+
+    TRAP( error, iContactsDatabase->OpenTablesL() );
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#else
+   	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+#endif
+   	
+    TRAP( error, iContactsDatabase->RecoverL() );
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#else
+   	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+#endif
+
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	// only do this with the DBMS version of the contacts model as DamageDatabaseL
+	// doesn't do anything in the SQLite version and so the test will always fail.
+    TRAP( error, iContactsDatabase->DamageDatabaseL(0x666); );
+    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#endif
+
+    TRAP( error,
+        CContactActiveRecover*  recover = iContactsDatabase->CreateRecoverLC();
+        CleanupStack::PopAndDestroy(recover);
+        );
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#else
+   	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+#endif
+    
+	TRAP( error, iContactsDatabase->SetOwnCardL( *iContactItem ) );
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#else
+   	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+#endif
+      	
+    TRAP( error, iContactsDatabase->SetFieldAsSpeedDialL(*iContactItem, 1, 1) );
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#else
+   	INTCOMPARE( KErrInUse, ==, error, 0, 0 );
+#endif
+   	
+    EndCompressL();
+    //end compress state
+
+    CloseL( ETrue );
+
+
+    }
+
+/**
+Perform operations that are not supported by current state, so that default state is used
+all operations should be unsuccessfull
+*/
+void CStateMachineStep::DefaultStateRecoveryTestsL()
+    {
+    TInt error = KErrNone;
+
+    //transition into opening state
+    StartRecoverL();
+
+    //perform usupported operations
+    TRAP( error, iContactsDatabase->CompactL() );
+
+    #ifdef _DEBUG
+    	#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+    	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    	#else
+      	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+     	#endif     
+    #else
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    #endif
+
+
+    TRAP( error,
+            CContactActiveCompress*  compress = iContactsDatabase->CreateCompressorLC();
+            CleanupStack::PopAndDestroy( compress );
+     );
+
+    #ifdef _DEBUG
+    	#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+    	INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    	#else
+      	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+     	#endif     
+    #else
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    #endif
+
+    EndRecoverL();
+    //end opening stat
+    }
+
+void CStateMachineStep::AsynchronousIntegrityTestL()
+    {
+	const TContactItemId KContactId = iIterate->NextL();
+    TInt error = KErrNone;
+
+    //test that it is possible to create multiple active compressor
+    iActiveRecoverObserver.iCompressOrRecoverError = KErrNone;
+    CContactActiveCompress*  compress1 = iContactsDatabase->CreateCompressorLC();
+	compress1->SetObserver( &iActiveRecoverObserver );
+    CContactActiveCompress*  compress2 = iContactsDatabase->CreateCompressorLC();
+	compress2->SetObserver( &iActiveRecoverObserver );
+    while(compress1->Step()){}
+    while(compress2->Step()){}
+    CleanupStack::PopAndDestroy( compress2 );
+    CleanupStack::PopAndDestroy( compress1 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+
+    //test that it is possible to create multiple active recoverers
+    iActiveRecoverObserver.iCompressOrRecoverError = KErrNone;
+    CContactActiveRecover*  recover1 = iContactsDatabase->CreateRecoverLC();
+	recover1->SetObserver( &iActiveRecoverObserver );
+    CContactActiveRecover*  recover2 = iContactsDatabase->CreateRecoverLC();
+	recover2->SetObserver( &iActiveRecoverObserver );
+    while(recover1->Step()){}
+    while(recover2->Step()){}
+    CleanupStack::PopAndDestroy( recover2 );
+    CleanupStack::PopAndDestroy( recover1 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    //transition into compress state
+
+    iCompleteSteps = EFalse;
+    StartCompressL();
+    TRAP( error,
+            CContactActiveRecover*  recover = iContactsDatabase->CreateRecoverLC();
+            CleanupStack::PopAndDestroy( recover );
+        );
+#ifdef __SYMBIAN_CNTMODEL_USE_SQLITE__
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+#else    
+    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+#endif   
+
+    EndCompressL();
+    //end compress state
+
+    //test that we have transitioned out of compress state
+    TRAP( error, ReadL( KContactId ) );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    CloseL( EFalse );
+
+    iCompleteSteps = EFalse;
+    //transition into opening state
+    StartRecoverL();
+    TRAP( error,
+            CContactActiveCompress*  compress = iContactsDatabase->CreateCompressorLC();
+            CleanupStack::PopAndDestroy( compress );
+        );
+
+    #ifdef _DEBUG
+   	    #ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+   		INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+   		#else
+   		INTCOMPARE( KErrNone, ==, error, 0, 0 );
+   		#endif     
+    #else
+    	INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    #endif
+    
+    EndRecoverL();
+    //transition out of opening state
+
+    //test that we have transitioned out of compress state
+    TRAP( error, ReadL( KContactId ) );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    CloseL( EFalse );
+    }
+
+void CStateMachineStep::TablesClosedStateTestsL()
+    {
+	const TContactItemId KContactId = iIterate->NextL();
+    TInt error = KErrNone;
+
+    iActiveRecoverObserver.iCompressOrRecoverError = KErrNone;
+    //transition to tables closed state
+    iContactsDatabase->CloseTables();
+
+
+    TRAP( error,
+            CContactActiveCompress*  compress = iContactsDatabase->CreateCompressorLC();
+            compress->SetObserver( &iActiveRecoverObserver );
+            CleanupStack::PopAndDestroy( compress );//dont complete all steps
+     );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    //test that we are still in tables closed state
+    TRAP( error, ReadL( KContactId ) );
+    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    CloseL( EFalse );
+
+    TRAP( error,
+            CContactActiveCompress*  compress = iContactsDatabase->CreateCompressorLC();
+            compress->SetObserver( &iActiveRecoverObserver );
+            while(compress->Step()){}//complete all steps
+            CleanupStack::PopAndDestroy( compress );
+     );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    INTCOMPARE( KErrNone, ==, iActiveRecoverObserver.iCompressOrRecoverError, 0, 0 );
+
+    //test that we are still in tables closed state
+    TRAP( error, ReadL( KContactId ) );
+    INTCOMPARE( KErrNotReady, ==, error, 0, 0 );
+    CloseL( EFalse );
+
+    //transition to writeable state
+    CContactDatabase *database = NULL;
+    TRAP( error, database = CContactDatabase::OpenL() );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+
+    //test that we have transitioned out of tables closed state
+    TRAP( error, ReadL( KContactId ) );
+    INTCOMPARE( KErrNone, ==, error, 0, 0 );
+    CloseL( EFalse );
+
+    CLEAR( database );
+
+    }