/// <summary> /// Validates for deleting scenario /// </summary> /// <param name="run"></param> /// <param name="scenario"></param> public static void ValidateForDeleteScenario(RunScenario scenario) { if (scenario.IsScheduledOrRunning) { throw new Exception("Cannot delete a scenario that is running or scheduled to run"); } }
internal static PdfPTable GetBodyTable(this RunScenario scenario, int testRun) { var table = new PdfPTable(new[] { 0.25f, 0.75f }); //two cols 1/3, 2/3 var bodyProps = scenario.GetBodyProperties().ToList(); bodyProps.Insert(1, new KeyValuePair <string, object>("Tet Run #", testRun)); foreach (var kv in bodyProps) { table.AddCell(kv.Key.GetNormalCell()); var value = kv.Value; if (kv.Key.Equals("RunTime")) { value += " Sec"; } if (kv.Key.Equals("Headers")) { table.AddCell(GetSummaryTable((IEnumerable <KeyValuePair <string, object> >)value, Rectangle.LISTITEM, 0.25f, 0.75f)); } else { table.AddCell(value.GetNormalCell(font: null, hasBackground: kv.Key.Equals("Name"))); } } return(table); }
public Task Execute(Run run, RunScenario scenario, IReadOnlyCollection <AutoBookInstanceConfiguration> autoBookInstanceConfigurationsForRun, double autoBookRequiredStorageGB, ConcurrentBag <RunInstance> runInstances, ConcurrentDictionary <Guid, ScenarioStatuses> newScenarioStatuses, ConcurrentDictionary <Guid, bool> scenarioSyncStatuses, bool autoDistributed) { return(Task.Run(() => { _semaphore.Wait(); try { using var scope = _lifetimeScope.BeginLifetimeScope(); var scenarioTask = scope.Resolve <RunScenarioTask>(); scenarioTask.Execute(run, scenario, autoBookInstanceConfigurationsForRun, autoBookRequiredStorageGB, runInstances, newScenarioStatuses, scenarioSyncStatuses, autoDistributed); } finally { _semaphore.Release(); } })); }
public static void SetException(this TreeNode node, Exception ex) { var ni = node.Tag as NodeInfo; if (ni.Type == NodeType.Folder) { return; } ni.Running = false; var sc = new RunScenario(); sc.WriteException(ex); sc.Name = "Runtime Exception"; ni.Steps.Add(sc); Int32 image = NodeInfo.IMAGE_FAIL; node.SetImage(image); }
public void RunCompleted(Run run, RunScenario scenario, bool success, HTTPNotificationSettings httpNotificationSettings) { if (httpNotificationSettings.Enabled) { // Set content string contentString = httpNotificationSettings.MethodSettings.ContentTemplate; if (!String.IsNullOrEmpty(contentString)) { contentString = contentString.Replace("{runId}", run.Id.ToString()); contentString = contentString.Replace("{scenarioId}", scenario.Id.ToString()); } // Process headers string contentType = ""; Dictionary <string, string> headers = new Dictionary <string, string>(); foreach (string header in httpNotificationSettings.MethodSettings.Headers.Keys) { switch (header) { case "Content-Type": // Should not be passed in headers collection contentType = httpNotificationSettings.MethodSettings.Headers[header]; break; default: headers.Add(header, httpNotificationSettings.MethodSettings.Headers[header]); break; } } // Set URL string url = httpNotificationSettings.MethodSettings.URL; url = url.Replace("{runId}", run.Id.ToString()); url = url.Replace("{scenarioId}", scenario.Id.ToString()); HttpWebRequest webRequest = CreateHttpWebRequest(url, httpNotificationSettings.MethodSettings.Method, headers, _defaultTimeout, String.IsNullOrEmpty(contentString) ? "" : contentType, String.IsNullOrEmpty(contentString) ? null : System.Text.Encoding.UTF8.GetBytes(contentString)); HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); ThrowExceptionIfNotSuccess(webResponse, httpNotificationSettings.SucccessStatusCodes); } }
/// <summary> /// Returns PassModels for RunScenario /// </summary> private static List <PassModel> GetPassModels( RunScenario runScenario, IList <Scenario> scenarios, IList <Pass> passes, IMapper mapper) { var passModels = new List <PassModel>(); var scenario = scenarios.FirstOrDefault(s => s.Id == runScenario.Id); if (scenario?.Passes == null || !scenario.Passes.Any()) { return(passModels); } foreach (var passReference in scenario.Passes) { var pass = passes.FirstOrDefault(p => p.Id == passReference.Id); if (pass != null) { passModels.Add(mapper.Map <PassModel>(pass)); } } return(passModels); }
public void Execute( Run run, RunScenario scenario, IReadOnlyCollection <AutoBookInstanceConfiguration> autoBookInstanceConfigurationsForRun, double autoBookRequiredStorageGB, ConcurrentBag <RunInstance> runInstances, ConcurrentDictionary <Guid, ScenarioStatuses> newScenarioStatuses, ConcurrentDictionary <Guid, bool> scenarioSyncStatuses, bool autoDistributed) { AutoBookDomainObject autoBook = null; IAutoBook autoBookInterface = null; bool runStarted = false; RaiseInfo($"Begin Execute for ScenarioID: { scenario.Id}"); try { AutoBookInstanceConfiguration runAutoBookInstanceConfiguration = null; if (autoDistributed) { RaiseInfo($"AutoDistributed - RunScenarioTask Execute Starting ScenarioID ={ scenario.Id}, RunID ={ run.Id}"); //create instance for scenario RunInstance runInstance = _runInstanceCreator.Create(run.Id, scenario.Id); RaiseInfo($"AutoDistributed - about to enter: {nameof(runInstance.UploadInputFilesAndCreateAutoBookRequest)}"); runInstance.UploadInputFilesAndCreateAutoBookRequest(autoBookInstanceConfigurationsForRun, autoBookRequiredStorageGB); RaiseInfo($"AutoDistributed - returned from: {nameof(runInstance.UploadInputFilesAndCreateAutoBookRequest)}"); // Flag run as started runStarted = true; runInstances.Add(runInstance); _ = newScenarioStatuses.TryRemove(scenario.Id, out _); // Don't update scenario status at the end scenarioSyncStatuses[scenario.Id] = false; RaiseInfo($"AutoDistributed - RunScenarioTask Execute Started ScenarioID ={ scenario.Id}, RunID ={ run.Id}"); } else { try { using (MachineLock.Create("xggameplan.AWSAutoBooks.GetFreeAutoBook", new TimeSpan(0, 10, 0))) { foreach (var autoBookInstanceConfiguration in autoBookInstanceConfigurationsForRun) { autoBook = _autoBooks.GetFirstAdequateIdleAutoBook(autoBookInstanceConfiguration, autoBookRequiredStorageGB, true); if (autoBook != null) // Got free AutoBook { RaiseInfo($"Got Free AutoBook: {autoBook.Id} ConfigurationId: {autoBook.InstanceConfigurationId}"); runAutoBookInstanceConfiguration = autoBookInstanceConfiguration; break; } } } } catch (MachineLockTimeoutException) { RaiseInfo($"MachineLockTimeoutException in xggameplan.AWSAutoBooks.GetFreeAutoBook"); } // Get autobook interface autoBookInterface = (autoBook == null) ? null : _autoBooks.GetInterface(autoBook); // Get free AutoBook instance, will be locked so that it can't be used elsewhere if (autoBook != null) // Free AutoBook - start run { RaiseInfo($"Free Autobook - Starting ScenarioID ={ scenario.Id}, AutoBookID ={autoBook?.Id}, RunID ={ run.Id}, Instance Configuration = { runAutoBookInstanceConfiguration.Description }"); // Start run, exception will cause cleanup below RunInstance runInstance = _runInstanceCreator.Create(run.Id, scenario.Id); runInstance.UploadInputFilesStartAutoBookRun(autoBookInterface, autoBook); // Flag run as started runStarted = true; runInstances.Add(runInstance); _ = newScenarioStatuses.TryRemove(scenario.Id, out _); // Don't update scenario status at the end scenarioSyncStatuses[scenario.Id] = false; RaiseInfo($"Started ScenarioID ={ scenario.Id}, AutoBookID ={ autoBook?.Id}, RunID ={ run.Id}, Instance Configuration = { runAutoBookInstanceConfiguration?.Description }"); } else // No free AutoBook, awaiting for provisioning { _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"No free AutoBook, awaiting for provisioning, waiting for existing AutoBooks to be Idle (RunID={run.Id}, ScenarioID={scenario.Id})")); // Update scenario so that it can be retried later when an AutoBook becomes idle RunManager.UpdateScenarioStatuses(_repositoryFactory, _auditEventRepository, run.Id, new List <Guid> { scenario.Id }, new List <ScenarioStatuses> { ScenarioStatuses.Scheduled }, new List <DateTime?> { null }); _ = newScenarioStatuses.TryRemove(scenario.Id, out _); // Don't update scenario status at the end scenarioSyncStatuses[scenario.Id] = false; } } } catch (System.Exception exception) { // Log exception but don't throw it. We want to try and start other scenarios _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, $"Error starting scenario (RunID={run.Id}, ScenarioID={scenario.Id}, AutoBookID={(autoBook == null ? "Unknown" : autoBook.Id)})", exception)); } finally { // If we locked a free AutoBook instance but didn't start the scenario then reset to free, unlocks it. if (!runStarted && autoBook != null) { autoBookInterface.ResetFree(); } } }
private static List <CampaignPassPriorityModel> MapToCampaignPassPriorityModels( RunScenario runScenario, IList <Scenario> scenarios, IMapper mapper) { return(MapToCampaignPassPriorityModels(scenarios.FirstOrDefault(s => s.Id == runScenario.Id), mapper)); }
/// <summary> /// Check scenario results data. E.g. KPI data. /// </summary> /// <param name="run"></param> /// <param name="salesAreas"></param> /// <param name="scenario"></param> /// <returns></returns> private List <SystemTestResult> CheckScenarioResultsOutputData(Run run, List <SalesArea> salesAreas, RunScenario scenario) { List <SystemTestResult> results = new List <SystemTestResult>(); try { if (scenario.Status == ScenarioStatuses.CompletedSuccess) { using (var scope = _repositoryFactory.BeginRepositoryScope()) { var scenarioResultRepository = scope.CreateRepository <IScenarioResultRepository>(); var scenarioResult = scenarioResultRepository.Find(scenario.Id); if (scenarioResult == null) // ScenarioResult missing { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Error, _category, string.Format("Run {0} (Run ID {1}) generated no Scenario Result document for scenario {2}. There will be no KPI data. There was a problem processing the output files.", run.Description, run.Id, scenario.Id), "")); } else if (scenarioResult.Metrics == null || !scenarioResult.Metrics.Any()) // No KPI data { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Error, _category, string.Format("Run {0} (Run ID {1}) generated no KPI for scenario {2}. There was a problem processing the output files.", run.Description, run.Id, scenario.Id), "")); } else { // Check individual metrics int countZeroMetrics = 0; foreach (var kpi in scenarioResult.Metrics) { if (kpi.Value == 0) { countZeroMetrics++; } } if (countZeroMetrics == scenarioResult.Metrics.Count) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Error, _category, string.Format("Run {0} (Run ID {1}) generated KPI for scenario {2} but all of the values were zero. There was a problem processing the output files.", run.Description, run.Id, scenario.Id), "")); } } } if (!results.Where(r => r.ResultType == SystemTestResult.ResultTypes.Error).Any()) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Information, _category, "Scenario Results out data OK", "")); } } } catch (System.Exception exception) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Information, _category, string.Format("Error checking Scenario Results output data: {0}", exception.Message), "")); } return(results); }
/// <summary> /// Checks for recommendations. If recommendations are not present then it may indicate a problem. /// </summary> /// <param name="run"></param> /// <param name="salesAreas"></param> /// <param name="scenario"></param> /// <returns></returns> private List <SystemTestResult> CheckRecommendationOutputData(Run run, List <SalesArea> salesAreas, RunScenario scenario) { List <SystemTestResult> results = new List <SystemTestResult>(); try { if (scenario.Status == ScenarioStatuses.CompletedSuccess) { // Check if recommendations are missing List <string> processors = new List <string>() { (run.Smooth ? "smooth" : ""), (run.Optimisation ? "autobook" : ""), (run.ISR ? "isr" : ""), (run.RightSizer ? "rzr" : "") }; processors.RemoveAll(p => String.IsNullOrEmpty(p)); Dictionary <string, string> processorDescriptions = new Dictionary <string, string>() { { "smooth", "Smooth" }, { "autobook", "Optimiser" }, { "isr", "ISR" }, { "rzr", "Right Sizer" } }; if (processors.Any()) { using (var scope = _repositoryFactory.BeginRepositoryScope()) { var recommendationRepository = scope.CreateRepository <IRecommendationRepository>(); // Get recommendations var recommendations = recommendationRepository.GetByScenarioId(scenario.Id); // For each processor then check if any recommendations foreach (string processor in processors) { var processorRecommendations = recommendations.Where(r => r.Processor == processor); if (!processorRecommendations.Any()) { if (processor == "smooth") // Smooth recommendations related to run, only set for first scenario { if (scenario == run.Scenarios.First()) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Error, _category, string.Format("Run {0} (Run ID {1}) generated no {2} recommendations for scenario {3}.", run.Description, run.Id, processorDescriptions[processor], scenario.Id), "")); } } else { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Error, _category, string.Format("Run {0} (Run ID {1}) generated no {2} recommendations for scenario {3}.", run.Description, run.Id, processorDescriptions[processor], scenario.Id), "")); } } } } } if (!results.Where(r => r.ResultType == SystemTestResult.ResultTypes.Error).Any()) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Information, _category, "Recommendations output data OK", "")); } } } catch (System.Exception exception) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Information, _category, string.Format("Error checking Recommendations output data: {0}", exception.Message), "")); } return(results); }
/// <summary> /// Checks for failures output data. /// </summary> /// <param name="run"></param> /// <param name="salesAreas"></param> /// <param name="scenario"></param> /// <returns></returns> private List <SystemTestResult> CheckFailuresOutputData(Run run, List <SalesArea> salesAreas, RunScenario scenario) { List <SystemTestResult> results = new List <SystemTestResult>(); try { if (scenario.Status == ScenarioStatuses.CompletedSuccess) { using (var scope = _repositoryFactory.BeginRepositoryScope()) { var failuresRepository = scope.CreateRepository <IFailuresRepository>(); var failures = failuresRepository.Get(scenario.Id); if (failures == null || failures.Items == null || failures.Items.Count == 0) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Error, _category, string.Format("Run {0} (RunID {1}) has a scenario (Scenario ID {2}) that generated no Optimiser failures.", run.Description, run.Id, scenario.Id), "")); } } if (!results.Where(r => r.ResultType == SystemTestResult.ResultTypes.Error).Any()) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Information, _category, "Failures output data OK", "")); } } } catch (System.Exception exception) { results.Add(new SystemTestResult(SystemTestResult.ResultTypes.Information, _category, string.Format("Error checking Failures output data: {0}", exception.Message), "")); } return(results); }
/// <summary> /// Creates template run, all run options selected, single sales area, default scenario. The template run can be manually modified /// later. /// </summary> /// <param name="runId"></param> private void CreateRunForTemplate(Guid runId) { using (var scope = _repositoryFactory.BeginRepositoryScope()) { var repositories = scope.CreateRepositories( typeof(IRunRepository), typeof(ISalesAreaRepository), typeof(ITenantSettingsRepository) ); var runRepository = repositories.Get <IRunRepository>(); var tenantSettingsRepository = repositories.Get <ITenantSettingsRepository>(); var salesAreaRepository = repositories.Get <ISalesAreaRepository>(); // Get sales areas var salesAreas = salesAreaRepository.GetAll(); // Get tenant settings with default scenario var tenantSettings = tenantSettingsRepository.Get(); // Create run, single sales area Run run = new Run() { Id = runId, Description = "Template", CreatedDateTime = DateTime.UtcNow, //StartDateTime = DateTime.UtcNow.Date, //EndDateTime = DateTime.UtcNow.Date.AddDays(48), IsLocked = false, Optimisation = true, Smooth = true, ISR = true, RightSizer = true, Real = false, Author = new AuthorModel() { Id = 1, Name = "User" } }; run.SalesAreaPriorities.Add(new SalesAreaPriority() { SalesArea = salesAreas.OrderBy(sa => sa.Name).First().Name, Priority = SalesAreaPriorityType.Priority3 }); // Add scenario var runScenario = new RunScenario() { Id = tenantSettings.DefaultScenarioId }; run.Scenarios.Add(runScenario); //Scenario scenario = (Scenario)tenantSettings.DefaultScenario.Clone(); run.Scenarios.ForEach(s => s.ResetToPendingStatus()); //run.Scenarios.Add(scenario); // Set new IDs IdUpdater.SetIds(run, _identityGeneratorResolver); // Save run runRepository.Add(run); runRepository.SaveChanges(); } }
/// <summary> /// Handles run scenario completed /// </summary> /// <param name="run"></param> /// <param name="scenario"></param> /// <param name="success"></param> public void Notify(Run run, RunScenario scenario, bool success) { TenantSettings tenantSettings = _tenantSettingsRepository.Get(); bool notificationsConfigured = false; // Get run scenario event settings if (tenantSettings.RunEventSettings != null) { RunEventSettings runEventSettings = tenantSettings.RunEventSettings.Where(item => item.EventType == RunEvents.RunScenarioCompleted).FirstOrDefault(); if (runEventSettings != null) { var exceptions = new List <Exception>(); try { // Check HTTP notification INotification <HTTPNotificationSettings> httpNotification = _notifications?.GetNotification <HTTPNotificationSettings>(); if (runEventSettings.HTTP != null && httpNotification != null && runEventSettings.HTTP.Enabled) { notificationsConfigured = true; try { _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForGameplanPipelineStart(0, 0, PipelineEventIDs.STARTED_NOTIFYING_MULE_SOFT_API, run.Id, scenario.Id, null, string.Format("Generating HTTP notification for run completed (RunID={0}, ScenarioID={1}, Success={2})", run.Id, scenario.Id, success))); _pipelineAuditEventRepository.Add(PipelineEventHelper.CreatePipelineAuditEvent(AuditEventTypes.GamePlanRun, PipelineEventIDs.STARTED_NOTIFYING_MULE_SOFT_API, run.Id, scenario.Id, null)); httpNotification.RunCompleted(run, scenario, success, runEventSettings.HTTP); _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForGameplanPipelineEnd(0, 0, PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, scenario.Id, null, string.Format("Generated HTTP notification for run completed (RunID={0}, ScenarioID={1}, Success={2})", run.Id, scenario.Id, success), null, null)); _pipelineAuditEventRepository.Add(PipelineEventHelper.CreatePipelineAuditEvent(AuditEventTypes.GamePlanRun, PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, scenario.Id, null)); } catch (System.Exception exception) { _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForGameplanPipelineEnd(0, 0, PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, scenario.Id, null, string.Format("Failed to generate HTTP notification for run completed (RunID={0}, ScenarioID={1}, Success={2})", run.Id, scenario.Id, success), exception.Message, exception)); _pipelineAuditEventRepository.Add(PipelineEventHelper.CreatePipelineAuditEvent(AuditEventTypes.GamePlanRun, PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, scenario.Id, exception.Message)); throw; } finally { _pipelineAuditEventRepository.SaveChanges(); } } } catch (System.Exception exception) { exceptions.Add(exception); } if (exceptions.Count == 1) { throw exceptions[0]; } else if (exceptions.Count > 0) { throw new AggregateException(exceptions); } } } // Log warning if notifications not enabled so that there's no dispute over why they weren't generated if (!notificationsConfigured) { _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"Not generating notification for run completed because notifications are not configured or enabled (RunID={run.Id}, ScenarioID={scenario.Id}, Success={success})")); } }
static void Main(string[] args) { var log = new LoggerConfiguration() .WriteTo.Console() .CreateLogger(); Serilog.Log.Logger = log; Serilog.Log.Information("Hello, Serilog!"); Console.WriteLine("Type any key to proceed. Example of piping, but the piping doesn't return functions"); Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Type Q to quit."); Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Type T For Test."); Console.WriteLine("Type any other key for Run."); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(); var input = Console.ReadLine(); while (input.Trim().ToUpper() != "Q") { if (input.Trim().ToUpper() == "T") { Console.ForegroundColor = ConsoleColor.Magenta; Console.WriteLine("Type 1 for partial Test on SaveBasket"); Console.WriteLine("Type 2 for partial Test on reserveProduct"); Console.WriteLine("Type 3 for Full Test on scenario"); Console.WriteLine("Type any other key for exiting Test."); var inputTest = Console.ReadLine().Trim().ToUpper(); while (inputTest == "1" || inputTest == "2" || inputTest == "3") { Piping.Example.ExampleTest.Test.TestMe(int.Parse(inputTest)); Console.ForegroundColor = ConsoleColor.Magenta; Console.WriteLine("Type 1 for partial Test on SaveBasket"); Console.WriteLine("Type 2 for partial Test on reserveProduct"); Console.WriteLine("Type 3 for Full Test on scenario"); Console.WriteLine("Type any other key for exiting Test."); inputTest = Console.ReadLine().Trim().ToUpper(); } Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Type Q to quit."); Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Type T For Test."); Console.WriteLine("Type any other key for Run."); } else { RunScenario.Run(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Type Q to quit."); Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Type T For Test."); Console.WriteLine("Type any other key for Run."); } input = Console.ReadLine(); } }
private static void SetIds(RunScenario scenario) { scenario.Id = (scenario.Id == Guid.Empty) ? Guid.NewGuid() : scenario.Id; }
/// <summary> /// Converts run from V1 format to new format /// </summary> /// <param name="runOld"></param> /// <param name="runs"></param> /// <param name="scenarios"></param> /// <param name="passes"></param> private void ConvertRun(RunV1 runOld, List <Run> runs, List <Scenario> scenarios, List <Pass> passes) { Run run = new Run() { Author = runOld.Author, Campaigns = runOld.Campaigns, CreatedDateTime = runOld.CreatedDateTime, CustomId = runOld.CustomId, Description = runOld.Description, EndDate = runOld.EndDateTime, ExecuteStartedDateTime = runOld.ExecuteStartedDateTime, Id = runOld.Id, IsLocked = runOld.IsLocked, ISR = runOld.ISR, LastModifiedDateTime = runOld.LastModifiedDateTime, Optimisation = runOld.Optimisation, Real = runOld.Real, RightSizer = runOld.RightSizer, //SalesAreas = runOld.SalesAreas, //commented out for compiling as new run model for xggp-752 does not contain SalesAreas (replaced with SalesAreaPriorities) Smooth = runOld.Smooth, StartDate = runOld.StartDateTime }; // Convert scenarios foreach (var scenarioOld in runOld.Scenarios) { RunScenario runScenario = new RunScenario() { Id = scenarioOld.Id, CompletedDateTime = scenarioOld.CompletedDateTime, Progress = scenarioOld.Progress, StartedDateTime = scenarioOld.StartedDateTime, Status = scenarioOld.Status }; Scenario scenario = new Scenario() { CustomId = scenarioOld.CustomId, Id = scenarioOld.Id, Name = string.Format("Scenario {0}", scenarioOld.CustomId), // Default Passes = new List <PassReference>() }; run.Scenarios.Add(runScenario); // Convert passes foreach (var passOld in scenarioOld.Passes) { PassReference passReference = new PassReference() { Id = passOld.Id }; scenario.Passes.Add(passReference); Pass pass = (Pass)passOld.Clone(); pass.Name = string.Format("Pass {0}", pass.Id); // Default passes.Add(pass); } scenarios.Add(scenario); } runs.Add(run); }