Files
UnrealEngineUWP/Engine/Source/Developer/AutomationController/Private/AutomationCommandline.cpp
Bob Tellez 4b28d78a10 Copying up to CL#2909284 //UE4/Fortnite-Staging to //UE4/Main
This is CL#2904759 from //Fortnite/Main

#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2904398 on 2016/03/10 by Bob.Tellez

	#UE4 OnlineBeaconClients are now destroyed when net cleanup happens instead of normal destruction time so the behave more like PlayerControllers. Also added some low level protection from closing already closed beacons.

	#rb Josh.Markiewicz
	#codreview Josh.Markiewicz
	#JIRA FORT-20703

Change 2904339 on 2016/03/10 by Daniel.Broder

	Added support for allowing an actor to determine whether it is selectable or not (rather than relying purely on editor modes).

	One example use-case is a Transient actor created by WorldSettings for Fortnite which can otherwise be selected, edited, and even copied and pasted to a non-Transient form (which can be done accidentally and cause bugs).

	Change made after discussion with Bob.

	#CodeReview Bob.Tellez

	#UE4

Change 2903020 on 2016/03/10 by John.Abercrombie

	Added blueprint function to set named params for use when running an EQS query from BP
	- Phil is going to test this out for me.

	#rb me (Mieszko wrote this)
	#codereview Phil.Cole, Mieszko.Zielinski

Change 2902440 on 2016/03/09 by Ben.Zeigler

	#Jira FORT-20149
	Fix package map issue where if the client package map received a reference to a package that was already in the async loading queue due to an unrelated async load call, it would not register it correctly, which would lead to error messages and actors potentially not being initialized.
	#codereview john.pollard
	#RB bob.tellez

Change 2900138 on 2016/03/08 by Bob.Tellez

	#UE4 Updated the following Parameter value functions to respect the bOverride flag

	GetStaticSwitchParameterValue
	GetStaticComponentMaskParameterValue
	GetTerrainLayerWeightParameterValue

	#rb Nick.Penwarden

Change 2899839 on 2016/03/08 by Lukasz.Furman

	fixed navmesh projection on actors with overlap response to world channels
	#rb Mieszko.Zielinski
	#codereview Zak.Middleton

Change 2899743 on 2016/03/08 by Lukasz.Furman

	fixed handling multiple blocking hits in navwalking's geometry conforming
	blocking response was used in previous implementation accepting first hit, scoring mutliple points requires getting them all with overlap response
	#fortnite FORT-21546
	#rb Mieszko.Zielinski
	#codereview Zak.Middleton

Change 2898194 on 2016/03/07 by Chris.Gagnon

	Added the ability to filter DataTable Assets by their row using the metadata.
	meta = (RowType=MyRowName)

	#RB Saad.Nader
	#codereview Saad.Nader, Jamie.Dale

Change 2895102 on 2016/03/04 by Ben.Zeigler

	#JIRA FORT-20290
	Fix issue where if a server received a 408 on a verify auth call, it would get stuck in the "in progress" state, and would never try to verify auth again until the auth timed out
	Add additional logging to auth queries, to track this and other issues. The new log lines are permanent, but StartExtraLogging should be disabled before merging back to main
	#codereview josh.markiewicz

Change 2891302 on 2016/03/02 by Bob.Tellez

	#UE4 The spawned NavGraph actors in CreateNavigationDataInstance were getting immediately marked pending kill due to the existance of the FortNavGraph actors placed in the NavMeshBounds map. Marking an actor pending kill instead of calling destroy actor is dangerous since DestroyActor does many other things including removing the actor from the networked actors list. Failure to remove from this list caused FORT-21458. This change both removes the existing FortNavGraph actors from the registered list and better handles cleaning up NavigationData removed for this reason.

	#rb Ben.Zeigler
	#codereview Lukasz.Furman

Change 2887908 on 2016/03/01 by Chris.Gagnon

	Added Event Track to UMG Sequencer.
	Added PlayTo functionality for targeting the end point of a played animation.

	#RB Frank.Fella
	#codereview Frank.Fella, Nick.Darnell

Change 2887686 on 2016/03/01 by Joel.Crabbe

	Fixed issue with replication comparison object not necessarily being the correct, blueprint-defined, defaults-edited version. Changed GetClass()->GetDefaultObject to GetArchetype() for comparison value.

	#codereview Ben.Zeigler

Change 2886847 on 2016/02/29 by Bob.Tellez

	#UE4 Fixed a bug where pasting multiple lines of text into the property matrix would leave the \\r character in the string in windows platforms.

	#codereview Richard.TalbotWatkin

Change 2886414 on 2016/02/29 by Lukasz.Furman

	fixed start point of composite path's update
	#fortnite FORT-21380
	#rb Mieszko.Zielinski

Change 2886250 on 2016/02/29 by Bob.Tellez

	#UE4 Adding !IsInSlateThread to assert in SuspendLoading/ResumeLoading. I suspect this may be the cause of a race condition involving flushing async loading during startup.

	#codereview Robert.Manuszewski

Change 2885942 on 2016/02/29 by Bob.Tellez

	#UE4 Disabling per-instance mesh painting on instanced static mesh components.

	#rb Jack.Porter

[CL 2909292 by Bob Tellez in Main branch]
2016-03-14 21:21:09 -04:00

419 lines
12 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "AutomationControllerPrivatePCH.h"
/** States for running the automation process */
namespace EAutomationTestState
{
enum Type
{
Idle, // Automation process is not running
FindWorkers, // Find workers to run the tests
RequestTests, // Find the tests that can be run on the workers
DoingRequestedWork, // Do whatever was requested from the commandline
Complete // The process is finished
};
};
namespace EAutomationCommand
{
enum Type
{
ListAllTests, //List all tests for the session
//RunSingleTest, //Run one test specified by the commandline
RunCommandLineTests, //Run only tests that are listed on the commandline
RunAll, //Run all the tests that are supported
RunFilter, //
Quit //quit the app when tests are done
};
};
class FAutomationExecCmd : private FSelfRegisteringExec
{
public:
void Init()
{
SessionID = FApp::GetSessionId();
// Set state to FindWorkers to kick off the testing process
AutomationTestState = EAutomationTestState::Idle;
DelayTimer = 0.0f;
// Load the automation controller
IAutomationControllerModule* AutomationControllerModule = &FModuleManager::LoadModuleChecked<IAutomationControllerModule>("AutomationController");
AutomationController = AutomationControllerModule->GetAutomationController();
AutomationController->Init();
const bool bSkipScreenshots = FParse::Param(FCommandLine::Get(), TEXT("NoScreenshots"));
const bool bFullSizeScreenshots = FParse::Param(FCommandLine::Get(), TEXT("FullSizeScreenshots"));
const bool bSendAnalytics = FParse::Param(FCommandLine::Get(), TEXT("SendAutomationAnalytics"));
AutomationController->SetScreenshotsEnabled(!bSkipScreenshots);
AutomationController->SetUsingFullSizeScreenshots(bFullSizeScreenshots);
// Register for the callback that tells us there are tests available
AutomationController->OnTestsRefreshed().BindRaw(this, &FAutomationExecCmd::HandleRefreshTestCallback);
TickHandler = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &FAutomationExecCmd::Tick));
int32 NumTestLoops = 1;
FParse::Value(FCommandLine::Get(), TEXT("TestLoops="), NumTestLoops);
AutomationController->SetNumPasses(NumTestLoops);
TestCount = 0;
SetUpFilterMapping();
}
void SetUpFilterMapping()
{
FilterMaps.Empty();
FilterMaps.Add("Engine", EAutomationTestFlags::EngineFilter);
FilterMaps.Add("Smoke", EAutomationTestFlags::SmokeFilter);
FilterMaps.Add("Stress", EAutomationTestFlags::StressFilter);
FilterMaps.Add("Perf", EAutomationTestFlags::PerfFilter);
FilterMaps.Add("Product", EAutomationTestFlags::ProductFilter);
}
void Shutdown()
{
//IAutomationControllerModule* AutomationControllerModule = &FModuleManager::LoadModuleChecked<IAutomationControllerModule>("AutomationController");
//AutomationControllerModule->ShutdownModule();
FTicker::GetCoreTicker().RemoveTicker(TickHandler);
}
bool IsTestingComplete()
{
// If the automation controller is no longer processing and we've reached the final stage of testing
if ((AutomationController->GetTestState() != EAutomationControllerModuleState::Running) && (AutomationTestState == EAutomationTestState::Complete) && (AutomationCommandQueue.Num() == 0))
{
// If an actual test was ran we then will let the user know how many of them were ran.
if (TestCount > 0)
{
OutputDevice->Logf(TEXT("...Automation Test Queue Empty %d tests performed."), TestCount);
TestCount = 0;
}
return true;
}
return false;
}
void GenerateTestNamesFromCommandLine(const TArray<FString>& AllTestNames, TArray<FString>& OutTestNames)
{
FString AllTestNamesNoWhiteSpaces;
OutTestNames.Empty();
//Split the test names up
TArray<FString> Filters;
StringCommand.ParseIntoArray(Filters, TEXT("+"), true);
//trim cruft from all entries
for (int32 FilterIndex = 0; FilterIndex < Filters.Num(); ++FilterIndex)
{
Filters[FilterIndex] = Filters[FilterIndex].Trim();
Filters[FilterIndex] = Filters[FilterIndex].Replace(TEXT(" "), TEXT(""));
}
for (int32 TestIndex = 0; TestIndex < AllTestNames.Num(); ++TestIndex)
{
for (int FilterIndex = 0; FilterIndex < Filters.Num(); ++FilterIndex)
{
AllTestNamesNoWhiteSpaces = AllTestNames[TestIndex];
AllTestNamesNoWhiteSpaces = AllTestNamesNoWhiteSpaces.Replace(TEXT(" "), TEXT(""));
if (AllTestNamesNoWhiteSpaces.Contains(Filters[FilterIndex]))
{
OutTestNames.Add(AllTestNames[TestIndex]);
TestCount++;
break;
}
}
}
}
void FindWorkers(float DeltaTime)
{
// Time to delay requesting workers - ensure they are up and running
const float DelayTime = 5.0f;
DelayTimer += DeltaTime;
if (DelayTimer > DelayTime)
{
// Request the workers
AutomationController->RequestAvailableWorkers(SessionID);
AutomationTestState = EAutomationTestState::RequestTests;
}
}
void HandleRefreshTestCallback()
{
TArray <FString> AllTestNames;
// We have found some workers
// Create a filter to add to the automation controller, otherwise we don't get any reports
AutomationController->SetFilter(MakeShareable(new AutomationFilterCollection()));
AutomationController->SetVisibleTestsEnabled(true);
AutomationController->GetEnabledTestNames(AllTestNames);
//assume we won't run any tests
bool bRunTests = false;
if (AutomationCommand == EAutomationCommand::ListAllTests)
{
//TArray<FAutomationTestInfo> TestInfo;
//FAutomationTestFramework::GetInstance().GetValidTestNames(TestInfo);
for (int TestIndex = 0; TestIndex < AllTestNames.Num(); ++TestIndex)
{
OutputDevice->Logf(TEXT("%s"), *AllTestNames[TestIndex]);
}
OutputDevice->Logf(TEXT("Found %i Automation Tests"), AllTestNames.Num());
// Set state to complete
AutomationTestState = EAutomationTestState::Complete;
}
else if (AutomationCommand == EAutomationCommand::RunCommandLineTests)
{
TArray <FString> FilteredTestNames;
GenerateTestNamesFromCommandLine(AllTestNames, FilteredTestNames);
if (FilteredTestNames.Num())
{
AutomationController->SetEnabledTests(FilteredTestNames);
bRunTests = true;
}
else
{
AutomationTestState = EAutomationTestState::Complete;
}
}
else if (AutomationCommand == EAutomationCommand::RunFilter)
{
if (FilterMaps.Contains(StringCommand))
{
OutputDevice->Logf(TEXT("Running %i Automation Tests"), AllTestNames.Num());
AutomationController->SetEnabledTests(AllTestNames);
bRunTests = true;
}
else
{
AutomationTestState = EAutomationTestState::Complete;
OutputDevice->Logf(TEXT("%s is not a valid flag to filter on! Valid options are: "), *StringCommand);
TArray<FString> FlagNames;
FilterMaps.GetKeys(FlagNames);
for (int i = 0; i < FlagNames.Num(); i++)
{
OutputDevice->Log(FlagNames[i]);
}
}
}
else if (AutomationCommand == EAutomationCommand::RunAll)
{
bRunTests = true;
TestCount = AllTestNames.Num();
}
if (bRunTests)
{
AutomationController->RunTests();
// Set state to monitoring to check for test completion
AutomationTestState = EAutomationTestState::DoingRequestedWork;
}
}
void MonitorTests()
{
if (AutomationController->GetTestState() != EAutomationControllerModuleState::Running)
{
// We have finished the testing, and results are available
AutomationTestState = EAutomationTestState::Complete;
}
}
bool Tick(float DeltaTime)
{
// Update the automation controller to keep it running
AutomationController->Tick();
// Update the automation process
switch (AutomationTestState)
{
case EAutomationTestState::FindWorkers:
{
FindWorkers(DeltaTime);
break;
}
case EAutomationTestState::RequestTests:
{
break;
}
case EAutomationTestState::DoingRequestedWork:
{
MonitorTests();
break;
}
case EAutomationTestState::Complete:
case EAutomationTestState::Idle:
default:
{
//pop next command
if (AutomationCommandQueue.Num())
{
AutomationCommand = AutomationCommandQueue[0];
AutomationCommandQueue.RemoveAt(0);
if (AutomationCommand == EAutomationCommand::Quit)
{
if (AutomationCommandQueue.IsValidIndex(0))
{
// Add Quit back to the end of the array.
AutomationCommandQueue.Add(EAutomationCommand::Quit);
break;
}
}
AutomationTestState = EAutomationTestState::FindWorkers;
}
// Only quit if Quit is the actual last element in the array.
if (AutomationCommand == EAutomationCommand::Quit)
{
FPlatformMisc::RequestExit(true);
// We have finished the testing, and results are available
AutomationTestState = EAutomationTestState::Complete;
}
break;
}
}
return !IsTestingComplete();
}
/** Console commands, see embeded usage statement **/
virtual bool Exec(UWorld*, const TCHAR* Cmd, FOutputDevice& Ar) override
{
bool bHandled = false;
// Track whether we have a flag we care about passing through.
FString FlagToUse = "";
// Hackiest hack to ever hack a hack to get this test running.
if (FParse::Command(&Cmd, TEXT("RunPerfTests")))
{
Cmd = TEXT("Automation RunFilter Perf");
}
else if (FParse::Command(&Cmd, TEXT("RunProductTests")))
{
Cmd = TEXT("Automation RunFilter Product");
}
//figure out if we are handling this request
if (FParse::Command(&Cmd, TEXT("Automation")))
{
//save off device to send results to
OutputDevice = GLog;
StringCommand.Empty();
TArray<FString> CommandList;
StringCommand = Cmd;
StringCommand.ParseIntoArray(CommandList, TEXT(";"), true);
//assume we handle this
bHandled = true;
Init();
for (int CommandIndex = 0; CommandIndex < CommandList.Num(); ++CommandIndex)
{
const TCHAR* TempCmd = *CommandList[CommandIndex];
if (FParse::Command(&TempCmd, TEXT("List")))
{
AutomationCommandQueue.Add(EAutomationCommand::ListAllTests);
}
else if (FParse::Command(&TempCmd, TEXT("RunTests")))
{
//only one of these should be used
StringCommand = TempCmd;
AutomationCommandQueue.Add(EAutomationCommand::RunCommandLineTests);
}
else if (FParse::Command(&TempCmd, TEXT("RunFilter")))
{
FlagToUse = TempCmd;
//only one of these should be used
StringCommand = TempCmd;
if (FilterMaps.Contains(FlagToUse))
{
AutomationController->SetRequestedTestFlags(FilterMaps[FlagToUse]);
}
AutomationCommandQueue.Add(EAutomationCommand::RunFilter);
}
else if (FParse::Command(&TempCmd, TEXT("RunAll")))
{
AutomationCommandQueue.Add(EAutomationCommand::RunAll);
}
else if (FParse::Command(&TempCmd, TEXT("Quit")))
{
AutomationCommandQueue.Add(EAutomationCommand::Quit);
}
// let user know he mis-typed a param/command
else if (FParse::Command(&TempCmd, TEXT("RunTest")))
{
Ar.Logf(TEXT("Unhandled token \"RunTest\". You probably meant \"RunTests\". Bailing out."));
bHandled = false;
break;
}
}
}
// Shutdown our service
return bHandled;
}
private:
/** The automation controller running the tests */
IAutomationControllerManagerPtr AutomationController;
/** The current state of the automation process */
EAutomationTestState::Type AutomationTestState;
/** What work was requested */
TArray<EAutomationCommand::Type> AutomationCommandQueue;
/** What work was requested */
EAutomationCommand::Type AutomationCommand;
/** Delay used before finding workers on game instances. Just to ensure they have started up */
float DelayTimer;
/** Holds the session ID */
FGuid SessionID;
//device to send results to
FOutputDevice* OutputDevice;
//so we can release control of the app and just get ticked like all other systems
FDelegateHandle TickHandler;
//Extra commandline params
FString StringCommand;
//This is the numbers of tests that are found in the command line.
int32 TestCount;
//Dictionary that maps flag names to flag values.
TMap<FString, int32> FilterMaps;
};
static FAutomationExecCmd AutomationExecCmd;