Integrating latest from github/TIF/Runtime
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/JobRunner/TestImpactProcessJobInfo.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Result of a job that was run.
|
||||
enum class JobResult
|
||||
{
|
||||
NotExecuted, //!< The job was not executed (e.g. the job runner terminated before the job could be executed).
|
||||
FailedToExecute, //!< The job failed to execute (e.g. due to the arguments used to execute the job being invalid).
|
||||
Terminated, //!< The job was terminated by the job runner (e.g. job or runner timeout exceeded while job was in-flight).
|
||||
ExecutedWithFailure, //!< The job was executed but exited in an erroneous state (the underlying process returned non-zero).
|
||||
ExecutedWithSuccess //!< The job was executed and exited in a successful state (the underlying processes returned zero).
|
||||
};
|
||||
|
||||
//! The meta-data for a given job.
|
||||
struct JobMeta
|
||||
{
|
||||
JobResult m_result = JobResult::NotExecuted;
|
||||
AZStd::optional<AZStd::chrono::high_resolution_clock::time_point>
|
||||
m_startTime; //!< The time, relative to the job runner start, that this job started.
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_duration; //!< The duration that this job took to complete.
|
||||
AZStd::optional<ReturnCode> m_returnCode; //!< The return code of the underlying processes of this job.
|
||||
};
|
||||
|
||||
//! Representation of a unit of work to be performed by a process.
|
||||
//! @tparam JobInfoT The JobInfo structure containing the information required to run this job.
|
||||
//! @tparam JobPayloadT The resulting output of the processed artifact produced by this job.
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
class Job
|
||||
{
|
||||
public:
|
||||
using Info = JobInfoT;
|
||||
using Payload = JobPayloadT;
|
||||
|
||||
//! Constructor with r-values for the specific use case of the job runner.
|
||||
Job(Info jobInfo, JobMeta&& jobMeta, AZStd::optional<Payload>&& payload);
|
||||
|
||||
//! Returns the job info associated with this job.
|
||||
const Info& GetJobInfo() const;
|
||||
|
||||
//! Returns the result of this job.
|
||||
JobResult GetResult() const;
|
||||
|
||||
//! Returns the start time, relative to the job runner start, that this job started.
|
||||
AZStd::chrono::high_resolution_clock::time_point GetStartTime() const;
|
||||
|
||||
//! Returns the end time, relative to the job runner start, that this job ended.
|
||||
AZStd::chrono::high_resolution_clock::time_point GetEndTime() const;
|
||||
|
||||
//! Returns the duration that this job took to complete.
|
||||
AZStd::chrono::milliseconds GetDuration() const;
|
||||
|
||||
//! Returns the return code of the underlying processes of this job.
|
||||
AZStd::optional<ReturnCode> GetReturnCode() const;
|
||||
|
||||
//! Returns the payload produced by this job.
|
||||
const AZStd::optional<Payload>& GetPayload() const;
|
||||
|
||||
private:
|
||||
Info m_jobInfo;
|
||||
JobMeta m_meta;
|
||||
AZStd::optional<Payload> m_payload;
|
||||
};
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
Job<JobInfoT, JobPayloadT>::Job(Info jobInfo, JobMeta&& jobMeta, AZStd::optional<Payload>&& payload)
|
||||
: m_jobInfo(jobInfo)
|
||||
, m_meta(AZStd::move(jobMeta))
|
||||
, m_payload(AZStd::move(payload))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
const JobInfoT& Job<JobInfoT, JobPayloadT>::GetJobInfo() const
|
||||
{
|
||||
return m_jobInfo;
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
JobResult Job<JobInfoT, JobPayloadT>::GetResult() const
|
||||
{
|
||||
return m_meta.m_result;
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::optional<ReturnCode> Job<JobInfoT, JobPayloadT>::GetReturnCode() const
|
||||
{
|
||||
return m_meta.m_returnCode;
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::chrono::high_resolution_clock::time_point Job<JobInfoT, JobPayloadT>::GetStartTime() const
|
||||
{
|
||||
return m_meta.m_startTime.value_or(AZStd::chrono::high_resolution_clock::time_point());
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::chrono::high_resolution_clock::time_point Job<JobInfoT, JobPayloadT>::GetEndTime() const
|
||||
{
|
||||
if (m_meta.m_startTime.has_value() && m_meta.m_duration.has_value())
|
||||
{
|
||||
return m_meta.m_startTime.value() + m_meta.m_duration.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZStd::chrono::high_resolution_clock::time_point();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::chrono::milliseconds Job<JobInfoT, JobPayloadT>::GetDuration() const
|
||||
{
|
||||
return m_meta.m_duration.value_or(AZStd::chrono::milliseconds{0});
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
const AZStd::optional<JobPayloadT>& Job<JobInfoT, JobPayloadT>::GetPayload() const
|
||||
{
|
||||
return m_payload;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Per-job information to configure and run jobs and process the resulting artifacts.
|
||||
//! @tparam AdditionalInfo Additional information to be provided to each job to be consumed by client.
|
||||
template<typename AdditionalInfo>
|
||||
class JobInfo
|
||||
: public AdditionalInfo
|
||||
{
|
||||
public:
|
||||
using IdType = size_t;
|
||||
|
||||
//! Client-provided identifier to distinguish between different jobs.
|
||||
//! @note Ids of different job types are not interchangeable.
|
||||
struct Id
|
||||
{
|
||||
IdType m_value;
|
||||
};
|
||||
|
||||
//! Constructs the job information with any additional information required by the job.
|
||||
//! @param jobId The client-provided unique identifier for the job.
|
||||
//! @param args The arguments used to launch the process running the job.
|
||||
//! @param additionalInfo The arguments to be provided to the additional information data structure.
|
||||
template<typename... AdditionalInfoArgs>
|
||||
JobInfo(Id jobId, const AZStd::string& args, AdditionalInfoArgs&&... additionalInfo);
|
||||
|
||||
//! Returns the id of this job.
|
||||
Id GetId() const;
|
||||
|
||||
//! Returns the command arguments used to execute this job.
|
||||
const AZStd::string& GetArgs() const;
|
||||
|
||||
private:
|
||||
Id m_id;
|
||||
AZStd::string m_args;
|
||||
};
|
||||
|
||||
template<typename AdditionalInfo>
|
||||
template<typename... AdditionalInfoArgs>
|
||||
JobInfo<AdditionalInfo>::JobInfo(Id jobId, const AZStd::string& args, AdditionalInfoArgs&&... additionalInfo)
|
||||
: AdditionalInfo{std::forward<AdditionalInfoArgs>(additionalInfo)...}
|
||||
, m_id(jobId)
|
||||
, m_args(args)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename AdditionalInfo>
|
||||
typename JobInfo<AdditionalInfo>::Id JobInfo<AdditionalInfo>::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
template<typename AdditionalInfo>
|
||||
const AZStd::string& JobInfo<AdditionalInfo>::GetArgs() const
|
||||
{
|
||||
return m_args;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/Scheduler/TestImpactProcessScheduler.h>
|
||||
#include <TestImpactFramework/TestImpactCallback.h>
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Callback for job completion/failure.
|
||||
//! @param jobInfo The job information associated with this job.
|
||||
//! @param meta The meta-data about the job run.
|
||||
//! @param std The standard output and standard error of the process running the job.
|
||||
template<typename Job>
|
||||
using JobCallback = AZStd::function<CallbackResult(const typename Job::Info& jobInfo, const JobMeta& meta, StdContent&& std)>;
|
||||
|
||||
//! The payloads produced by the job-specific payload producer in the form of a map associating each job id with the job's payload.
|
||||
template<typename Job>
|
||||
using PayloadMap = AZStd::unordered_map<typename Job::Info::IdType, AZStd::optional<typename Job::Payload>>;
|
||||
|
||||
//! The map used by the client to associate the job information and meta-data with the job ids.
|
||||
template<typename Job>
|
||||
using JobDataMap = AZStd::unordered_map<typename Job::Info::IdType, AZStd::pair<JobMeta, const typename Job::Info*>>;
|
||||
|
||||
//! The callback for producing the payloads for the jobs after all jobs have finished executing.
|
||||
//! @param jobInfos The information for each job run.
|
||||
//! @param jobDataMap The job data (in the form of job info and meta-data) for each job run.
|
||||
template<typename Job>
|
||||
using PayloadMapProducer = AZStd::function<PayloadMap<Job>(const JobDataMap<Job>& jobDataMap)>;
|
||||
|
||||
//! Generic job runner that launches a process for each job, records metrics about each job run and hands the payload artifacts
|
||||
//! produced by each job to the client before compositing the metrics and payload artifacts for each job into a single interface
|
||||
//! to be consumed by the client.
|
||||
template<typename JobT>
|
||||
class JobRunner
|
||||
{
|
||||
public:
|
||||
//! Constructs the job runner with the specified parameters to constrain job runs.
|
||||
//! @param stdOutRouting The standard output routing to be specified for all jobs.
|
||||
//! @param stdErrRouting The standard error routing to be specified for all jobs.
|
||||
//! @param maxConcurrentProcesses he maximum number of concurrent jobs in-flight.
|
||||
//! @param processTimeout The maximum duration a job may be in-flight before being forcefully terminated (nullopt if no timeout).
|
||||
//! @param scheduleTimeout The maximum duration the scheduler may run before forcefully terminating all in-flight jobs (nullopt if
|
||||
//! no timeout).
|
||||
JobRunner(
|
||||
StdOutputRouting stdOutRouting,
|
||||
StdErrorRouting stdErrRouting,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> processTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> scheduleTimeout);
|
||||
|
||||
//! Executes the specified jobs and returns the products of their labor.
|
||||
//! @note: the job and payload callbacks are specified here rather than in the constructor to allow clients to use capturing lambdas
|
||||
//! should they desire to.
|
||||
//! @param jobs The arguments (and other pertinent information) required for each job to be run.
|
||||
//! @param jobCallback The client callback to be called when each job changes state.
|
||||
//! @param payloadMapProducer The client callback to be called when all jobs have finished to transform the work produced by each
|
||||
//! job into the desired output.
|
||||
AZStd::vector<typename JobT> Execute(
|
||||
const AZStd::vector<typename JobT::Info>& jobs, JobCallback<typename JobT> jobCallback,
|
||||
PayloadMapProducer<JobT> payloadMapProducer);
|
||||
|
||||
private:
|
||||
size_t m_maxConcurrentProcesses = 0; //!< Maximum number of concurrent jobs being executed at a given time.
|
||||
StdOutputRouting m_stdOutRouting; //!< Standard output routing from each job process to job runner.
|
||||
StdErrorRouting m_stdErrRouting; //!< Standard error routing from each job process to job runner
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_jobTimeout; //!< Maximum time a job can run for before being forcefully terminated.
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_runnerTimeout; //!< Maximum time the job runner can run before forcefully terminating all in-flight jobs and shutting down.
|
||||
};
|
||||
|
||||
template<typename JobT>
|
||||
JobRunner<JobT>::JobRunner(
|
||||
StdOutputRouting stdOutRouting,
|
||||
StdErrorRouting stdErrRouting,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> jobTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout)
|
||||
: m_maxConcurrentProcesses(maxConcurrentProcesses)
|
||||
, m_stdOutRouting(stdOutRouting)
|
||||
, m_stdErrRouting(stdErrRouting)
|
||||
, m_jobTimeout(jobTimeout)
|
||||
, m_runnerTimeout(runnerTimeout)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename JobT>
|
||||
AZStd::vector<JobT> JobRunner<JobT>::Execute(
|
||||
const AZStd::vector<typename JobT::Info>& jobInfos,
|
||||
JobCallback<JobT> jobCallback,
|
||||
PayloadMapProducer<JobT> payloadMapProducer)
|
||||
{
|
||||
AZStd::vector<ProcessInfo> processes;
|
||||
AZStd::unordered_map<JobT::Info::IdType, AZStd::pair<JobMeta, const typename JobT::Info*>> metas;
|
||||
AZStd::vector<JobT> jobs;
|
||||
jobs.reserve(jobInfos.size());
|
||||
processes.reserve(jobInfos.size());
|
||||
|
||||
// Transform the job infos into the underlying process infos required for each job
|
||||
for (size_t jobIndex = 0; jobIndex < jobInfos.size(); jobIndex++)
|
||||
{
|
||||
const auto* jobInfo = &jobInfos[jobIndex];
|
||||
const auto jobId = jobInfo->GetId().m_value;
|
||||
metas.emplace(jobId, AZStd::pair<JobMeta, const typename JobT::Info*>{JobMeta{}, jobInfo});
|
||||
processes.emplace_back(jobId, m_stdOutRouting, m_stdErrRouting, jobInfo->GetArgs());
|
||||
}
|
||||
|
||||
// Wrapper around low-level process launch callback to gather job meta-data and present a simplified callback interface to the client
|
||||
const auto processLaunchCallback = [&jobCallback, &jobInfos, &metas](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::LaunchResult launchResult,
|
||||
AZStd::chrono::high_resolution_clock::time_point createTime)
|
||||
{
|
||||
auto& [meta, jobInfo] = metas.at(pid);
|
||||
if (launchResult == LaunchResult::Failure)
|
||||
{
|
||||
meta.m_result = JobResult::FailedToExecute;
|
||||
return jobCallback(*jobInfo, meta, {});
|
||||
}
|
||||
else
|
||||
{
|
||||
meta.m_startTime = createTime;
|
||||
return CallbackResult::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper around low-level process exit callback to gather job meta-data and present a simplified callback interface to the client
|
||||
const auto processExitCallback = [&jobCallback, &jobInfos, &metas](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::ExitCondition exitCondition,
|
||||
TestImpact::ReturnCode returnCode,
|
||||
TestImpact::StdContent&& std,
|
||||
AZStd::chrono::high_resolution_clock::time_point exitTime)
|
||||
{
|
||||
auto& [meta, jobInfo] = metas.at(pid);
|
||||
meta.m_returnCode = returnCode;
|
||||
meta.m_duration = AZStd::chrono::duration_cast<AZStd::chrono::milliseconds>(exitTime - *meta.m_startTime);
|
||||
if (exitCondition == ExitCondition::Gracefull && returnCode == 0)
|
||||
{
|
||||
meta.m_result = JobResult::ExecutedWithSuccess;
|
||||
}
|
||||
else if (exitCondition == ExitCondition::Terminated || exitCondition == ExitCondition::Timeout)
|
||||
{
|
||||
meta.m_result = JobResult::Terminated;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta.m_result = JobResult::ExecutedWithFailure;
|
||||
}
|
||||
|
||||
return jobCallback(*jobInfo, meta, AZStd::move(std));
|
||||
};
|
||||
|
||||
// Schedule all jobs for execution
|
||||
ProcessScheduler scheduler(
|
||||
processes,
|
||||
processLaunchCallback,
|
||||
processExitCallback,
|
||||
m_maxConcurrentProcesses,
|
||||
m_jobTimeout,
|
||||
m_runnerTimeout
|
||||
);
|
||||
|
||||
// Hand off the jobs to the client for payload generation
|
||||
auto payloadMap = payloadMapProducer(metas);
|
||||
|
||||
// Unpack the payload map produced by the client into a vector of jobs containing the job data and payload for each job
|
||||
for (const auto& jobInfo : jobInfos)
|
||||
{
|
||||
const auto jobId = jobInfo.GetId().m_value;
|
||||
jobs.emplace_back(JobT(jobInfo, AZStd::move(metas.at(jobId).first), AZStd::move(payloadMap[jobId])));
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Process/Scheduler/TestImpactProcessScheduler.h>
|
||||
#include <Process/TestImpactProcess.h>
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
#include <Process/TestImpactProcessLauncher.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
struct ProcessScheduler::ProcessInFlight
|
||||
{
|
||||
AZStd::unique_ptr<Process> m_process;
|
||||
AZStd::optional<AZStd::chrono::high_resolution_clock::time_point> m_startTime;
|
||||
AZStd::string m_stdOutput;
|
||||
AZStd::string m_stdError;
|
||||
};
|
||||
|
||||
ProcessScheduler::ProcessScheduler(
|
||||
const AZStd::vector<ProcessInfo>& processes,
|
||||
const ProcessLaunchCallback& processLaunchCallback,
|
||||
const ProcessExitCallback& processExitCallback,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> processTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> scheduleTimeout)
|
||||
: m_processCreateCallback(processLaunchCallback)
|
||||
, m_processExitCallback(processExitCallback)
|
||||
, m_processTimeout(processTimeout)
|
||||
, m_scheduleTimeout(scheduleTimeout)
|
||||
, m_startTime(AZStd::chrono::high_resolution_clock::now())
|
||||
{
|
||||
AZ_TestImpact_Eval(maxConcurrentProcesses != 0, ProcessException, "Max Number of concurrent processes in flight cannot be 0");
|
||||
AZ_TestImpact_Eval(!processes.empty(), ProcessException, "Number of processes to launch cannot be 0");
|
||||
AZ_TestImpact_Eval(
|
||||
!m_processTimeout.has_value() || m_processTimeout->count() > 0, ProcessException,
|
||||
"Process timeout must be empty or non-zero value");
|
||||
AZ_TestImpact_Eval(
|
||||
!m_scheduleTimeout.has_value() || m_scheduleTimeout->count() > 0, ProcessException,
|
||||
"Scheduler timeout must be empty or non-zero value");
|
||||
|
||||
const size_t numConcurrentProcesses = AZStd::min(processes.size(), maxConcurrentProcesses);
|
||||
m_processPool.resize(numConcurrentProcesses);
|
||||
|
||||
for (const auto& process : processes)
|
||||
{
|
||||
m_processQueue.emplace(process);
|
||||
}
|
||||
|
||||
for (auto& process : m_processPool)
|
||||
{
|
||||
if (PopAndLaunch(process) == CallbackResult::Abort)
|
||||
{
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MonitorProcesses();
|
||||
}
|
||||
|
||||
ProcessScheduler::~ProcessScheduler()
|
||||
{
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
}
|
||||
|
||||
void ProcessScheduler::MonitorProcesses()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Check to see whether or not the scheduling has exceeded its specified runtime
|
||||
if (m_scheduleTimeout.has_value())
|
||||
{
|
||||
const auto shedulerRunTime = AZStd::chrono::milliseconds(AZStd::chrono::high_resolution_clock::now() - m_startTime);
|
||||
|
||||
if (shedulerRunTime > m_scheduleTimeout)
|
||||
{
|
||||
// Runtime exceeded, terminate all proccesses and schedule no further
|
||||
TerminateAllProcesses(ExitCondition::Timeout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Flag to determine whether or not there are currently any processes in-flight
|
||||
bool processesInFlight = false;
|
||||
|
||||
// Loop round the process pool and visit round robin queued up processes for launch
|
||||
for (auto& processInFlight : m_processPool)
|
||||
{
|
||||
if (processInFlight.m_process)
|
||||
{
|
||||
// Process is alive (note: not necessarilly currently running)
|
||||
AccumulateProcessStdContent(processInFlight);
|
||||
const ProcessId processId = processInFlight.m_process->GetProcessInfo().GetId();
|
||||
|
||||
if (!processInFlight.m_process->IsRunning())
|
||||
{
|
||||
// Process has exited of its own accord
|
||||
const ReturnCode returnCode = processInFlight.m_process->GetReturnCode().value();
|
||||
processInFlight.m_process.reset();
|
||||
const auto exitTime = AZStd::chrono::high_resolution_clock::now();
|
||||
|
||||
// Inform the client that the processes has exited
|
||||
if (CallbackResult::Abort == m_processExitCallback(
|
||||
processId,
|
||||
ExitCondition::Gracefull,
|
||||
returnCode,
|
||||
ConsumeProcessStdContent(processInFlight),
|
||||
exitTime))
|
||||
{
|
||||
// Client chose to abort the scheduler
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
else if (!m_processQueue.empty())
|
||||
{
|
||||
// This slot in the pool is free so launch one of the processes waiting in the queue
|
||||
if (PopAndLaunch(processInFlight) == CallbackResult::Abort)
|
||||
{
|
||||
// Client chose to abort the scheduler
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We know from the above PopAndLaunch there is at least one process in-flight this iteration
|
||||
processesInFlight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process is still in-flight
|
||||
const auto exitTime = AZStd::chrono::high_resolution_clock::now();
|
||||
const auto runTime = AZStd::chrono::milliseconds(exitTime - processInFlight.m_startTime.value());
|
||||
|
||||
// Check to see whether or not the processes has exceeded its specified flight time
|
||||
if (m_processTimeout.has_value() && runTime > m_processTimeout)
|
||||
{
|
||||
processInFlight.m_process->Terminate(ProcessTimeoutErrorCode);
|
||||
const ReturnCode returnCode = processInFlight.m_process->GetReturnCode().value();
|
||||
processInFlight.m_process.reset();
|
||||
|
||||
if (CallbackResult::Abort == m_processExitCallback(
|
||||
processId,
|
||||
ExitCondition::Timeout,
|
||||
returnCode,
|
||||
ConsumeProcessStdContent(processInFlight),
|
||||
exitTime))
|
||||
{
|
||||
// Flight time exceeded, terminate this process
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We know that at least this process is in-flight this iteration
|
||||
processesInFlight = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Queue is empty, no more processes to launch
|
||||
if (!m_processQueue.empty())
|
||||
{
|
||||
if (PopAndLaunch(processInFlight) == CallbackResult::Abort)
|
||||
{
|
||||
// Client chose to abort the scheduler
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We know from the above PopAndLaunch there is at least one process in-flight this iteration
|
||||
processesInFlight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!processesInFlight)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallbackResult ProcessScheduler::PopAndLaunch(ProcessInFlight& processInFlight)
|
||||
{
|
||||
auto processInfo = m_processQueue.front();
|
||||
m_processQueue.pop();
|
||||
const auto createTime = AZStd::chrono::high_resolution_clock::now();
|
||||
LaunchResult createResult = LaunchResult::Success;
|
||||
|
||||
try
|
||||
{
|
||||
processInFlight.m_process = LaunchProcess(AZStd::move(processInfo));
|
||||
processInFlight.m_startTime = createTime;
|
||||
}
|
||||
catch (ProcessException& e)
|
||||
{
|
||||
AZ_Warning("ProcessScheduler", false, e.what());
|
||||
createResult = LaunchResult::Failure;
|
||||
}
|
||||
|
||||
return m_processCreateCallback(processInfo.GetId(), createResult, createTime);
|
||||
}
|
||||
|
||||
void ProcessScheduler::AccumulateProcessStdContent(ProcessInFlight& processInFlight)
|
||||
{
|
||||
// Accumulate the stdout/stderr so we don't deadlock with the process waiting for the pipe to empty before finishing
|
||||
processInFlight.m_stdOutput += processInFlight.m_process->ConsumeStdOut().value_or("");
|
||||
processInFlight.m_stdError += processInFlight.m_process->ConsumeStdErr().value_or("");
|
||||
}
|
||||
|
||||
StdContent ProcessScheduler::ConsumeProcessStdContent(ProcessInFlight& processInFlight)
|
||||
{
|
||||
return
|
||||
{
|
||||
!processInFlight.m_stdOutput.empty()
|
||||
? AZStd::optional<AZStd::string>{AZStd::move(processInFlight.m_stdOutput)}
|
||||
: AZStd::nullopt,
|
||||
!processInFlight.m_stdError.empty()
|
||||
? AZStd::optional<AZStd::string>{AZStd::move(processInFlight.m_stdError)}
|
||||
: AZStd::nullopt
|
||||
};
|
||||
}
|
||||
|
||||
void ProcessScheduler::TerminateAllProcesses(ExitCondition exitStatus)
|
||||
{
|
||||
bool isCallingBackToClient = true;
|
||||
const ReturnCode returnCode = static_cast<ReturnCode>(exitStatus);
|
||||
|
||||
for (auto& processInFlight : m_processPool)
|
||||
{
|
||||
if (processInFlight.m_process)
|
||||
{
|
||||
processInFlight.m_process->Terminate(ProcessTerminateErrorCode);
|
||||
AccumulateProcessStdContent(processInFlight);
|
||||
const ProcessId processId = processInFlight.m_process->GetProcessInfo().GetId();
|
||||
|
||||
if (isCallingBackToClient)
|
||||
{
|
||||
const auto exitTime = AZStd::chrono::high_resolution_clock::now();
|
||||
if (CallbackResult::Abort == m_processExitCallback(
|
||||
processInFlight.m_process->GetProcessInfo().GetId(),
|
||||
exitStatus,
|
||||
returnCode,
|
||||
ConsumeProcessStdContent(processInFlight),
|
||||
exitTime))
|
||||
{
|
||||
// Client chose to abort the scheduler, do not make any further callbacks
|
||||
isCallingBackToClient = false;
|
||||
}
|
||||
}
|
||||
|
||||
processInFlight.m_process.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace TestImpact
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
#include <TestImpactFramework/TestImpactCallback.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Result of the attempt to launch a process.
|
||||
enum class LaunchResult : bool
|
||||
{
|
||||
Failure,
|
||||
Success
|
||||
};
|
||||
|
||||
//! The condition under which the processes exited.
|
||||
//! @note For convinience, the terminate and timeout condition values are set to the corresponding return value sent to the
|
||||
//! process.
|
||||
enum class ExitCondition : ReturnCode
|
||||
{
|
||||
Gracefull, //!< Process has exited of its own accord.
|
||||
Terminated = ProcessTerminateErrorCode, //!< The process was terminated by the client/scheduler.
|
||||
Timeout = ProcessTimeoutErrorCode //!< The process was terminated by the scheduler due to exceeding runtime limit.
|
||||
};
|
||||
|
||||
//! Callback for process launch attempt.
|
||||
//! @param processId The id of the process that attempted to launch.
|
||||
//! @param launchResult The result of the process launch attempt.
|
||||
//! @param createTime The timestamp of the process launch attempt.
|
||||
using ProcessLaunchCallback =
|
||||
AZStd::function<CallbackResult(
|
||||
ProcessId processId,
|
||||
LaunchResult launchResult,
|
||||
AZStd::chrono::high_resolution_clock::time_point createTime)>;
|
||||
|
||||
//! Callback for process exit of successfully launched process.
|
||||
//! @param processId The id of the process that attempted to launch.
|
||||
//! @param exitStatus The circumstances upon which the processes exited.
|
||||
//! @param returnCode The return code of the exited process.
|
||||
//! @param std The standard output and standard error of the process.
|
||||
//! @param createTime The timestamp of the process exit.
|
||||
using ProcessExitCallback =
|
||||
AZStd::function<CallbackResult(
|
||||
ProcessId processId,
|
||||
ExitCondition exitStatus,
|
||||
ReturnCode returnCode,
|
||||
StdContent&& std,
|
||||
AZStd::chrono::high_resolution_clock::time_point exitTime)>;
|
||||
|
||||
//! Schedules a batch of processes for launch using a round robin approach to distribute the in-flight processes over
|
||||
//! the specified number of concurrent process slots.
|
||||
class ProcessScheduler
|
||||
{
|
||||
public:
|
||||
//! Constructs the scheduler with the specified batch of processes.
|
||||
//! @param processes The batch of processes to schedule.
|
||||
//! @param processLaunchCallback The process launch callback function.
|
||||
//! @param processExitCallback The process exit callback function.
|
||||
//! @param maxConcurrentProcesses The maximum number of concurrent processes in-flight.
|
||||
//! @param processTimeout The maximum duration a process may be in-flight for before being forcefully terminated.
|
||||
//! @param scheduleTimeout The maximum duration the scheduler may run before forcefully terminating all in-flight processes.
|
||||
//! processes and abandoning any queued processes.
|
||||
ProcessScheduler(
|
||||
const AZStd::vector<ProcessInfo>& processes,
|
||||
const ProcessLaunchCallback& processLaunchCallback,
|
||||
const ProcessExitCallback& processExitCallback,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> processTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> scheduleTimeout);
|
||||
|
||||
~ProcessScheduler();
|
||||
|
||||
private:
|
||||
struct ProcessInFlight;
|
||||
|
||||
void MonitorProcesses();
|
||||
CallbackResult PopAndLaunch(ProcessInFlight& processInFlight);
|
||||
void TerminateAllProcesses(ExitCondition exitStatus);
|
||||
StdContent ConsumeProcessStdContent(ProcessInFlight& processInFlight);
|
||||
void AccumulateProcessStdContent(ProcessInFlight& processInFlight);
|
||||
|
||||
const ProcessLaunchCallback m_processCreateCallback;
|
||||
const ProcessExitCallback m_processExitCallback;
|
||||
const AZStd::optional<AZStd::chrono::milliseconds> m_processTimeout;
|
||||
const AZStd::optional<AZStd::chrono::milliseconds> m_scheduleTimeout;
|
||||
const AZStd::chrono::high_resolution_clock::time_point m_startTime;
|
||||
AZStd::vector<ProcessInFlight> m_processPool;
|
||||
AZStd::queue<ProcessInfo> m_processQueue;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Process/TestImpactProcess.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
Process::Process(const ProcessInfo& processInfo)
|
||||
: m_processInfo(processInfo)
|
||||
{
|
||||
}
|
||||
|
||||
const ProcessInfo& Process::GetProcessInfo() const
|
||||
{
|
||||
return m_processInfo;
|
||||
}
|
||||
|
||||
AZStd::optional<ReturnCode> Process::GetReturnCode() const
|
||||
{
|
||||
return m_returnCode;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Abstraction of platform-specific process.
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
explicit Process(const ProcessInfo& processInfo);
|
||||
virtual ~Process() = default;
|
||||
|
||||
//! Terminates the process with the specified return code.
|
||||
virtual void Terminate(ReturnCode returnCode) = 0;
|
||||
|
||||
//! Block the calling thread until the process exits.
|
||||
virtual void BlockUntilExit() = 0;
|
||||
|
||||
//! Returns whether or not the process is still running.
|
||||
virtual bool IsRunning() const = 0;
|
||||
|
||||
//! Returns the process info associated with this process.
|
||||
const ProcessInfo& GetProcessInfo() const;
|
||||
|
||||
//! Returns the return code of the exited process.
|
||||
//! Will be empty if the process is still running or was not successfully launched.
|
||||
AZStd::optional<ReturnCode> GetReturnCode() const;
|
||||
|
||||
//! Flushes the internal buffer and returns the process's buffered standard output.
|
||||
//! Subsequent calls will keep returning data so long as the process is producing output.
|
||||
//! Will return nullopt if no output routing or no output produced.
|
||||
virtual AZStd::optional<AZStd::string> ConsumeStdOut() = 0;
|
||||
|
||||
//! Flushes the internal buffer and returns the process's buffered standard error.
|
||||
//! Subsequent calls will keep returning data so long as the process is producing errors.
|
||||
//! Will return nullopt if no error routing or no errors produced.
|
||||
virtual AZStd::optional<AZStd::string> ConsumeStdErr() = 0;
|
||||
|
||||
protected:
|
||||
//! The information used to launch the process.
|
||||
ProcessInfo m_processInfo;
|
||||
|
||||
//! The return code of a successfully launched process (otherwise is empty)
|
||||
AZStd::optional<ReturnCode> m_returnCode;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for processes and process-related operations.
|
||||
class ProcessException
|
||||
: public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
ProcessInfo::ProcessInfo(ProcessId id, const AZ::IO::Path& processPath, const AZStd::string& startupArgs)
|
||||
: m_id(id)
|
||||
, m_parentHasStdOutput(false)
|
||||
, m_parentHasStdErr(false)
|
||||
, m_processPath(processPath)
|
||||
, m_startupArgs(startupArgs)
|
||||
{
|
||||
AZ_TestImpact_Eval(processPath.String().length() > 0, ProcessException, "Process path cannot be empty");
|
||||
}
|
||||
|
||||
ProcessInfo::ProcessInfo(
|
||||
ProcessId id,
|
||||
StdOutputRouting stdOut,
|
||||
StdErrorRouting stdErr,
|
||||
const AZ::IO::Path& processPath,
|
||||
const AZStd::string& startupArgs)
|
||||
: m_id(id)
|
||||
, m_processPath(processPath)
|
||||
, m_startupArgs(startupArgs)
|
||||
, m_parentHasStdOutput(stdOut == StdOutputRouting::ToParent ? true : false)
|
||||
, m_parentHasStdErr(stdErr == StdErrorRouting::ToParent ? true : false)
|
||||
{
|
||||
AZ_TestImpact_Eval(processPath.String().length() > 0, ProcessException, "Process path cannot be empty");
|
||||
}
|
||||
|
||||
ProcessId ProcessInfo::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
const AZ::IO::Path& ProcessInfo::GetProcessPath() const
|
||||
{
|
||||
return m_processPath;
|
||||
}
|
||||
|
||||
const AZStd::string& ProcessInfo::GetStartupArgs() const
|
||||
{
|
||||
return m_startupArgs;
|
||||
}
|
||||
|
||||
bool ProcessInfo::ParentHasStdOutput() const
|
||||
{
|
||||
return m_parentHasStdOutput;
|
||||
}
|
||||
|
||||
bool ProcessInfo::ParentHasStdError() const
|
||||
{
|
||||
return m_parentHasStdErr;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Identifier to distinguish between processes.
|
||||
using ProcessId = size_t;
|
||||
|
||||
//! Return code of successfully launched process.
|
||||
using ReturnCode = int;
|
||||
|
||||
//! Error code for processes that are forcefully terminated whilst in-flight by the client.
|
||||
inline constexpr const ReturnCode ProcessTerminateErrorCode = 0xF10BAD;
|
||||
|
||||
//! Error code for processes that are forcefully terminated whilst in-flight by the scheduler due to timing out.
|
||||
inline constexpr const ReturnCode ProcessTimeoutErrorCode = 0xBADF10;
|
||||
|
||||
//! Specifier for how the process's standard out willt be routed
|
||||
enum class StdOutputRouting
|
||||
{
|
||||
ToParent,
|
||||
None
|
||||
};
|
||||
|
||||
enum class StdErrorRouting
|
||||
{
|
||||
ToParent,
|
||||
None
|
||||
};
|
||||
|
||||
//! Container for process standard output and standard error.
|
||||
struct StdContent
|
||||
{
|
||||
AZStd::optional<AZStd::string> m_out;
|
||||
AZStd::optional<AZStd::string> m_err;
|
||||
};
|
||||
|
||||
//! Information about a process the arguments used to launch it.
|
||||
class ProcessInfo
|
||||
{
|
||||
public:
|
||||
//! Provides the information required to launch a process.
|
||||
//! @param processId Client-supplied id to diffrentiate between processes.
|
||||
//! @param stdOut Routing of process standard output.
|
||||
//! @param stdErr Routing of process standard error.
|
||||
//! @param processPath Path to executable binary to launch.
|
||||
//! @param startupArgs Arguments to launch the process with.
|
||||
ProcessInfo(
|
||||
ProcessId processId,
|
||||
StdOutputRouting stdOut,
|
||||
StdErrorRouting stdErr,
|
||||
const AZ::IO::Path& processPath,
|
||||
const AZStd::string& startupArgs = "");
|
||||
ProcessInfo(ProcessId processId, const AZ::IO::Path& processPath, const AZStd::string& startupArgs = "");
|
||||
|
||||
//! Returns the identifier of this process.
|
||||
ProcessId GetId() const;
|
||||
|
||||
//! Returns whether or not stdoutput is routed to the parent process.
|
||||
bool ParentHasStdOutput() const;
|
||||
|
||||
//! Returns whether or not stderror is routed to the parent process.
|
||||
bool ParentHasStdError() const;
|
||||
|
||||
// Returns the path to the process binary.
|
||||
const AZ::IO::Path& GetProcessPath() const;
|
||||
|
||||
//! Returns the command line arguments used to launch the process.
|
||||
const AZStd::string& GetStartupArgs() const;
|
||||
|
||||
private:
|
||||
const ProcessId m_id;
|
||||
const bool m_parentHasStdOutput;
|
||||
const bool m_parentHasStdErr;
|
||||
const AZ::IO::Path m_processPath;
|
||||
const AZStd::string m_startupArgs;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
class Process;
|
||||
class ProcessInfo;
|
||||
|
||||
//! Attempts to launch a process with the provided command line arguments.
|
||||
//! @param processInfo The path and command line arguments to launch the process with.
|
||||
AZStd::unique_ptr<Process> LaunchProcess(const ProcessInfo& processInfo);
|
||||
} // namespace TestImpact
|
||||
Reference in New Issue
Block a user