// Copyright (c) 1995-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\prime\t_timer.cpp
// Overview:
// Time and Timer tests.
// API Information:
// RTimer, TTime
// Details:
// - Test relative timers using the RTimer::After() method. Verify 
// results are as expected.
// - Set the date and time using TTime::HomeTime() and verify results
// are as expected.
// - Test absolute timers using RTimer::At() method. Verify results
// are as expected.
// - Test the timer is ok if its thread terminates.
// - Test synchronising time via the RTimer::Lock() method. Verify 
// results are as expected.
// - Test locked timers abort when the system time changes.
// - Test User::ResetInactivityTime() results are as expected.
// Platforms/Drives/Compatibility:
// All.
// Assumptions/Requirement/Pre-requisites:
// Failures and causes:
// Base Port information:
// 
//

// the following was used to help debug emulator implemenation of user mode callbacks
//#define REQUEST_STATUS_POLL_SOAK_TEST  

#define __E32TEST_EXTENSION__

#include <e32test.h>
#include <e32hal.h>
#include <e32panic.h>
#include <hal.h>
#include <e32power.h>
#include <e32math.h>

LOCAL_D RTest test(_L("T_TIMER"));
TInt MachineUid;

TInt AfterNegative(TAny*)
	{
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	t.After(s,-1);
	return KErrNone;
	}

TInt AfterTwice(TAny*)
	{
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	t.After(s,1000000);
	test(s==KRequestPending);
	t.After(s,1000000);
	return KErrNone;
	}

void PrintTime()
	{
	TTime now;
	now.HomeTime();
	TDateTime dt(now.DateTime());
	test.Printf(_L("Time: %02d:%02d:%02d:%06d\n"),dt.Hour(),dt.Minute(),dt.Second(),dt.MicroSecond());
	}

TBool RequestIsComplete(TRequestStatus& s)
	{
	return s != KRequestPending;
	}

LOCAL_C void testRel()
//
// Test relative timers.
//
	{

	test.Start(_L("After 0"));
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	t.After(s,0);
	test(s==KRequestPending || s==KErrNone);
	User::WaitForRequest(s);
	test(s==KErrNone);
//
	test.Next(_L("After 1 tenth"));
	t.After(s,100000);
#ifdef __WINS__
	// On WINS we can't guarantee thread scheduling so timer may already have
	// completed before we get to test the status. Therefore, allow KErrNone.
	test(s==KRequestPending || s==KErrNone);
	if(s==KErrNone)
		test.Printf(_L("NOTE: completed 'early'"));
#else
	test(s==KRequestPending);
#endif
	User::WaitForRequest(s);
	test(s==KErrNone);
//
	test.Next(_L("After -1 millionth"));
	RThread thread;
	r=thread.Create(_L("After -1"),AfterNegative,KDefaultStackSize,NULL,&thread);
	test(r==KErrNone);
	thread.Logon(s);
	test(s==KRequestPending);
	TBool justInTime=User::JustInTime();
	User::SetJustInTime(EFalse);
	thread.Resume();
	User::WaitForRequest(s);
	test(s==ERTimerAfterTimeNegative);
	test(thread.ExitCategory()==_L("USER"));
	test(thread.ExitReason()==ERTimerAfterTimeNegative);
	test(thread.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(thread);
	User::SetJustInTime(justInTime);
//
	test.Next(_L("After 1 second"));
	t.After(s,1000000);
	test(s==KRequestPending);
	User::WaitForRequest(s);
	test(s==KErrNone);
//
	test.Next(_L("After 1 second polling"));
	t.After(s,1000000);
	test(s==KRequestPending);
	// Have to be careful the compiler doesn't optimise this away
	while(!RequestIsComplete(s))
		; // poll
	test(s==KErrNone);
	User::WaitForRequest(s);
//
	test.Next(_L("Cancel"));
	t.After(s,1000000);
	test(s==KRequestPending);
	t.Cancel();
	User::WaitForRequest(s);
	test(s==KErrCancel);
	t.Close();
//
	test.Next(_L("Request twice"));
	r=thread.Create(_L("After twice"),AfterTwice,KDefaultStackSize,NULL,&thread);
	test(r==KErrNone);
	thread.Logon(s);
	test(s==KRequestPending);
	User::SetJustInTime(EFalse);
	thread.Resume();
	User::WaitForRequest(s);
	test(s==ETimerAlreadyPending);
	test(thread.ExitCategory()==_L("KERN-EXEC"));
	test(thread.ExitReason()==ETimerAlreadyPending);
	test(thread.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(thread);
	User::SetJustInTime(justInTime);
//
	test.End();
	}

#ifdef REQUEST_STATUS_POLL_SOAK_TEST

static volatile TBool PollTestRunning;

LOCAL_C TInt PollThread(TAny* aArg)
	{
	const TInt KMaxTimers = 1000;

	TInt threadIndex = (TInt)aArg;
	TInt64 seed = 5511498647534504549 + RThread().Id();
	RTimer timers[KMaxTimers];
	TRequestStatus statuses[KMaxTimers];

	TInt i;
	for (i = 0 ; i < KMaxTimers ; ++i)
		{
		test_KErrNone(timers[i].CreateLocal());
		statuses[i] = 1;
		}

	TInt totalComplete = 0;
	TInt totalWaiting = 0;
	
	while(PollTestRunning)
		{
		for (i = 0 ; i < KMaxTimers ; ++i)
			{
			switch(statuses[i].Int())
				{
				case KRequestPending:
					// do nothing
					++totalWaiting;
					break;
					
				case KErrNone:
					User::WaitForRequest(statuses[i]);
					++totalComplete;
					// fall through

				case 1:
					{
					TInt after = ((TUint)Math::Rand(seed) >> 28) + 1;
					timers[i].HighRes(statuses[i], after);
					}
					break;

				default:
					return statuses[i].Int();
				}
			}
		}
		
	for (i = 0 ; i < KMaxTimers ; ++i)
		{
		User::WaitForRequest(statuses[i]);
		if (statuses[i].Int() != KErrNone)
			return statuses[i].Int();
		timers[i].Close();
		}

	RDebug::Printf("%d: %d %d\n", threadIndex, totalComplete, totalWaiting);
	return KErrNone;
	}

LOCAL_C void testPoll()
	{
	const TInt KMaxThreads = 10;
	const TInt KSecondsToTest = 60;

	RThread threads[KMaxThreads];
	TRequestStatus statuses[KMaxThreads];
	
	test.Start(_L("Test polling"));

	PollTestRunning = ETrue;

	TInt i;
	for (i = 0 ; i < KMaxThreads ; ++i)
		{
		test_KErrNone(threads[i].Create(KNullDesC, PollThread, 0x1000, NULL, (TAny*)i));
		threads[i].Logon(statuses[i]);
		threads[i].Resume();
		}

	User::After(KSecondsToTest * 1000 * 1000);
	
	PollTestRunning = EFalse;

	for (i = 0 ; i < KMaxThreads ; ++i)
		{
		User::WaitForRequest(statuses[i]);
		test_KErrNone(statuses[i].Int());
		test_Equal(EExitKill, threads[i].ExitType());
		threads[i].Close();
		}
	
	test.End();
	}

#endif

LOCAL_C void testHomeTime()
//
// Test HomeTime.
//
	{

    TTime t1, t2;
    t1.HomeTime();
    for (TInt x=0;x<100;x++)
        {
        do
            {
            t2.HomeTime();
            }
        while (t2==t1);
#if defined(_DEBUG)
		TDateTime dt=t2.DateTime();
		test.Printf(_L("%d:%d\r\n"),dt.Second(),dt.MicroSecond());
#endif
        test(t2>t1);
        t1=t2;
        }
#if defined(_DEBUG)
	test.Printf(_L("\r\n"));
#endif
    }

TInt AtTwice(TAny*)
	{
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	TTime time;
	time.UniversalTime();
	t.AtUTC(s,time+TTimeIntervalSeconds(1));
	test(s==KRequestPending);
	t.AtUTC(s,time+TTimeIntervalSeconds(2));
	return KErrNone;
	}

TInt AtAfter(TAny*)
	{
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	TTime time;
	time.UniversalTime();
	t.AtUTC(s,time+TTimeIntervalSeconds(1));
	test(s==KRequestPending);
	t.After(s,1000000);
	return KErrNone;
	}

TInt AfterAt(TAny*)
	{
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	TTime time;
	time.UniversalTime();
	t.After(s,1000000);
	test(s==KRequestPending);
	t.AtUTC(s,time+TTimeIntervalSeconds(2));
	return KErrNone;
	}

LOCAL_C void testAbs()
//
// Test absolute timers.
//
	{

	test.Start(_L("Now -1"));
	RTimer t;
	TInt r=t.CreateLocal();
	test(r==KErrNone);
	TRequestStatus s;
	TTime time;
	time.UniversalTime();
	t.AtUTC(s,time+TTimeIntervalSeconds(-2));
	test(s==KErrUnderflow);  // =KRequestPending
	User::WaitForRequest(s);
	test(s==KErrUnderflow);
//
	TTime time2;
	test.Next(_L("Synchronise to clock"));
	time.UniversalTime();
    TDateTime dateTime=time.DateTime();
	dateTime.SetMicroSecond(0);
    time=dateTime;
 	time+=TTimeIntervalSeconds(2);
	t.AtUTC(s,time);
	User::WaitForRequest(s);

	test.Next(_L("Now +1"));
	time += TTimeIntervalSeconds(1);
	t.AtUTC(s,time);
	test(s==KRequestPending);
	User::WaitForRequest(s);
	time2.UniversalTime();
	test(s==KErrNone);
	TTimeIntervalMicroSeconds delay=time2.MicroSecondsFrom(time);
	// Test we are in the same second as the requested time...
	test(delay>=TTimeIntervalMicroSeconds(0));
	test(delay<TTimeIntervalMicroSeconds(1000000));

	test.Next(_L("Now +3"));
	time += TTimeIntervalSeconds(3);
	t.AtUTC(s,time);
	test(s==KRequestPending);
	User::WaitForRequest(s);
	time2.UniversalTime();
	test(s==KErrNone);
	delay=time2.MicroSecondsFrom(time);
	// Test we are in the same second as the requested time...
	test(delay>=TTimeIntervalMicroSeconds(0));
	test(delay<TTimeIntervalMicroSeconds(1000000));
//
	test.Next(_L("UTC vs local"));
	TTimeIntervalSeconds savedOffset = User::UTCOffset();
	User::SetUTCOffset(3600);
	
	time.HomeTime();
	time += TTimeIntervalSeconds(1);
	t.At(s,time);
	test(s==KRequestPending);
	User::WaitForRequest(s);
	time2.HomeTime();
	test(s==KErrNone);
	delay=time2.MicroSecondsFrom(time);
	// Test we are in the same second as the requested time...
	test(delay>=TTimeIntervalMicroSeconds(0));
	test(delay<TTimeIntervalMicroSeconds(1000000));
	
	time.UniversalTime();
	time += TTimeIntervalSeconds(1);
	t.AtUTC(s,time);
	test(s==KRequestPending);
	User::WaitForRequest(s);
	time2.UniversalTime();
	test(s==KErrNone);
	delay=time2.MicroSecondsFrom(time);
	// Test we are in the same second as the requested time...
	test(delay>=TTimeIntervalMicroSeconds(0));
	test(delay<TTimeIntervalMicroSeconds(1000000));
	
	User::SetUTCOffset(savedOffset);	
//
	test.Next(_L("Cancel"));
	time.UniversalTime();
	t.AtUTC(s,time+TTimeIntervalSeconds(10));
	test(s==KRequestPending);
	t.Cancel();
	User::WaitForRequest(s);
	test(s==KErrCancel);
	t.Close();						
//
	test.Next(_L("Request twice"));
	RThread thread;
	r=thread.Create(_L("At twice"),AtTwice,KDefaultStackSize,NULL,&thread);
	test(r==KErrNone);
	thread.Logon(s);
	test(s==KRequestPending);
	TBool justInTime=User::JustInTime();
	User::SetJustInTime(EFalse);
	thread.Resume();
	User::WaitForRequest(s);
	User::SetJustInTime(justInTime);
	test(s==ETimerAlreadyPending);
	test(thread.ExitCategory()==_L("KERN-EXEC"));
	test(thread.ExitReason()==ETimerAlreadyPending);
	test(thread.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(thread);
//
	r=thread.Create(_L("At After"),AtAfter,KDefaultStackSize,NULL,&thread);
	test(r==KErrNone);
	thread.Logon(s);
	test(s==KRequestPending);
	User::SetJustInTime(EFalse);
	thread.Resume();
	User::WaitForRequest(s);
	User::SetJustInTime(justInTime);
	test(s==ETimerAlreadyPending);
	test(thread.ExitCategory()==_L("KERN-EXEC"));
	test(thread.ExitReason()==ETimerAlreadyPending);
	test(thread.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(thread);
//
	r=thread.Create(_L("After At"),AfterAt,KDefaultStackSize,NULL,&thread);
	test(r==KErrNone);
	thread.Logon(s);
	test(s==KRequestPending);
	User::SetJustInTime(EFalse);
	thread.Resume();
	User::WaitForRequest(s);
	User::SetJustInTime(justInTime);
	test(s==ETimerAlreadyPending);
	test(thread.ExitCategory()==_L("KERN-EXEC"));
	test(thread.ExitReason()==ETimerAlreadyPending);
	test(thread.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(thread);
//
	test.End();
	}

TInt LockTwice(TAny*)
	{
	RTimer t;
	test(t.CreateLocal()==KErrNone);
	TRequestStatus stat;
	t.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	t.Lock(stat, ETwelveOClock);
	t.Lock(stat, ETwelveOClock);
	return KErrNone;
	}

LOCAL_C void testLock()
//
// Test locked timers
//
	{

	test.Start(_L("Test synchronise to ETwelveOClock"));
	RTimer t;
	TTime time,time2;
	test(t.CreateLocal()==KErrNone);
	TRequestStatus stat;
	t.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	time.UniversalTime();
	t.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);
	test(stat==KErrNone);
	time2.UniversalTime();
	test(time<time2);
	User::After(500000);
	test.Next(_L("Test sync to EOneOClock for 4 seconds"));
	t.Lock(stat, EOneOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	time.UniversalTime();
	TInt i;
	for (i=0; i<5; i++)
		{
		t.Lock(stat, EOneOClock);
		User::WaitForRequest(stat);
		test(stat==KErrNone);
		test.Printf(_L("."));
		}
	time2.UniversalTime();
	TTimeIntervalSeconds ti;
	test(time2.SecondsFrom(time, ti)==KErrNone);
	test(ti>=TTimeIntervalSeconds(4));
	test.Printf(_L("\n"));
	test.Next(_L("Test sync to every half second, from EFourOClock for 5 seconds"));
	t.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);
	for (i=0; i<5; i++)
		{
		t.Lock(stat, EFourOClock);
		User::WaitForRequest(stat);
		test(stat==KErrNone);
		test.Printf(_L("."));
		t.Lock(stat, ETenOClock);
		User::WaitForRequest(stat);
		test(stat==KErrNone);
		test.Printf(_L(","));
		}
	test.Printf(_L("\n"));
	test.Next(_L("Test KErrGeneral after delay"));
	User::After(1000000);
	t.Lock(stat,EThreeOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	test.Next(_L("Test cancel, and re-request immediately"));
	User::After(1000000);
	t.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	t.Lock(stat, EElevenOClock);
	t.Cancel();
	User::WaitForRequest(stat);
	test(stat==KErrCancel);
	t.Lock(stat, EElevenOClock);
	User::WaitForRequest(stat);
	test(stat==KErrNone);
	test.Next(_L("Test complete a request at 1, then cancel a request for 11, and re-request at 3 gives KErrGeneral"));
	User::After(1000000);
	t.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	t.Lock(stat,EOneOClock);
	User::WaitForRequest(stat);
	test(stat==KErrNone);
	t.Lock(stat,EElevenOClock);
	User::After(400000); // ensure EThreeOClock is in the past
	t.Cancel();
	User::WaitForRequest(stat);
	test(stat==KErrCancel);
	t.Lock(stat,EThreeOClock);
	User::WaitForRequest(stat);
	// EThreeOClock should be more than one second away from the previous timer expiration
	test(stat==KErrGeneral);
//
	test.Next(_L("Lock twice"));
	RThread thread;
	TInt r=thread.Create(_L("Lock twice"),LockTwice,KDefaultStackSize,NULL,&thread);
	test(r==KErrNone);
	thread.Logon(stat);
	test(stat==KRequestPending);
	TBool justInTime=User::JustInTime();
	User::SetJustInTime(EFalse);
	thread.Resume();
	User::WaitForRequest(stat);
	User::SetJustInTime(justInTime);
	test(stat==ETimerAlreadyPending);
	test(thread.ExitCategory()==_L("KERN-EXEC"));
	test(thread.ExitReason()==ETimerAlreadyPending);
	test(thread.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(thread);
//
	
#if !(defined(__EPOC32__) && defined(__X86__))
	TInt muid = 0;
	HAL::Get(HAL::EMachineUid, muid);
	if(muid!=HAL::EMachineUid_Lubbock && muid!=HAL::EMachineUid_NE1_TB)
		{
		test.Next(_L("Test sequential locks fail over on/off"));
		RTimer tat;
		TRequestStatus sat;
		r=tat.CreateLocal();
		TTime now;
		now.UniversalTime();
		tat.At(sat, now+TTimeIntervalSeconds(10)); // turn on in 10 seconds
		t.Lock(stat, ETwelveOClock);
		User::WaitForRequest(stat);
		test(stat==KErrGeneral);
		t.Lock(stat, EElevenOClock);
		User::WaitForRequest(stat);
		PrintTime();
		// Go to standby 
		r = Power::EnableWakeupEvents(EPwStandby);
		test (r == KErrNone);
		r = Power::PowerDown();
		test (r == KErrNone);
		test(stat==KErrNone);
		PrintTime();
		t.Lock(stat, EElevenOClock);
		User::WaitForRequest(stat);
		test(stat==KErrGeneral);
		tat.Close();
		}
#endif

	t.Close();
	test.End();
	}


void testChange()
//
// Bug HA-255
// Test locked timers abort when the system time changes
//
	{

    RTimer rr;
	TRequestStatus stat;
    rr.CreateLocal();
    rr.Lock(stat, ETwelveOClock);
    User::WaitForRequest(stat);
    test(stat==KErrGeneral);
    RTimer rrr;
    rrr.CreateLocal();
    rrr.After(stat, 1000000);
    User::WaitForRequest(stat);
    
	RTimer r;
	TRequestStatus sstat;
	TTime t;
	r.CreateLocal();
	r.Lock(stat,ETwelveOClock);
	rr.Lock(sstat,EOneOClock);
	User::WaitForRequest(stat);
	test(stat==KErrGeneral);
	User::WaitForRequest(sstat);
	test(sstat==KErrGeneral);
	r.Lock(stat,ETwelveOClock);
	rr.Lock(sstat,EOneOClock);
	User::WaitForRequest(stat);
	test(stat==KErrNone);
	User::WaitForRequest(sstat);
	test(sstat==KErrNone);
	t.UniversalTime();
	r.Lock(stat,ETwelveOClock);
	rr.Lock(sstat,EOneOClock);
	TInt ret=User::SetUTCTime(t-TTimeIntervalSeconds(100));
	test(ret==KErrNone);
	t.UniversalTime();
	ret=User::SetUTCTime(t+TTimeIntervalSeconds(100));
	test(ret==KErrNone);
	User::WaitForRequest(stat);
	test(stat==KErrAbort);
	User::WaitForRequest(sstat);
	test(sstat==KErrAbort);

	// Check that changing the *secure* time *doesn't* abort a locked timer
	r.Lock(stat, ETwelveOClock);
	User::WaitForRequest(stat);		// stat will be KErrGeneral after abort above, but time will be TwelveOClock anyway
	t.UniversalTimeSecure();
	r.Lock(stat, EEightOClock);
	ret = User::SetUTCTimeSecure(t+TTimeIntervalSeconds(100));
	User::WaitForRequest(stat);		// this timer should complete at EightOClock with status KErrNone, *not* KErrAbort
	r.Lock(sstat, ETwelveOClock);
	User::WaitForRequest(sstat);	// this should complete one whole second after we read the secure time above
	User::SetUTCTimeSecure(t+TTimeIntervalSeconds(1));
	test(stat == KErrNone);
	test(sstat == KErrNone);
	if (ret != KErrNone)
		RDebug::Printf("WARNING: Secure clock change test skipped because secure time could not be changed!");

	r.Close();
	rr.Close();
	rrr.Close();
	}

void testInactivity()
//
//
//
	{
	
	test.Start(_L("Test User::ResetInactivityTime()"));
	RTimer t,t2;
	TRequestStatus stat,stat2;
	t.CreateLocal();
	t2.CreateLocal();
	User::ResetInactivityTime();
	t.Inactivity(stat, 4);
	t2.Inactivity(stat2, 2);
	TTime now;
	now.UniversalTime();
	TInt r=User::SetUTCTime(now+TTimeIntervalDays(1));
	test(r==KErrNone);
	test(stat==KRequestPending);
	test(stat2==KRequestPending);
	r=User::SetUTCTime(now-TTimeIntervalDays(1));
	test(r==KErrNone);
	test(stat==KRequestPending);
	test(stat2==KRequestPending);
	r=User::SetUTCTime(now);
	test(r==KErrNone);
	test(stat==KRequestPending);
	test(stat2==KRequestPending);
	User::After(1000000);
	User::ResetInactivityTime();
	test(stat==KRequestPending);
	test(stat2==KRequestPending);
	User::After(3000000);
	User::ResetInactivityTime();
	test(stat==KRequestPending);
	test(stat2!=KRequestPending);
	User::After(2000000);
	User::ResetInactivityTime();
	test(stat==KRequestPending);
	User::After(2000000);
	User::ResetInactivityTime();
	test(stat==KRequestPending);
	User::After(5000000);
	test(stat!=KRequestPending);
	test.End();
	}

GLDEF_C TInt E32Main()
//
// Test timers.
//
    {

	test.Title();
	TInt r=HAL::Get(HAL::EMachineUid,MachineUid);
	test(r==KErrNone);
	test.Start(_L("Testing relative timers"));
	testRel();
//
#ifdef REQUEST_STATUS_POLL_SOAK_TEST
	test.Next(_L("Testing polling"));
	testPoll();
#endif
//
    test.Next(_L("Testing HomeTime()"));
    testHomeTime();
//
	test.Next(_L("Testing absolute timers"));
	testAbs();
//
	test.Next(_L("Testing locked timers"));
	testLock();
//
	test.Next(_L("Testing changing time"));
	testChange();
//
	test.Next(_L("Testing inactivity timers"));
	testInactivity();
//
	test.End();
	return(KErrNone);
    }

