serialserver/packetloopbackcsy/src/LoopbackTestStep.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialserver/packetloopbackcsy/src/LoopbackTestStep.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,985 @@
+// Copyright (c) 2004-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:
+// Tests for packet loopback CSY
+// 
+//
+
+/**
+ @file
+*/
+
+#include <e32property.h>
+#include <c32comm.h>
+#include <e32def.h>
+#include <e32base.h>
+
+#include <test/testexecutelog.h>
+
+#include "LoopbackTestStep.h"
+#include "LoopbackConfig.h"
+
+_LIT(KCsyName,"PKTLOOPBACK");
+_LIT(KPortName1,"PKTLOOPBACK::501");
+const TUint KPortUnitNum1 = 501;
+_LIT(KPortName2,"PKTLOOPBACK::502");
+const TUint KPortUnitNum2 = 502;
+_LIT(KPortName3,"PKTLOOPBACK::503");
+_LIT(KPortName4,"PKTLOOPBACK::504");
+_LIT8(KWriteBuf1,"1Packet data1");
+_LIT8(KWriteBuf2,"2Packet data2");
+_LIT8(KWriteBuf3,"3Packet data3");
+_LIT8(KWriteBuf4,"4Packet data4");
+
+const TUint KConfiguredPortDelayMicroseconds = 100000;
+const TUint KConfiguredPortLongDelayMicroseconds = 1000000;
+
+const TUint KTooSmallBufferSize = 4;
+const TUint KRegularBufferSize = 64;
+const TUint KHugeBufferSize = 10000;
+
+const TUint KLoopackConfigTestNumber1 = 1;
+const TUint KLoopackConfigTestNumber2 = 2;
+const TUint KLoopackConfigTestNumber3 = 3;
+const TUint KLoopackConfigTestNumber4 = 4;
+const TUint KLoopackConfigTestNumber5 = 5;
+const TUint KLoopackConfigTestNumber6 = 6;
+const TUint KLoopackConfigTestNumber7 = 7;
+const TUint KLoopackConfigTestNumber8 = 8;
+const TUint KLoopackConfigTestNumber9 = 9;
+const TUint KLoopackConfigTestNumber10 = 10;
+const TUint KLoopackConfigTestNumber11 = 11;
+const TUint KLoopackConfigTestNumber12 = 12;
+const TUint KLoopackConfigTestNumber13 = 13;
+
+CLoopbackTestStepBase::CLoopbackTestStepBase(TInt aTestNumber)
+	{
+	iTestNumber = aTestNumber;
+	}
+
+CLoopbackTestStepBase::~CLoopbackTestStepBase()
+	{
+	iCommPort1.Close();
+	iCommPort2.Close();
+	iCommPort3.Close();
+	iCommPort4.Close();
+	iCommServer.Close();
+	}
+
+void CLoopbackTestStepBase::SetTestNumber(TInt aTestNumber)
+  	{
+  	TInt dummy;
+	TInt ret = RProperty::Get(KUidPSPacketLoopbackCsyCategory, KPSLoopbackCsyTestNumber, dummy);
+	if(ret == KErrNotFound)
+		{
+		RProperty::Define(KUidPSPacketLoopbackCsyCategory, KPSLoopbackCsyTestNumber, 
+							KPSLoopbackCsyTestNumberKeyType);
+		}		
+	ret = RProperty::Set(KUidPSPacketLoopbackCsyCategory, KPSLoopbackCsyTestNumber, aTestNumber);
+  	}
+
+void CLoopbackTestStepBase::SetFlowControl(TUint aUnit, TBool aFlowControlOn)
+  	{
+  	TInt dummy;
+	TInt ret = RProperty::Get(KUidPSCsyFlowControlCategory, aUnit, dummy);
+	if(ret == KErrNotFound)
+		{
+		RProperty::Define(KUidPSCsyFlowControlCategory, aUnit, KPSLoopbackCsyFlowControlOnKeyType);
+		}
+	ret = RProperty::Set(KUidPSCsyFlowControlCategory, aUnit, aFlowControlOn);
+  	}
+
+void CLoopbackTestStepBase::SetReadResult(TUint aUnit, TInt aReadResult)
+  	{
+  	TInt dummy;
+	TInt ret = RProperty::Get(KUidPSCsyReadResultCategory, aUnit, dummy);
+	if(ret == KErrNotFound)
+		{
+		RProperty::Define(KUidPSCsyReadResultCategory, aUnit, KUidPSCsyReadResultCategoryKeyType);
+		}
+	ret = RProperty::Set(KUidPSCsyReadResultCategory, aUnit, aReadResult);
+  	}
+
+void CLoopbackTestStepBase::SetWriteResult(TUint aUnit, TInt aWriteResult)
+  	{
+  	TInt dummy;
+	TInt ret = RProperty::Get(KUidPSCsyWriteResultCategory, aUnit, dummy);
+	if(ret == KErrNotFound)
+		{
+		RProperty::Define(KUidPSCsyWriteResultCategory, aUnit, KUidPSCsyWriteResultCategoryKeyType);
+		}
+	ret = RProperty::Set(KUidPSCsyWriteResultCategory, aUnit, aWriteResult);
+  	}
+
+TVerdict CLoopbackTestStepBase::doTestStepPreambleL()
+	{
+	__UHEAP_MARK;
+	SetTestNumber(iTestNumber);
+
+	TestErrorCodeL( iCommServer.Connect(), _L("Connect to comm server") );
+	TestErrorCodeL( iCommServer.LoadCommModule(KCsyName), _L("Loading comm module") );
+
+	return TestStepResult();
+	}
+	
+TVerdict CLoopbackTestStepBase::doTestStepPostambleL()
+	{
+	User::LeaveIfError(KErrNone);	// To prevent LeaveScan warning
+
+	iCommPort1.Close();
+	iCommPort2.Close();
+	iCommPort3.Close();
+	iCommPort4.Close();
+	iCommServer.Close();
+
+	__UHEAP_MARKEND;
+	return EPass;
+	}
+	
+void CLoopbackTestStepBase::TestErrorCodeL(TInt aErrCode, const TDesC& aMessage)
+	{	
+	TestErrorCodeL(aErrCode, KErrNone, aMessage);
+	}
+
+void CLoopbackTestStepBase::TestErrorCodeL(TInt aErrCode, TInt aExpectedErrCode, const TDesC& aMessage)
+	{	
+	if(aExpectedErrCode == aErrCode)
+		{
+		INFO_PRINTF3(_L("[%S]. err[%d], as expected. OK."), &aMessage, aErrCode);
+		}
+	else
+		{
+		ERR_PRINTF5(_L("Failed: [%S]. err[%d], expected [%d]. Leaving with [%d])."), &aMessage, aErrCode, aExpectedErrCode, aErrCode);
+		User::Leave(aErrCode);
+		}
+	}
+
+void CLoopbackTestStepBase::TestBooleanTrueL(TInt aBool, const TDesC& aMessage)
+	{	
+	if(aBool)
+		{
+		INFO_PRINTF2(_L("[%S] is true, as expected. OK."), &aMessage);
+		}
+	else
+		{
+		ERR_PRINTF2(_L("Failed: [%S] is false. Leaving with KErrGeneral)."), &aMessage);
+		User::Leave(KErrGeneral);
+		}
+	}
+
+void CLoopbackTestStepBase::TestErrorCodeAndDescriptorL(TInt aErrCode, TInt aExpectedErrCode, const TDesC8& aDesC, const TDesC8& aExpectedDesC, const TDesC& aMessage)
+	{
+	if ( (aExpectedErrCode == aErrCode) && (aDesC.Compare(aExpectedDesC) == 0) )
+		{
+		INFO_PRINTF4(_L("[%S]. err[%d], and string [%S] as expected. OK."), &aMessage, aErrCode, &aExpectedDesC);
+		}
+	else if (aExpectedErrCode == aErrCode)
+		{
+		ERR_PRINTF5(_L("Failed: [%S]. err[%d], expected [%d]. Leaving with [%d])."), &aMessage, aErrCode, aExpectedErrCode, aErrCode);
+		User::Leave(aErrCode);
+		}
+	else
+		{
+		ERR_PRINTF4(_L("Failed: [%S]. String [%S] received, expected [%S]. Leaving with KErrGeneral."), &aMessage, &aDesC, &aExpectedDesC);
+		User::Leave(KErrGeneral);
+		}
+	}
+	
+void CLoopbackTestStepBase::TestErrorCodeAndDescriptorL(TInt aErrCode, const TDesC8& aDesC, const TDesC8& aExpectedDesC, const TDesC& aMessage)
+	{
+	TestErrorCodeAndDescriptorL(aErrCode, KErrNone, aDesC, aExpectedDesC, aMessage);
+	}
+	
+CLoopbackTestStep1::~CLoopbackTestStep1()
+	{
+	}
+
+CLoopbackTestStep1::CLoopbackTestStep1() : CLoopbackTestStepBase(KLoopackConfigTestNumber1)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep1);
+	}
+	
+TVerdict CLoopbackTestStep1::doTestStepL()
+/**
+Test that two different sets of loopback ports can read/write to their corresponding loopback port
+The test's ini file is configured to have commPort1 and commPort2 as loopback ports, and 
+commPort3 and commPort4 as loopback ports
+*/
+	{
+	// open the 4 ports
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	TestErrorCodeL( iCommPort3.Open(iCommServer, KPortName3, ECommExclusive, ECommRoleDCE), _L("Opening comm port 3") );
+	TestErrorCodeL( iCommPort4.Open(iCommServer, KPortName4, ECommExclusive, ECommRoleDCE), _L("Opening comm port 4") );
+
+	// There are a total of 4 writes (one to and from each port)
+	// 2 of the reads occur before the write and 2 after
+	
+	// Issue the two reads before the writes
+	TRequestStatus readStatus1, readStatus2;
+	TBuf8<KRegularBufferSize> readBuf1;
+	TBuf8<KRegularBufferSize> readBuf2;
+	iCommPort1.ReadOneOrMore(readStatus1, readBuf1);
+	iCommPort2.ReadOneOrMore(readStatus2, readBuf2);
+	
+	// Issue the writes on each port
+	TRequestStatus writeStatus1, writeStatus2, writeStatus3, writeStatus4;
+	iCommPort1.Write(writeStatus1, KWriteBuf1);
+	iCommPort2.Write(writeStatus2, KWriteBuf2);
+	iCommPort3.Write(writeStatus3, KWriteBuf3);
+	iCommPort4.Write(writeStatus4, KWriteBuf4);
+
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+	User::WaitForRequest(writeStatus2);
+	TestErrorCodeL(writeStatus2.Int(), _L("Writing to comm port 2"));
+	User::WaitForRequest(writeStatus3);
+	TestErrorCodeL(writeStatus3.Int(), _L("Writing to comm port 3"));
+	User::WaitForRequest(writeStatus4);
+	TestErrorCodeL(writeStatus4.Int(), _L("Writing to comm port 4"));
+
+	// Check that the first 2 reads completed successfully
+	User::WaitForRequest(readStatus1);
+	TestErrorCodeAndDescriptorL(readStatus1.Int(), readBuf1, KWriteBuf2, _L("Read from comm port 1"));
+	User::WaitForRequest(readStatus2);
+	TestErrorCodeAndDescriptorL(readStatus2.Int(), readBuf2, KWriteBuf1, _L("Read from comm port 2"));
+
+	// Issue the 2 reads after the writes and make sure they complete successfully
+	TRequestStatus readStatus3, readStatus4;
+	TBuf8<KRegularBufferSize> readBuf3;
+	TBuf8<KRegularBufferSize> readBuf4;
+
+	iCommPort3.ReadOneOrMore(readStatus3, readBuf3);
+	User::WaitForRequest(readStatus3);
+	TestErrorCodeAndDescriptorL(readStatus3.Int(), readBuf3, KWriteBuf4, _L("Read from comm port 3"));
+
+	iCommPort4.ReadOneOrMore(readStatus4, readBuf4);
+	User::WaitForRequest(readStatus4);
+	TestErrorCodeAndDescriptorL(readStatus4.Int(), readBuf4, KWriteBuf3, _L("Read from comm port 4"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep2::~CLoopbackTestStep2()
+	{
+	}
+
+CLoopbackTestStep2::CLoopbackTestStep2() : CLoopbackTestStepBase(KLoopackConfigTestNumber2)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep2);
+	}
+	
+TVerdict CLoopbackTestStep2::doTestStepL()
+/**
+Test that writes are successfully queued and sent.
+The 2 ports opened are configured as loopback ports in the ini file
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+		
+	// Issue 2 writes immediately one after the other in each direction
+	TRequestStatus writeStatus1, writeStatus2, writeStatus3, writeStatus4;
+	iCommPort1.Write(writeStatus1, KWriteBuf1);
+	iCommPort1.Write(writeStatus2, KWriteBuf2);
+	
+	iCommPort2.Write(writeStatus3, KWriteBuf3);
+	iCommPort2.Write(writeStatus4, KWriteBuf4);
+	
+	TBool writesSuccessful = EFalse;
+	User::WaitForRequest(writeStatus1);
+	User::WaitForRequest(writeStatus2);
+	User::WaitForRequest(writeStatus3);
+	User::WaitForRequest(writeStatus4);
+	if (writeStatus1 == KErrNone && writeStatus2 == KErrNone && 
+		writeStatus3 == KErrNone && writeStatus4 == KErrNone)
+		{
+		writesSuccessful = ETrue;
+		}
+	TestBooleanTrueL(writesSuccessful, _L("Writing to comm ports successful"));
+
+	// Issue the reads
+	TRequestStatus readStatus1, readStatus2, readStatus3, readStatus4;
+	TBuf8<KRegularBufferSize> readBuf1, readBuf2, readBuf3, readBuf4;
+	iCommPort2.ReadOneOrMore(readStatus1, readBuf1);
+	User::WaitForRequest(readStatus1);
+	iCommPort2.ReadOneOrMore(readStatus2, readBuf2);
+	User::WaitForRequest(readStatus2);
+	iCommPort1.ReadOneOrMore(readStatus3, readBuf3);
+	iCommPort1.ReadOneOrMore(readStatus4, readBuf4);
+	User::WaitForRequest(readStatus4);
+	User::WaitForRequest(readStatus3);
+
+	// Make sure the requests are all successful
+	TestBooleanTrueL(readStatus1 == KErrNone && readStatus2 == KErrNone && 
+					 readStatus3 == KErrNone && readStatus4 == KErrNone,
+					 _L("Check that reading from comm ports returned no errors"));
+	TestBooleanTrueL(readBuf1.Compare(KWriteBuf1) == 0 && readBuf2.Compare(KWriteBuf2) == 0 &&
+					 readBuf3.Compare(KWriteBuf3) == 0 || readBuf4.Compare(KWriteBuf4) == 0,
+					 _L("Check that correct values were read from comm ports"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep3::~CLoopbackTestStep3()
+	{
+	}
+
+CLoopbackTestStep3::CLoopbackTestStep3() : CLoopbackTestStepBase(KLoopackConfigTestNumber3)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep3);
+	}
+	
+TVerdict CLoopbackTestStep3::doTestStepL()
+/**
+Test the 3 different orders in which read/write operations can occur as follows:
+	1. The read is issued, then the write is issued, then the data is sent across the port
+	2. The write is issued, then the read is issued, then the data is sent across the port
+	3. The write is issued, then the data is sent across the port, then the read is issued
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+
+	TRequestStatus readStatus1, readStatus2;
+	TBuf8<KRegularBufferSize> readBuf1, readBuf2;
+	TRequestStatus writeStatus1;
+
+	// 1. The read is issued, then the write is issued, then the data is sent across the port
+	
+	// fist issue the read
+	iCommPort1.ReadOneOrMore(readStatus1, readBuf1);
+
+	// second issue the write
+	iCommPort2.Write(writeStatus1, KWriteBuf1);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+		
+	User::WaitForRequest(readStatus1);
+	TestErrorCodeAndDescriptorL(readStatus1.Int(), readBuf1, KWriteBuf1, _L("Read from comm port 1"));
+
+	// 2. The write is issued, then the read is issued, then the data is sent across the port
+	
+	// first issue the write
+	iCommPort1.Write(writeStatus1, KWriteBuf2);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+		
+	// second issue the read before the data has the chance to be sent across the port
+	iCommPort2.ReadOneOrMore(readStatus2, readBuf2);
+	User::WaitForRequest(readStatus2);
+	TestErrorCodeAndDescriptorL(readStatus2.Int(), readBuf2, KWriteBuf2, _L("Read from comm port 2"));
+		
+	// 3. The write is issued, then the data is sent across the port, then the read is issued
+	
+	// first issue the write
+	iCommPort1.Write(writeStatus1, KWriteBuf2);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+	// second wait until the data has the chance to be sent across the port (this delay is configured
+	// to be 0.1s in the ini file, so we wait a bit longer)
+	User::After(2*KConfiguredPortDelayMicroseconds);
+		
+	// third the read is issued
+	iCommPort2.ReadOneOrMore(readStatus2, readBuf2);
+	User::WaitForRequest(readStatus2);
+	TestErrorCodeAndDescriptorL(readStatus2.Int(), readBuf2, KWriteBuf2, _L("Read from comm port 2"));
+		
+	return TestStepResult();
+	}
+
+CLoopbackTestStep4::~CLoopbackTestStep4()
+	{
+	}
+
+CLoopbackTestStep4::CLoopbackTestStep4() : CLoopbackTestStepBase(KLoopackConfigTestNumber4)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep4);
+	}
+	
+TVerdict CLoopbackTestStep4::doTestStepL()
+/**
+Test reading/writing to an un-opened port, or a port whose loopback port is un-opened
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+
+	TRequestStatus readStatus;
+	TBuf8<KRegularBufferSize> readBuf;
+	TRequestStatus writeStatus;
+
+	// issue read request before port is opened
+	iCommPort1.ReadOneOrMore(readStatus, readBuf);
+	// iCommPort2's loopback port is not yet opened, so write should fail
+	iCommPort1.Write(writeStatus, KWriteBuf1);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), KErrNotReady, _L("Writing to comm port 1 before port 2 is opened"));
+		
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+
+	iCommPort2.Write(writeStatus, KWriteBuf2);
+	User::WaitForRequest(writeStatus);
+
+	// now wait for read request which should complete from before iCommPort2 was opened
+	User::WaitForRequest(readStatus);
+
+	TestErrorCodeL(writeStatus.Int(), _L("Writing to comm port 1 after port 2 is opened"));
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf2, _L("Read from comm port 2"));
+		
+	iCommPort2.Close();
+
+	// iCommPort1 is now closed, so both write should fail
+	iCommPort1.Write(writeStatus, KWriteBuf1);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), KErrNotReady, _L("Writing to comm port 1 after port 2 is closed"));
+		
+	return TestStepResult();
+	}
+
+CLoopbackTestStep5::~CLoopbackTestStep5()
+	{
+	}
+
+CLoopbackTestStep5::CLoopbackTestStep5() : CLoopbackTestStepBase(KLoopackConfigTestNumber5)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep5);
+	}
+	
+TVerdict CLoopbackTestStep5::doTestStepL()
+/**
+Test filling up the read and write queues
+In this test, the read and write queues are set to be 1 entry in size
+*/
+	{
+	INFO_PRINTF1(_L("Starting Loopback test step 5"));
+
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+
+	TRequestStatus readStatus1;
+	TBuf8<KRegularBufferSize> readBuf1;
+	TRequestStatus writeStatus1, writeStatus2;
+
+	// Issue 2 writes immediately after each other. Since the queue is only set to 1 entry
+	// it will be full after the first write, so the second should return with KErrOverflow
+	iCommPort2.Write(writeStatus1, KWriteBuf1);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 2"));
+		
+	iCommPort2.Write(writeStatus2, KWriteBuf2);
+	User::WaitForRequest(writeStatus2);
+	TestErrorCodeL(writeStatus2.Int(), KErrOverflow, _L("Writing to comm port 2"));
+		
+	// wait until the data has the chance to be sent across the port (this delay is configured
+	// to be 1s in the ini file, so we wait a bit longer)
+	User::After(2*KConfiguredPortLongDelayMicroseconds);
+		
+	// After this delay, the buffer should have been 'sent' to the read queue of the loopback port
+	// Again, issue 2 writes immediately after each other, the first one filling up the queue
+	// meaning the second will return with KErrOverflow
+	iCommPort2.Write(writeStatus2, KWriteBuf2);
+	User::WaitForRequest(writeStatus2);
+	TestErrorCodeL(writeStatus2.Int(), _L("Writing to comm port 2"));
+		
+	iCommPort2.Write(writeStatus2, KWriteBuf2);
+	User::WaitForRequest(writeStatus2);
+	TestErrorCodeL(writeStatus2.Int(), KErrOverflow, _L("Writing to comm port 2"));
+		
+	// Wait for the amount of time it should take for the data to cross the port.
+	// After the delay the buffer should not be sent because the read buffer on the loopback port is full
+	User::After(2*KConfiguredPortLongDelayMicroseconds);
+		
+	iCommPort2.Write(writeStatus2, KWriteBuf2);
+	User::WaitForRequest(writeStatus2);
+	TestErrorCodeL(writeStatus2.Int(), KErrOverflow, _L("Writing to comm port 2"));
+		
+	// Issue reads for the 2 writes that have been sent successfully
+	// Since the second read has not yet been sent across the port, it should take more than the 
+	// time configured to send a buffer 
+
+	// Get the time before the reads
+	TTime beforeTime;
+	beforeTime.UniversalTime();
+	
+	iCommPort1.ReadOneOrMore(readStatus1, readBuf1);
+	User::WaitForRequest(readStatus1);
+	TestErrorCodeAndDescriptorL(readStatus1.Int(), readBuf1, KWriteBuf1, _L("Read from comm port 1"));
+
+	iCommPort1.ReadOneOrMore(readStatus1, readBuf1);
+	User::WaitForRequest(readStatus1);
+
+	// Get the time after the read
+	TTime afterTime;
+	afterTime.UniversalTime();
+
+	// Make sure the read was successful
+	TestErrorCodeAndDescriptorL(readStatus1.Int(), readBuf1, KWriteBuf2, _L("Read from comm port 1"));
+	
+	// Make sure the read took at least the amount of time as the configured delay
+	// We need a long time-out here because the resolution of the timer may cause it to expire prematurely
+	const TTimeIntervalMicroSeconds delayTime((TInt)(0.5*KConfiguredPortLongDelayMicroseconds));
+	TTime netTime = afterTime - delayTime;
+	TestBooleanTrueL(netTime > beforeTime, _L("Check there was a delay writing to the port"));
+	
+	return TestStepResult();
+	}
+
+CLoopbackTestStep6::~CLoopbackTestStep6()
+	{
+	}
+
+CLoopbackTestStep6::CLoopbackTestStep6() : CLoopbackTestStepBase(KLoopackConfigTestNumber6)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep6);
+	}
+	
+TVerdict CLoopbackTestStep6::doTestStepL()
+/**
+Test reading an entry with too small a read buffer
+*/
+	{
+	INFO_PRINTF1(_L("Starting Loopback test step 6"));
+
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	
+	TRequestStatus readStatus1;
+	TBuf8<KTooSmallBufferSize> smallReadBuf;
+	TBuf8<KRegularBufferSize> largeEnoughReadBuf1;
+	TRequestStatus writeStatus2;
+
+	iCommPort2.Write(writeStatus2, KWriteBuf1);
+	User::WaitForRequest(writeStatus2);
+	TestErrorCodeL(writeStatus2.Int(), _L("Writing to comm port 1"));
+		
+	// Issue read that should fail from too small of a buffer
+	iCommPort1.ReadOneOrMore(readStatus1, smallReadBuf);
+	User::WaitForRequest(readStatus1);
+	TestErrorCodeL(readStatus1.Int(), KErrOverflow, _L("Check that read fails becuase too small buffer supplied"));
+
+	// Issue read that should succeed
+	iCommPort1.ReadOneOrMore(readStatus1, largeEnoughReadBuf1);
+	User::WaitForRequest(readStatus1);
+	TestErrorCodeAndDescriptorL(readStatus1.Int(), largeEnoughReadBuf1, KWriteBuf1, _L("Read from comm port 1"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep7::~CLoopbackTestStep7()
+	{
+	}
+
+CLoopbackTestStep7::CLoopbackTestStep7() : CLoopbackTestStepBase(KLoopackConfigTestNumber7)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep7);
+	}
+	
+TVerdict CLoopbackTestStep7::doTestStepL()
+/**
+Test issuing write with too large of a buffer
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	
+	// Create the large buffer
+	HBufC8 *hugeHeapDescriptor = HBufC8::NewLC(KHugeBufferSize);
+	TPtr8 hugeDescriptor = hugeHeapDescriptor->Des();
+	hugeDescriptor.AppendFill('a', KHugeBufferSize);
+	
+	// Issue the write with the buffer that is too large
+	TRequestStatus writeStatus1, readStatus1;
+	iCommPort2.Write(writeStatus1, hugeDescriptor);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), KErrArgument, _L("Writing to comm port 1"));
+
+	// Make sure write still works with normal sized buffer
+	iCommPort2.Write(writeStatus1, KWriteBuf1);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+		
+	TBuf8<KRegularBufferSize> readBuf;
+	iCommPort1.ReadOneOrMore(readStatus1, readBuf);
+	User::WaitForRequest(readStatus1);
+	if (readStatus1 != KErrNone)
+		{
+		INFO_PRINTF1(_L("Failed read"));
+		SetTestStepResult(EFail);
+		}
+
+	CleanupStack::PopAndDestroy(hugeHeapDescriptor);
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep8::~CLoopbackTestStep8()
+	{
+	}
+
+CLoopbackTestStep8::CLoopbackTestStep8() : CLoopbackTestStepBase(KLoopackConfigTestNumber8)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep8);
+	}
+	
+TVerdict CLoopbackTestStep8::doTestStepL()
+/**
+Test wrapping around the queue by issuing more writes than the queue size (configured to 2 in the ini file)
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	
+	TRequestStatus writeStatus, readStatus;
+	iCommPort2.Write(writeStatus, KWriteBuf1);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), _L("Writing to comm port 1"));
+
+	iCommPort2.Write(writeStatus, KWriteBuf2);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), _L("Writing to comm port 1"));
+		
+	TBuf8<KRegularBufferSize> readBuf;
+	iCommPort1.ReadOneOrMore(readStatus, readBuf);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf1, _L("Read from comm port 1"));
+
+	iCommPort2.Write(writeStatus, KWriteBuf3);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), _L("Writing to comm port 1"));
+		
+	iCommPort1.ReadOneOrMore(readStatus, readBuf);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf2, _L("Read from comm port 1"));
+
+	iCommPort1.ReadOneOrMore(readStatus, readBuf);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf3, _L("Read from comm port 1"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep9::~CLoopbackTestStep9()
+	{
+	}
+
+CLoopbackTestStep9::CLoopbackTestStep9() : CLoopbackTestStepBase(KLoopackConfigTestNumber9)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep9);
+	}
+	
+TVerdict CLoopbackTestStep9::doTestStepL()
+/**
+Test read cancel
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	
+	TRequestStatus writeStatus, readStatus;
+	iCommPort1.Write(writeStatus, KWriteBuf1);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), _L("Writing to comm port 1"));
+
+	TBuf8<KRegularBufferSize> readBuf;
+	iCommPort2.ReadOneOrMore(readStatus, readBuf);
+	// Cancel the buffer before it has the chance to complete
+	iCommPort2.ReadCancel();
+	User::WaitForRequest(readStatus);
+	TestErrorCodeL(readStatus.Int(), KErrCancel, _L("Check that cancelled request returns KErrCancel"));
+	
+	// Make sure the read still works
+	iCommPort2.ReadOneOrMore(readStatus, readBuf);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf1, _L("Read from comm port 1"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep10::~CLoopbackTestStep10()
+	{
+	}
+
+CLoopbackTestStep10::CLoopbackTestStep10() : CLoopbackTestStepBase(KLoopackConfigTestNumber10)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep10);
+	}
+	
+TVerdict CLoopbackTestStep10::doTestStepL()
+/**
+Test flow control
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	
+	TRequestStatus writeStatus1;
+	iCommPort1.Write(writeStatus1, KWriteBuf1);
+	SetFlowControl(KPortUnitNum1, ETrue);
+	SetFlowControl(KPortUnitNum2, ETrue);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+
+	TRequestStatus timerStatus, readStatus;
+	TBuf8<KRegularBufferSize> readBuf;
+	iCommPort2.ReadOneOrMore(readStatus, readBuf);
+
+	RTimer timer;
+	timer.CreateLocal();
+	timer.After(timerStatus, 3*KConfiguredPortDelayMicroseconds);
+	
+	User::WaitForRequest(readStatus, timerStatus);
+	
+	SetFlowControl(KPortUnitNum1, EFalse);
+	SetFlowControl(KPortUnitNum2, EFalse);
+	TestBooleanTrueL(timerStatus == KErrNone && readStatus != KErrNone, _L("Check that setting flow control causes read to be stopped"));
+
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf1, _L("Read from comm port 1"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep11::~CLoopbackTestStep11()
+	{
+	}
+
+CLoopbackTestStep11::CLoopbackTestStep11() : CLoopbackTestStepBase(KLoopackConfigTestNumber11)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep11);
+	}
+	
+TVerdict CLoopbackTestStep11::doTestStepL()
+/**
+Test setting read result
+*/
+	{
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	
+	TRequestStatus writeStatus1;
+	iCommPort1.Write(writeStatus1, KWriteBuf1);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+
+	TRequestStatus readStatus;
+	TBuf8<KRegularBufferSize> readBuf;
+	iCommPort2.ReadOneOrMore(readStatus, readBuf);
+
+	SetReadResult(KPortUnitNum2, KErrNotFound);
+
+	User::WaitForRequest(readStatus);
+	
+	// Make sure everything still works
+	SetReadResult(KPortUnitNum2, KErrNone);
+	TestErrorCodeL(readStatus.Int(), KErrNotFound, _L("Check that SetReadResult causes Read to return error"));
+
+	iCommPort1.Write(writeStatus1, KWriteBuf2);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+
+	iCommPort2.ReadOneOrMore(readStatus, readBuf);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf2, _L("Read from comm port 1"));
+
+	// Now test failing a write
+	SetWriteResult(KPortUnitNum2, KErrNotFound);
+	iCommPort2.Write(writeStatus1, KWriteBuf3);
+	User::WaitForRequest(writeStatus1);
+	SetWriteResult(KPortUnitNum2, KErrNone);
+	TestErrorCodeL(writeStatus1.Int(), KErrNotFound, _L("Check that SetWriteResult causes Write to return error"));
+
+	// Make sure we can't read this
+	TRequestStatus timerStatus;
+	RTimer timer;
+	timer.CreateLocal();
+	iCommPort1.ReadOneOrMore(readStatus, readBuf);
+	timer.After(timerStatus, 3*KConfiguredPortDelayMicroseconds);
+	
+	User::WaitForRequest(readStatus, timerStatus);
+	TestBooleanTrueL(timerStatus == KErrNone && readStatus != KErrNone, _L("Write that was configured to fail completed successfully"));
+	
+	return TestStepResult();
+	}
+
+CLoopbackTestStep12::~CLoopbackTestStep12()
+	{
+	}
+
+CLoopbackTestStep12::CLoopbackTestStep12() : CLoopbackTestStepBase(KLoopackConfigTestNumber12)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep12);
+	}
+	
+_LIT8(KWriteBuf,"12345");
+_LIT8(KDoubleWriteBuf,"1234512345");
+_LIT8(KWriteBufTabTerminator,"12345\t");
+_LIT8(KWriteBufNewlineTerminator,"12345\n");
+_LIT8(KWriteBufTabThenNewlineTerminator,"12345\t12345\n12345");
+_LIT8(KWriteBufNewlineThenTabTerminator,"12345\n12345\t12345");
+const TInt KWriteBufSegmentSize = 5;
+
+TVerdict CLoopbackTestStep12::doTestStepL()
+/**
+Test setting read result
+*/
+	{
+	TRequestStatus readStatus;
+	TBuf8<KWriteBufSegmentSize> readBuf;
+	TRequestStatus writeStatus1;
+
+	TCommConfig commConfigBuf;
+	TCommConfigV01& commConfig = commConfigBuf();
+	commConfig.iTerminator[0] = '\t';
+	commConfig.iTerminator[1] = '\n';
+	commConfig.iTerminatorCount = 2;
+	
+	TestErrorCodeL( iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort1.SetConfig(commConfigBuf), _L("Opening comm port 1") );
+	TestErrorCodeL( iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE), _L("Opening comm port 2") );
+	TestErrorCodeL( iCommPort2.SetConfig(commConfigBuf), _L("Opening comm port 2") );
+		
+	// reads and writes are same size
+	iCommPort1.Write(writeStatus1, KWriteBuf);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+
+	iCommPort2.ReadOneOrMore(readStatus, readBuf);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf, KWriteBuf, _L("Read from comm port 1"));
+	
+
+	// test ReadOneOrMore
+	iCommPort1.Write(writeStatus1, KWriteBufTabThenNewlineTerminator);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Writing to comm port 1"));
+
+	TBuf8<KRegularBufferSize> readBuf2;
+	iCommPort2.ReadOneOrMore(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	if (readBuf2.Compare(KWriteBufTabTerminator) != 0 || readStatus != KErrNone)
+		{
+		INFO_PRINTF1(_L("Failed write"));
+		SetTestStepResult(EFail);
+		}
+	
+	iCommPort2.ReadOneOrMore(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeL(readStatus.Int(), _L("Error in read status"));
+	TestErrorCodeL(readBuf2.Compare(KWriteBufNewlineTerminator), _L("Incorrect buffer received"));
+	
+	iCommPort2.ReadOneOrMore(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	if (readBuf2.Compare(KWriteBuf) != 0 || readStatus != KErrNone)
+		{
+		INFO_PRINTF1(_L("Failed write"));
+		SetTestStepResult(EFail);
+		}
+	
+	iCommPort1.Write(writeStatus1, KWriteBufNewlineThenTabTerminator);
+	User::WaitForRequest(writeStatus1);
+	TestErrorCodeL(writeStatus1.Int(), _L("Failed write"));
+
+	iCommPort2.ReadOneOrMore(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	TestBooleanTrueL(readBuf2.Compare(KWriteBufNewlineTerminator) == 0 && readStatus == KErrNone, _L("Failed read"));
+	
+	iCommPort2.ReadOneOrMore(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	TestBooleanTrueL(readBuf2.Compare(KWriteBufTabTerminator) == 0 && readStatus == KErrNone, _L("Failed read"));
+	
+	iCommPort2.ReadOneOrMore(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	TestBooleanTrueL(readBuf2.Compare(KWriteBuf) == 0 || readStatus == KErrNone, _L("Failed read"));
+
+	return TestStepResult();
+	}
+
+CLoopbackTestStep13::~CLoopbackTestStep13()
+	{
+	}
+
+CLoopbackTestStep13::CLoopbackTestStep13() : CLoopbackTestStepBase(KLoopackConfigTestNumber13)
+	{
+	// Call base class method to set up the human readable name for logging
+	SetTestStepName(KLoopbackTestStep13);
+	}
+	
+TVerdict CLoopbackTestStep13::doTestStepL()
+/**
+Test setting read result
+*/
+	{
+	TRequestStatus readStatus;
+	TRequestStatus writeStatus;
+
+	TCommConfig commConfigBuf;
+	TCommConfigV01& commConfig = commConfigBuf();
+	commConfig.iTerminator[0] = '\t';
+	commConfig.iTerminator[1] = '\n';
+	commConfig.iTerminatorCount = 2;
+	
+	TInt err = iCommPort1.Open(iCommServer, KPortName1, ECommExclusive, ECommRoleDCE);
+	err = iCommPort1.SetConfig(commConfigBuf);
+	TestErrorCodeL(err, _L("Failed loading port"));
+		
+	err = iCommPort2.Open(iCommServer, KPortName2, ECommExclusive, ECommRoleDCE);
+	err = iCommPort2.SetConfig(commConfigBuf);
+	TestErrorCodeL(err, _L("Failed loading port"));
+	
+	// make sure Read works
+	iCommPort1.Write(writeStatus, KWriteBufNewlineThenTabTerminator);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), _L("Write failed"));
+
+	TBuf8<KRegularBufferSize> readBuf2;
+	iCommPort2.Read(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf2, KWriteBufNewlineTerminator, _L("Read from comm port 1"));
+	
+	iCommPort2.Read(readStatus, readBuf2);
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf2, KWriteBufTabTerminator, _L("Read from comm port 1"));
+	
+	TRequestStatus timerStatus;
+	TBuf8<2*KWriteBufSegmentSize> readBuf4;
+	iCommPort2.Read(readStatus, readBuf4);
+
+	RTimer timer;
+	timer.CreateLocal();
+	timer.After(timerStatus, 10*KConfiguredPortDelayMicroseconds);
+
+	User::WaitForRequest(readStatus, timerStatus);
+	TestBooleanTrueL(timerStatus == KErrNone && readStatus != KErrNone, _L("Check that read didn't complete"));
+	
+	iCommPort1.Write(writeStatus, KWriteBuf);
+	User::WaitForRequest(writeStatus);
+	TestErrorCodeL(writeStatus.Int(), _L("Failed write"));
+
+	User::WaitForRequest(readStatus);
+	TestErrorCodeAndDescriptorL(readStatus.Int(), readBuf4, KDoubleWriteBuf, _L("Read from comm port 1"));
+
+	return TestStepResult();
+	}
+