// Copyright (c) 2008-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
 @internalTechnology
*/

#include "t_coredumpmonitor.h"

//Names of functions to be tested - referenced from script file
_LIT(KUntrustedAccessToSCMConfig, "UntrustedAccessToSCMConfig");
_LIT(KGatherTraceBuffer, "GatherTraceBuffer");
_LIT(KTrustedAccessToSCMConfig, "TrustedAccessToSCMConfig");
_LIT(KReadDefaultConfigValues, "ReadDefaultConfigValues");
_LIT(KValidateNewestCrash, "ValidateNewestCrash");

/**
 * Constructor for test wrapper
 */
CCoreDumpMonitorWrapper::CCoreDumpMonitorWrapper()
	{
	}

/**
 * Destructor
 */
CCoreDumpMonitorWrapper::~CCoreDumpMonitorWrapper()
	{
	iCoreDumpSession.Close();
	iCrashList.ResetAndDestroy();
	iFsSession.Close();
	}

/**
 * Two phase constructor for CCoreDumpMonitorWrapper
 * @return CCoreDumpMonitorWrapper object
 * @leave
 */
CCoreDumpMonitorWrapper* CCoreDumpMonitorWrapper::NewL()
	{
	CCoreDumpMonitorWrapper* ret = new (ELeave) CCoreDumpMonitorWrapper();
	CleanupStack::PushL(ret);
	ret->ConstructL();
	CleanupStack::Pop(ret);
	return ret;
	}

/**
 * Safe construction
 * @leave
 */
void CCoreDumpMonitorWrapper::ConstructL()
	{
	

	User::LeaveIfError(iCoreDumpSession.Connect());
	User::LeaveIfError(iFsSession.Connect());
	}

/**
 * Assign the object
 * @param aObject TAny* to the object to test
 * @leave
 */
void CCoreDumpMonitorWrapper::SetObjectL(TAny* aObject)
	{}

/**
 * Runs a test preamble
 */
void CCoreDumpMonitorWrapper::PrepareTestL()
	{
	SetBlockResult(EPass);
	INFO_PRINTF1(_L("CCoreDumpMonitorWrapper::Ready to start test"));
	}

/**
 * Handle a command invoked from the script
 * @param aCommand Is the name of the command for a TBuf
 * @param aSection Is the .ini file section where parameters to the command are located
 * @param aAsyncErrorIndex Is used by the TEF Block framework to handle asynchronous commands.
 */
TBool CCoreDumpMonitorWrapper::DoCommandL(const TTEFFunction& aCommand, const TTEFSectionName& aSection, const TInt aAsyncErrorIndex)
	{
	//__UHEAP_MARK;	
	PrepareTestL();

	if (KUntrustedAccessToSCMConfig() == aCommand)
		{
		TestUntrustedAccessToCDSConfigL();
		}
	else if(KGatherTraceBuffer() == aCommand)
		{
		TestTraceBufferAccessL();
		}
	else if(KTrustedAccessToSCMConfig() ==aCommand)
		{
		TestTrustedAccessToCDSConfigL();
		}
	else if (KReadDefaultConfigValues() == aCommand)
		{
		TestReadDefaultConfigValuesL();
		}
else if(KValidateNewestCrash() == aCommand)
		{
		TestValidateNewestCrashL();
		}
	else
		{
		return EFalse;
		}

	//__UHEAP_MARKEND;

	return ETrue;
	}

void CCoreDumpMonitorWrapper::TestTrustedAccessToCDSConfigL()
	{
	INFO_PRINTF1(_L("TestTrustedAccessToCDSConfigL"));
	
	INFO_PRINTF1(_L("Getting the number of config parameters"));
	
	TUint numConfigParams = 0;
	TRAPD(err, numConfigParams = iCoreDumpSession.GetNumberConfigParametersL());
	if(KErrNone != err)
		{
		ERR_PRINTF2(_L("Unable to get the number of config parameters. Returned %d"), err);		
		SetBlockResult(EFail);
		return;
		}
	
	INFO_PRINTF2(_L("Found %d params"), numConfigParams);
	TBool foundScmConfig = EFalse;
	
	for (TInt i = 0; i < numConfigParams; i++)
		{
		COptionConfig* conf;
		conf = iCoreDumpSession.GetConfigParameterL(i);
		
		if (conf->Source()== COptionConfig::ESCMConfig)
			{
			foundScmConfig = ETrue;
			}
		
		delete conf;
		}
	
	if(!foundScmConfig)
		{
		ERR_PRINTF1(_L("Not Able to retrieve a config param for the SCM"));		
		SetBlockResult(EFail);
		return;
		}
	
	INFO_PRINTF1(_L("Looked at all config parameters and found some SCM params so that is a pass"));
	}

/**
 * Tests that that CDS enforces that untrusted users cannot 
 * access the CDS configuration
 */
void CCoreDumpMonitorWrapper::TestUntrustedAccessToCDSConfigL()
	{
	INFO_PRINTF1(_L("TestUntrustedAccessToCDSConfigL"));
	
	INFO_PRINTF1(_L("Getting the number of config parameters"));
	
	TUint numConfigParams = 0;
	TRAPD(err, numConfigParams = iCoreDumpSession.GetNumberConfigParametersL());
	if(KErrNone != err)
		{
		ERR_PRINTF2(_L("Unable to get the number of config parameters. Returned %d"), err);		
		SetBlockResult(EFail);
		return;
		}
	
	INFO_PRINTF2(_L("Found %d params"), numConfigParams);
	
	for (TInt i = 0; i < numConfigParams; i++)
		{
		COptionConfig* conf;
		conf = iCoreDumpSession.GetConfigParameterL(i);
		
		if (conf->Source()== COptionConfig::ESCMConfig)
			{
			ERR_PRINTF1(_L("Able to retrieve a config param for the SCM"));		
			SetBlockResult(EFail);
			delete conf;
			return;
			}
		
		delete conf;
		}
	
	INFO_PRINTF1(_L("Looked at all config parameters and none were SCM params so that is a pass"));
	}

void CCoreDumpMonitorWrapper::TestTraceBufferAccessL()
	{
	//Step 1: Load the UTRACE formatter and file writter
	INFO_PRINTF1(_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL loading UTRACE Formatter and File Writer"));

	TPluginRequest loadUtracePlugin;
	loadUtracePlugin.iPluginType = TPluginRequest::EFormatter;
	loadUtracePlugin.iLoad = ETrue;
	loadUtracePlugin.iUid = KUtraceUid;	
	
	TPluginRequest loadWriterReq;
	loadWriterReq.iPluginType = TPluginRequest::EWriter;
	loadWriterReq.iLoad = ETrue;
	loadWriterReq.iUid = KUidFileWriter;
	
	// loading Symbian ELF formatter
	TRAPD(err, iCoreDumpSession.PluginRequestL(loadUtracePlugin));
	if (err != KErrNone)
		{
		ERR_PRINTF2(_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL() Could not load UTRACE plugin!, err:%d\n"), err);
		SetBlockResult(EFail);
		User::Leave(err);
		}	
	
	// loading Symbian File writer
	TRAP(err, iCoreDumpSession.PluginRequestL(loadWriterReq));
	if (err != KErrNone)
		{
		ERR_PRINTF2(_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL() Could not load writer plugin!, err:%d\n"), err);
		SetBlockResult(EFail);
		User::Leave(err);
		}
	
	//Configuring the file writer plugin to have a specified crash file name
	TRAP(err, DoConfigureL((TInt)(CCrashDataSave::ECoreFilePath),
			KUidFileWriter.iUid, COptionConfig::EWriterPlugin,
			COptionConfig::ETFileName, KFilePathPrompt, 1, KNullDesC, 0,
			KCrashFileName, 0));

	if (err != KErrNone)
		{
		ERR_PRINTF2(_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL()() for File Writer Error %d changing param"),
				err);
		SetBlockResult(EFail);
		User::Leave(err);
		}	
	
	//List crashes in flash
	iCrashList.Reset();
	TRAP(err, iCoreDumpSession.ListCrashesInFlashL(iCrashList));
	if (err != KErrNone)
		{
		ERR_PRINTF2(_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL() Could not read Crashes in the Flash! err:%d\n"), err);
		SetBlockResult(EFail);
		User::Leave(err);
		}	
	
	INFO_PRINTF2(_L("Number of crashes present: %d"),	iCrashList.Count());
	if(iCrashList.Count() == 0)
		{
		ERR_PRINTF1(_L("Failed to find any crashes in log for the analysing"));
		SetBlockResult(EFail);
		User::Leave(err);
		}
	
	//Step 2: Process the crash
	for (TInt i = 0; i < iCrashList.Count(); i++)
		{
		TRAP(err, iCoreDumpSession.ProcessCrashLogL(iCrashList[i]->iCrashId));
		if (err != KErrNone)
			{
			ERR_PRINTF2(_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL() Could not process crash! err:%d\n"), err);
			SetBlockResult(EFail);
			User::Leave(err);
			}
		}
	
	INFO_PRINTF1(_L("Crashes Processed, Now looking for file generated"));
	
	//Step 3: Check the trace file has been generated
	//Use wildcard utilities to search for the UTRACE FIle Created
	TBuf<32> buf;
	buf = KDir;
	TUidType uid1;
	TUidType uid2(uid1.MostDerived());

	CFindFileByType* obj = new(ELeave) CFindFileByType(iFsSession);
	CleanupStack::PushL(obj);

	err = obj->FindFirst(KCrashWildCard, buf, uid2);
	if (err != KErrNone)
		{
		ERR_PRINTF2(
				_L("CCoreDumpMonitorWrapper::TestTraceBufferAccessL() Error finding the UTRACE File %d"),
				err);
		SetBlockResult(EFail);
		User::Leave(err);
		}
	
	INFO_PRINTF2(_L("The UTRACE File Found is E:\\:%S "), &(obj->Entry().iName));	
	
	CleanupStack::PopAndDestroy(); //CFindFileByType
	
	
	//Future improvements: Check contents of file
	}

/**
 * Tests that that after deletion of the entire partition  
 * SCM config values should correspond to the default build time values
 */
void CCoreDumpMonitorWrapper::TestReadDefaultConfigValuesL()
	{
	INFO_PRINTF1(_L("CCoreDumpMonitorWrapper::TestReadDefaultConfigValuesL Match with Build time SCM config values"));
	
	TInt noConfigParams = 0;
	TInt scmConfigParams = 0;
	// this will ultimateley read the config
    TRAPD(err, noConfigParams = iCoreDumpSession.GetNumberConfigParametersL());
    if(err != KErrNone)
        {
        ERR_PRINTF1(_L("Could not read number of config params"));
		SetBlockResult(EFail);
		User::Leave(KErrGeneral);       
        }
    else
    	{	
    	INFO_PRINTF2(_L("Found %d config params"), noConfigParams);
    	
		for (TInt i = 0; i < noConfigParams; i++)
			{
			COptionConfig* conf = iCoreDumpSession.GetConfigParameterL(i);
			CleanupStack::PushL(conf);
			
			if (conf->Source()== COptionConfig::ESCMConfig)
				{
				//count number of SCM configurations
				scmConfigParams++;
				TConfigItem::TSCMDataType dataType = (TConfigItem::TSCMDataType) conf->Instance();

				//Default SCM Configuration for TConfigItem::EThreadsUsrStack has priority = 0
				if(dataType == TConfigItem::EThreadsUsrStack && conf->Value() != 0)  
					{
					ERR_PRINTF3(_L("TConfigItem::EThreadsUsrStack did not match the ZERO Priority for config data type %d with priority %d"), dataType, conf->Value());
					SetBlockResult(EFail);
					User::Leave(KErrGeneral);
					}
				//Default SCM Configuration for TConfigItem::EThreadsSvrStack has priority = 0
				else if(dataType == TConfigItem::EThreadsSvrStack && conf->Value() != 0)
					{
					ERR_PRINTF3(_L("TConfigItem::EThreadsSvrStack did not match the ZERO Priority for config data type %d with priority %d"), dataType, conf->Value());
					SetBlockResult(EFail);
					User::Leave(KErrGeneral);
					}
				else if (dataType == TConfigItem::EThreadsSvrStack || dataType == TConfigItem::EThreadsUsrStack)
						{
						INFO_PRINTF3(_L("VERIFIED ZERO priority for config data type %d priority %d"), dataType, conf->Value());
						CleanupStack::PopAndDestroy(conf);
						continue;
						}
 
				//Default SCM Configuration for all has a priority value equal to thier postion in the list + 1
				if(conf->Value() != (dataType + 1) )
					{
					ERR_PRINTF3(_L("Did not match the DEFAULT Configurtion for config data type %d with priority %d"), dataType, conf->Value());
					SetBlockResult(EFail);
					User::Leave(KErrGeneral);			
					}
				
				//happy to print the value
				INFO_PRINTF3(_L("VERIFIED config data type %d has priority %d"), dataType, conf->Value());
					
				}
		
			CleanupStack::PopAndDestroy(conf);//COptionConfig
			}//for loop for noConfigParams
		
		INFO_PRINTF2(_L("Match with DEFAULT config values Successful for %d SCM Configuration Parameters"),scmConfigParams);
    	}//else for no errors GetNumberConfigParametersL
	
	}

/**
 * @return void
 * @param aIndex Internal index to the component that owns the object
 * @param aUID UID of the component that owns the object
 * @param aSource Type of component that owns the object
 * @param aType Type of parameter
 * @param aPrompt Prompt to present to user 
 * @param aNumOptions Number of options that the parameter can be set to. Only applies if type is ETMultiEntryEnum.
 * @param aOptions Comma separated list of options. Applies to ETMultiEntryEnum and ETBool
 * @param aVal Integer value. Applies to ETInt, ETUInt, ETBool
 * @param aStrValue String value. Applies to ETString, ETFileName, ETMultiEntry, ETBool
 */
void CCoreDumpMonitorWrapper::DoConfigureL(const TUint32& aIndex,
		const TUint32& aUID, const COptionConfig::TParameterSource& aSource,
		const COptionConfig::TOptionType& aType, const TDesC& aPrompt,
		const TUint32& aNumOptions, const TDesC& aOptions, const TInt32& aVal,
		const TDesC& aStrValue, const TUint aInstance)
	{
	COptionConfig * config;

	config = COptionConfig::NewL(aIndex, aUID, aSource, aType, aPrompt,
			aNumOptions, aOptions, aVal, aStrValue);

	CleanupStack::PushL(config);

	config->Instance(aInstance);

	//Configure now...
	iCoreDumpSession.SetConfigParameterL(*config);

	CleanupStack::PopAndDestroy(config);
	}


void CCoreDumpMonitorWrapper::TestValidateNewestCrashL()
	{
	
	INFO_PRINTF1(_L("TestValidateNewestCrashL called"));
	
	//Do list all the Crash Information here
	TRAPD(err, iCoreDumpSession.ListCrashesInFlashL(iCrashList));
	if (err != KErrNone)
		{
		ERR_PRINTF2(
				_L("TestValidateNewestCrashL Could not read Crashes in the Flash! err:%d\n"),
				err);
		SetBlockResult(EFail);
		return;
		//User::Leave(err);
		}

	INFO_PRINTF2(_L("TestValidateNewestCrashL Number of crash information present: %d"),
			iCrashList.Count());

	TInt expectedNewestIndex = 0;
	
	if( iCrashList.Count() > 0)
		{
		// must be entries for test to potentially fail	
		TInt newestIndex = 0;
		// start with first entry being newest time
		TUint64 newestTime = iCrashList[0]->iTime;
		
		for (TInt i = 0; i < iCrashList.Count(); i++)
			{		
			INFO_PRINTF3(_L("Crash no: %d, CrashId %d"), i, iCrashList[i]->iCrashId);
			INFO_PRINTF3(_L("Crash no: %d, Type %ld"), i, iCrashList[i]->iType);
			INFO_PRINTF3(_L("Crash no: %d, Time %ld"), i, iCrashList[i]->iTime);
			INFO_PRINTF3(_L("Crash no: %d, Thread ID %ld"), i, iCrashList[i]->iTid);
			
			// crash time held in the header as TUint64 - highest value should be the newset crash
			if(iCrashList[i]->iTime > newestTime)
				{
				newestIndex = i;
				newestTime = iCrashList[i]->iTime;
				}	
			}
			
		INFO_PRINTF2(_L("Newest crash is Crash no: %d"), newestIndex);
		if(newestIndex != expectedNewestIndex)
			{
			ERR_PRINTF3(_L("DoCmdValidateNewestCrashL newest crash was not in expected position expected (%d) actual(%d)")
					, expectedNewestIndex, newestIndex);
			SetBlockResult(EFail);
			//User::Leave(err);
			}			
		}
	
	INFO_PRINTF1(_L("TestValidateNewestCrashL finished"));
	
	}

//eof
