public async void BubblesCancellation() { try { //Arrange Setup(); var bingTask = new TaskInstance() { Enabled = true, Name = "Bing", Version = "0.1.2", Id = Guid.NewGuid() }; var pingTask = new TaskInstance() { Enabled = true, Name = "Ping", Version = "0.1.1", Id = Guid.NewGuid() }; var bingVersion = new TaskVersion(bingTask.Version); var pingVersion = new TaskVersion(pingTask.Version); _jobServer .Setup(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), _ec.Object.CancellationToken)) .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => { _ecTokenSource.Cancel(); return(Task.FromResult <Stream>(GetZipStream())); }); var tasks = new List <TaskInstance>(new TaskInstance[] { bingTask, pingTask }); //Act //should initiate a download with a mocked IJobServer, which sets a cancellation token and //download task is expected to be in cancelled state Task downloadTask = _taskManager.DownloadAsync(_ec.Object, tasks); Task[] taskToWait = { downloadTask, Task.Delay(2000) }; //wait for the task to be cancelled to exit await Task.WhenAny(taskToWait); //Assert //verify task completed in less than 2sec and it is in cancelled state Assert.True(downloadTask.IsCompleted, $"{nameof(_taskManager.DownloadAsync)} timed out."); Assert.True(!downloadTask.IsFaulted, downloadTask.Exception?.ToString()); Assert.True(downloadTask.IsCanceled); //check if the task.json was not downloaded for ping and bing tasks Assert.Equal( 0, Directory.GetFiles(IOUtil.GetTasksPath(_hc), "*", SearchOption.AllDirectories).Length); //assert download was invoked only once, because the first task cancelled the second task download _jobServer .Verify(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), _ec.Object.CancellationToken), Times.Once()); } finally { Teardown(); } }
public int TaskSetVersion(TaskVersion model) { using (RLib.DB.DbConn dbconn = Pub.GetConn()) { var task = taskdal.GetDetail(dbconn, model.TaskId); if (task == null) { throw new MException("没有任务!"); } dbconn.BeginTransaction(); try { model.TaskId = task.TaskId; var versions = taskdal.AddVersion(dbconn, new Model.TaskVersion() { CreateTime = DateTime.Now, FilePath = model.FilePath ?? "", FileSize = model.FileSize, Remark = model.Remark ?? "", TaskId = model.TaskId, VersionId = 0, VersionNO = DateTime.Now.ToString("yyyyMMddHHmmssfff" + "-" + model.TaskId), Vstate = 0 }); taskdal.SetVersion(dbconn, task.TaskId, versions.VersionId); dbconn.Commit(); return(model.TaskId); } catch (Exception ex) { dbconn.Rollback(); throw; } } }
public async void RetryStreamException() { try { // Arrange. using (var tokenSource = new CancellationTokenSource()) using (var _hc = Setup(tokenSource)) { var pingTask = new Pipelines.TaskStep() { Enabled = true, Reference = new Pipelines.TaskStepDefinitionReference() { Name = "Ping", Version = "0.1.1", Id = Guid.NewGuid() } }; var pingVersion = new TaskVersion(pingTask.Reference.Version); Exception expectedException = new System.Net.Http.HttpRequestException("simulated network error"); _taskServer .Setup(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), It.IsAny <CancellationToken>())) .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => { return(Task.FromResult <Stream>(new ExceptionStream())); }); var tasks = new List <Pipelines.TaskStep>(new Pipelines.TaskStep[] { pingTask }); //Act Exception actualException = null; try { await _taskManager.DownloadAsync(_ec.Object, tasks); } catch (Exception ex) { actualException = ex; } //Assert //verify task completed in less than 2sec and it is in failed state state Assert.Equal("NotImplementedException", actualException.GetType().Name); //assert download was invoked 3 times, because we retry on task download _taskServer .Verify(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), It.IsAny <CancellationToken>()), Times.Exactly(3)); //see if the task.json was not downloaded Assert.Equal( 0, Directory.GetFiles(_hc.GetDirectory(WellKnownDirectory.Tasks), "*", SearchOption.AllDirectories).Length); } } finally { Teardown(); } }
public void GetTasks() { // Arrange. const string taskName = "task name"; var task = new Task(taskName); var date = new DateTime(); var taskVersion = new TaskVersion(date); var versions = new SortedDictionary <DateTime, TaskVersion>(); versions.Add(date, taskVersion); var taskVersions = new Dictionary < string, SortedDictionary <DateTime, TaskVersion> >(); taskVersions.Add(taskName, versions); var store = MockRepository.GeneratePartialMock <MemoryTaskStore>(); store.Expect(s => s.TaskVersions).Return(taskVersions); store.Expect(s => s.New(taskName, versions)).Return(task); // Act. var res = store.Tasks.ToList(); // Assert. store.VerifyAllExpectations(); Assert.AreEqual(1, res.Count()); Assert.AreEqual(task, res.First()); }
/// <summary> /// 批量上传版本变指定为当前版本 /// </summary> /// <param name="model"></param> /// <param name="tag"></param> public void BatchTaskVersion(TaskVersion model, int tag) { using (RLib.DB.DbConn dbconn = Pub.GetConn()) { var tasks = taskdal.GetAllTask(dbconn, tag); if (tasks.Count == 0) { throw new MException("没有任务!"); } dbconn.BeginTransaction(); try { foreach (var a in tasks) { model.TaskId = a.TaskId; var versions = taskdal.AddVersion(dbconn, model); taskdal.SetVersion(dbconn, a.TaskId, versions.VersionId); } dbconn.Commit(); } catch (Exception ex) { dbconn.Rollback(); throw; } } }
public async void BubblesCancellation() { try { //Arrange Setup(); var bingTask = new TaskInstance() { Enabled = true, Name = "Bing", Version = "0.1.2", Id = Guid.NewGuid() }; var pingTask = new TaskInstance() { Enabled = true, Name = "Ping", Version = "0.1.1", Id = Guid.NewGuid() }; var bingVersion = new TaskVersion(bingTask.Version); var pingVersion = new TaskVersion(pingTask.Version); _taskServer .Setup(x => x.GetTaskContentZipAsync(It.IsAny<Guid>(), It.IsAny<TaskVersion>(), _ec.Object.CancellationToken)) .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => { _ecTokenSource.Cancel(); return Task.FromResult<Stream>(GetZipStream()); }); var tasks = new List<TaskInstance>(new TaskInstance[] { bingTask, pingTask }); //Act //should initiate a download with a mocked IJobServer, which sets a cancellation token and //download task is expected to be in cancelled state Task downloadTask = _taskManager.DownloadAsync(_ec.Object, tasks); Task[] taskToWait = { downloadTask, Task.Delay(2000) }; //wait for the task to be cancelled to exit await Task.WhenAny(taskToWait); //Assert //verify task completed in less than 2sec and it is in cancelled state Assert.True(downloadTask.IsCompleted, $"{nameof(_taskManager.DownloadAsync)} timed out."); Assert.True(!downloadTask.IsFaulted, downloadTask.Exception?.ToString()); Assert.True(downloadTask.IsCanceled); //check if the task.json was not downloaded for ping and bing tasks Assert.Equal( 0, Directory.GetFiles(IOUtil.GetTasksPath(_hc), "*", SearchOption.AllDirectories).Length); //assert download was invoked only once, because the first task cancelled the second task download _taskServer .Verify(x => x.GetTaskContentZipAsync(It.IsAny<Guid>(), It.IsAny<TaskVersion>(), _ec.Object.CancellationToken), Times.Once()); } finally { Teardown(); } }
public void SaveNoTaskVersionException() { // Arrange. const string taskName = "name"; TaskVersion version = null; var store = new MemoryTaskStore(); // Act and assert. store.Save(taskName, version); }
public void SaveEmptyTaskNameException() { // Arrange. const string taskName = " "; var version = new TaskVersion(new DateTime()); var store = new MemoryTaskStore(); // Act and assert. store.Save(taskName, version); }
public void CtorSavesDateRef() { // Arrange. var date = new DateTime(2000, 1, 1); // Act. var version = new TaskVersion(date); // Assert. Assert.AreEqual(date, version.Date); }
public TaskVersion AddTaskVersion(TaskVersion model) { if (model.TaskId <= 0) { throw new MException("任务ID不能为空!"); } using (RLib.DB.DbConn dbconn = Pub.GetConn()) { var versions = taskdal.AddVersion(dbconn, model); return(versions); } }
public async void BubblesNetworkException() { try { // Arrange. Setup(); var pingTask = new Pipelines.TaskStep() { Enabled = true, Reference = new Pipelines.TaskStepDefinitionReference() { Name = "Ping", Version = "0.1.1", Id = Guid.NewGuid() } }; var pingVersion = new TaskVersion(pingTask.Reference.Version); Exception expectedException = new System.Net.Http.HttpRequestException("simulated network error"); _taskServer .Setup(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), _ec.Object.CancellationToken)) .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => { throw expectedException; }); var tasks = new List <Pipelines.TaskStep>(new Pipelines.TaskStep[] { pingTask }); //Act Exception actualException = null; try { await _taskManager.DownloadAsync(_ec.Object, tasks); } catch (Exception ex) { actualException = ex; } //Assert //verify task completed in less than 2sec and it is in failed state state Assert.Equal(expectedException, actualException); //see if the task.json was not downloaded Assert.Equal( 0, Directory.GetFiles(_hc.GetDirectory(WellKnownDirectory.Tasks), "*", SearchOption.AllDirectories).Length); } finally { Teardown(); } }
public Task <Stream> GetTaskContentZipAsync(Guid taskId, TaskVersion taskVersion, CancellationToken token) { String taskZip = Path.Join(HostContext.GetDirectory(WellKnownDirectory.Externals), "Tasks", taskId.ToString() + ".zip"); if (File.Exists(taskZip)) { return(Task.FromResult <Stream>(new FileStream(taskZip, FileMode.Open, FileAccess.Read, FileShare.Read))); } else { throw new Exception("A step specified a task which does not exist in the L1 test framework. Any tasks used by L1 tests must be added manually."); } }
public Task <Stream> GetTaskContentZipAsync(Guid taskId, TaskVersion taskVersion, CancellationToken token) { String baseDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); String taskZipsPath = Path.Join(baseDirectory, "TaskZips"); foreach (String zip in Directory.GetFiles(taskZipsPath)) { String zipName = Path.GetFileNameWithoutExtension(zip); if (zipName.Equals(taskId.ToString())) { return(Task.FromResult <Stream>(new FileStream(zip, FileMode.Open))); } } return(Task.FromResult <Stream>(null)); }
private Type GetTaskType(string name, string version) { var taskVersion = new TaskVersion(name, version); if (_typeMap.TryGetValue(taskVersion, out Type type)) { return(type); } foreach (NamedTypeDescriptor <TDescribed> descriptor in _descriptors) { if (IsTaskMatch(name, version, descriptor)) { _typeMap.TryAdd(taskVersion, descriptor.Type); return(descriptor.Type); } } return(null); }
public void SaveCreatesTaskAndAppendsVersion() { // Arrange. const string name = "task name"; var date = new DateTime(2000, 1, 1); var version = new TaskVersion(date); var task = new Task(name); var versions = new SortedDictionary <DateTime, TaskVersion>(); var store = MockRepository.GeneratePartialMock <MemoryTaskStore>(); store.Expect(s => s.GetVersions(name)).Return(versions); store.Expect(s => s.New(name, versions)).Return(task); // Act. var res = store.Save(name, version); // Assert. store.VerifyAllExpectations(); Assert.AreEqual(task, res); Assert.AreEqual(1, versions.Count()); Assert.AreEqual(version, versions[date]); }
public void NewCreatesTaskWithSpecifiedName() { // Arrange. const string taskName = "task name"; var date = new DateTime(); var version = new TaskVersion(date); var versions = new SortedDictionary <DateTime, TaskVersion>(); versions.Add(date, version); var store = new MemoryTaskStore(); // Act. var task = store.New(taskName, versions); // Assert. Assert.AreEqual(taskName, task.Name); Assert.AreEqual(1, task.Versions.Count()); Assert.AreEqual(version, task.Versions.First()); }
private Task CreateTaskWithVersion(string text, string id, DateTime start, DateTime end, int complete) { Task task = new Task(text, id, start, end); task.Complete = complete; TaskVersion version1 = new TaskVersion(); version1.Start = start.AddDays(30); version1.End = end.AddDays(31); version1.Complete = complete - 20; task.Versions.Add(version1); TaskVersion version2 = new TaskVersion(); version2.Start = start.AddDays(-1); version2.End = end.AddDays(-1); version2.Complete = complete - 10; task.Versions.Add(version2); return(task); }
public void CreateDelegates() { // Arrange. var date = new DateTime(2000, 1, 1); const string serializedTask = "serialized task"; const string taskName = "task name"; var parserResult = new ParserResult { Name = taskName }; var taskVersion = new TaskVersion(date); var task = new Task(taskName); var parser = MockRepository.GenerateStrictMock <ITaskParser>(); var store = MockRepository.GenerateStrictMock <ITaskStore>(); var factory = MockRepository.GeneratePartialMock <TaskFactory>(parser, store); parser .Expect(p => p.Parse(serializedTask)) .Return(parserResult); factory .Expect(f => f.New(date, parserResult)) .Return(taskVersion); store .Expect(s => s.Save(taskName, taskVersion)) .Return(task); // Act. var res = factory.Create(date, serializedTask); // Assert. parser.VerifyAllExpectations(); factory.VerifyAllExpectations(); store.VerifyAllExpectations(); Assert.AreEqual(task, res); }
//----------------------------------------------------------------- // Task Manager: Query and Download Task //----------------------------------------------------------------- public Task <Stream> GetTaskContentZipAsync(Guid taskId, TaskVersion taskVersion, CancellationToken token) { ArgUtil.Equal(RunMode.Normal, HostContext.RunMode, nameof(HostContext.RunMode)); CheckConnection(); return(_taskAgentClient.GetTaskContentZipAsync(taskId, taskVersion, cancellationToken: token)); }
public async Task EnsureCachedAsync(TaskDefinition task, CancellationToken token) { Trace.Entering(); ArgUtil.NotNull(task, nameof(task)); ArgUtil.NotNullOrEmpty(task.Version, nameof(task.Version)); // first check to see if we already have the task string destDirectory = GetTaskDirectory(task); Trace.Info($"Ensuring task exists: ID '{task.Id}', version '{task.Version}', name '{task.Name}', directory '{destDirectory}'."); if (File.Exists(destDirectory + ".completed")) { Trace.Info("Task already downloaded."); return; } // Invalidate the local cache. _localTasks = null; // delete existing task folder. Trace.Verbose("Deleting task destination folder: {0}", destDirectory); IOUtil.DeleteDirectory(destDirectory, CancellationToken.None); // Inform the user that a download is taking place. The download could take a while if // the task zip is large. It would be nice to print the localized name, but it is not // available from the reference included in the job message. _term.WriteLine(StringUtil.Loc("DownloadingTask0", task.Name)); string zipFile; var version = new TaskVersion(task.Version); //download and extract task in a temp folder and rename it on success string tempDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Tasks), "_temp_" + Guid.NewGuid()); try { Directory.CreateDirectory(tempDirectory); zipFile = Path.Combine(tempDirectory, string.Format("{0}.zip", Guid.NewGuid())); //open zip stream in async mode using (FileStream fs = new FileStream(zipFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) { using (Stream result = await HttpClient.GetTaskContentZipAsync(task.Id, version, token)) { //81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k). await result.CopyToAsync(fs, 81920, token); await fs.FlushAsync(token); } } Directory.CreateDirectory(destDirectory); ZipFile.ExtractToDirectory(zipFile, destDirectory); Trace.Verbose("Create watermark file indicate task download succeed."); File.WriteAllText(destDirectory + ".completed", DateTime.UtcNow.ToString()); Trace.Info("Finished getting task."); } finally { try { //if the temp folder wasn't moved -> wipe it if (Directory.Exists(tempDirectory)) { Trace.Verbose("Deleting task temp folder: {0}", tempDirectory); IOUtil.DeleteDirectory(tempDirectory, CancellationToken.None); // Don't cancel this cleanup and should be pretty fast. } } catch (Exception ex) { //it is not critical if we fail to delete the temp folder Trace.Warning("Failed to delete temp folder '{0}'. Exception: {1}", tempDirectory, ex); Trace.Warning(StringUtil.Loc("FailedDeletingTempDirectory0Message1", tempDirectory, ex.Message)); } } }
//设置任务版本 public ActionResult TaskSetVersion(TaskVersion model) { var model2 = manageApiBll.TaskSetVersion(model); return(ApiSuccess(model2)); }
private async Task DownloadAsync(IExecutionContext executionContext, Pipelines.TaskStepDefinitionReference task) { Trace.Entering(); ArgUtil.NotNull(executionContext, nameof(executionContext)); ArgUtil.NotNull(task, nameof(task)); ArgUtil.NotNullOrEmpty(task.Version, nameof(task.Version)); var taskServer = HostContext.GetService <ITaskServer>(); // first check to see if we already have the task string destDirectory = GetDirectory(task); Trace.Info($"Ensuring task exists: ID '{task.Id}', version '{task.Version}', name '{task.Name}', directory '{destDirectory}'."); var configurationStore = HostContext.GetService <IConfigurationStore>(); AgentSettings settings = configurationStore.GetSettings(); Boolean signingEnabled = !String.IsNullOrEmpty(settings.Fingerprint); if (File.Exists(destDirectory + ".completed") && !signingEnabled) { executionContext.Debug($"Task '{task.Name}' already downloaded at '{destDirectory}'."); return; } String taskZipPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.TaskZips), $"{task.Name}_{task.Id}_{task.Version}.zip"); if (signingEnabled && File.Exists(taskZipPath)) { executionContext.Debug($"Task '{task.Name}' already downloaded at '{taskZipPath}'."); // We need to extract the zip now because the task.json metadata for the task is used in JobExtension.InitializeJob. // This is fine because we overwrite the contents at task run time. if (!File.Exists(destDirectory + ".completed")) { // The zip exists but it hasn't been extracted yet. IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken); ExtractZip(taskZipPath, destDirectory); } return; } // delete existing task folder. Trace.Verbose("Deleting task destination folder: {0}", destDirectory); IOUtil.DeleteDirectory(destDirectory, CancellationToken.None); // Inform the user that a download is taking place. The download could take a while if // the task zip is large. It would be nice to print the localized name, but it is not // available from the reference included in the job message. executionContext.Output(StringUtil.Loc("DownloadingTask0", task.Name, task.Version)); string zipFile = string.Empty; var version = new TaskVersion(task.Version); //download and extract task in a temp folder and rename it on success string tempDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Tasks), "_temp_" + Guid.NewGuid()); try { Directory.CreateDirectory(tempDirectory); int retryCount = 0; // Allow up to 20 * 60s for any task to be downloaded from service. // Base on Kusto, the longest we have on the service today is over 850 seconds. // Timeout limit can be overwrite by environment variable if (!int.TryParse(Environment.GetEnvironmentVariable("VSTS_TASK_DOWNLOAD_TIMEOUT") ?? string.Empty, out int timeoutSeconds)) { timeoutSeconds = 20 * 60; } while (retryCount < 3) { using (var taskDownloadTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds))) using (var taskDownloadCancellation = CancellationTokenSource.CreateLinkedTokenSource(taskDownloadTimeout.Token, executionContext.CancellationToken)) { try { zipFile = Path.Combine(tempDirectory, string.Format("{0}.zip", Guid.NewGuid())); //open zip stream in async mode using (FileStream fs = new FileStream(zipFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: _defaultFileStreamBufferSize, useAsync: true)) using (Stream result = await taskServer.GetTaskContentZipAsync(task.Id, version, taskDownloadCancellation.Token)) { await result.CopyToAsync(fs, _defaultCopyBufferSize, taskDownloadCancellation.Token); await fs.FlushAsync(taskDownloadCancellation.Token); // download succeed, break out the retry loop. break; } } catch (OperationCanceledException) when(executionContext.CancellationToken.IsCancellationRequested) { Trace.Info($"Task download has been cancelled."); throw; } catch (Exception ex) when(retryCount < 2) { retryCount++; Trace.Error($"Fail to download task '{task.Id} ({task.Name}/{task.Version})' -- Attempt: {retryCount}"); Trace.Error(ex); if (taskDownloadTimeout.Token.IsCancellationRequested) { // task download didn't finish within timeout executionContext.Warning(StringUtil.Loc("TaskDownloadTimeout", task.Name, timeoutSeconds)); } else { executionContext.Warning(StringUtil.Loc("TaskDownloadFailed", task.Name, ex.Message)); if (ex.InnerException != null) { executionContext.Warning("Inner Exception: {ex.InnerException.Message}"); } } } } if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("VSTS_TASK_DOWNLOAD_NO_BACKOFF"))) { var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30)); executionContext.Warning($"Back off {backOff.TotalSeconds} seconds before retry."); await Task.Delay(backOff); } } if (signingEnabled) { Directory.CreateDirectory(HostContext.GetDirectory(WellKnownDirectory.TaskZips)); // Copy downloaded zip to the cache on disk for future extraction. executionContext.Debug($"Copying from {zipFile} to {taskZipPath}"); File.Copy(zipFile, taskZipPath); } // We need to extract the zip regardless of whether or not signing is enabled because the task.json metadata for the task is used in JobExtension.InitializeJob. // This is fine because we overwrite the contents at task run time. Directory.CreateDirectory(destDirectory); ExtractZip(zipFile, destDirectory); executionContext.Debug($"Task '{task.Name}' has been downloaded into '{(signingEnabled ? taskZipPath : destDirectory)}'."); Trace.Info("Finished getting task."); } finally { try { //if the temp folder wasn't moved -> wipe it if (Directory.Exists(tempDirectory)) { Trace.Verbose("Deleting task temp folder: {0}", tempDirectory); IOUtil.DeleteDirectory(tempDirectory, CancellationToken.None); // Don't cancel this cleanup and should be pretty fast. } } catch (Exception ex) { //it is not critical if we fail to delete the temp folder Trace.Warning("Failed to delete temp folder '{0}'. Exception: {1}", tempDirectory, ex); executionContext.Warning(StringUtil.Loc("FailedDeletingTempDirectory0Message1", tempDirectory, ex.Message)); } } }
//----------------------------------------------------------------- // Task Manager: Query and Download Task //----------------------------------------------------------------- public Task<Stream> GetTaskContentZipAsync(Guid taskId, TaskVersion taskVersion, CancellationToken token) { CheckConnection(); return _taskAgentClient.GetTaskContentZipAsync(taskId, taskVersion, null, token); }
//----------------------------------------------------------------- // Task Manager: Query and Download Task //----------------------------------------------------------------- public Task <Stream> GetTaskContentZipAsync(Guid taskId, TaskVersion taskVersion, CancellationToken token) { CheckConnection(); return(_taskAgentClient.GetTaskContentZipAsync(taskId, taskVersion, null, token)); }
public async void BubblesCancellation() { try { //Arrange using (var tokenSource = new CancellationTokenSource()) using (var _hc = Setup(tokenSource)) { var bingTask = new Pipelines.TaskStep() { Enabled = true, Reference = new Pipelines.TaskStepDefinitionReference() { Name = "Bing", Version = "0.1.2", Id = Guid.NewGuid() } }; var pingTask = new Pipelines.TaskStep() { Enabled = true, Reference = new Pipelines.TaskStepDefinitionReference() { Name = "Ping", Version = "0.1.1", Id = Guid.NewGuid() } }; var bingVersion = new TaskVersion(bingTask.Reference.Version); var pingVersion = new TaskVersion(pingTask.Reference.Version); _taskServer .Setup(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), It.IsAny <CancellationToken>())) .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => { tokenSource.Cancel(); tokenSource.Token.ThrowIfCancellationRequested(); return(null); }); var tasks = new List <Pipelines.TaskStep>(new Pipelines.TaskStep[] { bingTask, pingTask }); //Act //should initiate a download with a mocked IJobServer, which sets a cancellation token and //download task is expected to be in cancelled state Task downloadTask = _taskManager.DownloadAsync(_ec.Object, tasks); Task[] taskToWait = { downloadTask, Task.Delay(2000) }; //wait for the task to be cancelled to exit await Task.WhenAny(taskToWait); //Assert //verify task completed in less than 2sec and it is in cancelled state Assert.True(downloadTask.IsCompleted, $"{nameof(_taskManager.DownloadAsync)} timed out."); Assert.True(!downloadTask.IsFaulted, downloadTask.Exception?.ToString()); Assert.True(downloadTask.IsCanceled); //check if the task.json was not downloaded for ping and bing tasks Assert.Equal( 0, Directory.GetFiles(_hc.GetDirectory(WellKnownDirectory.Tasks), "*", SearchOption.AllDirectories).Length); //assert download was invoked only once, because the first task cancelled the second task download _taskServer .Verify(x => x.GetTaskContentZipAsync(It.IsAny <Guid>(), It.IsAny <TaskVersion>(), It.IsAny <CancellationToken>()), Times.Once()); } } finally { Teardown(); } }
public async void BubblesNetworkException() { try { // Arrange. Setup(); var pingTask = new TaskInstance() { Enabled = true, Name = "Ping", Version = "0.1.1", Id = Guid.NewGuid() }; var pingVersion = new TaskVersion(pingTask.Version); Exception expectedException = new System.Net.Http.HttpRequestException("simulated network error"); _taskServer .Setup(x => x.GetTaskContentZipAsync(It.IsAny<Guid>(), It.IsAny<TaskVersion>(), _ec.Object.CancellationToken)) .Returns((Guid taskId, TaskVersion taskVersion, CancellationToken token) => { throw expectedException; }); var tasks = new List<TaskInstance>(new TaskInstance[] { pingTask }); //Act Exception actualException = null; try { await _taskManager.DownloadAsync(_ec.Object, tasks); } catch (Exception ex) { actualException = ex; } //Assert //verify task completed in less than 2sec and it is in failed state state Assert.Equal(expectedException, actualException); //see if the task.json was not downloaded Assert.Equal( 0, Directory.GetFiles(IOUtil.GetTasksPath(_hc), "*", SearchOption.AllDirectories).Length); } finally { Teardown(); } }
//----------------------------------------------------------------- // Task Manager: Query and Download Task //----------------------------------------------------------------- public Task <TaskDefinition> GetTaskDefinitionAsync(Guid taskId, TaskVersion taskVersion, CancellationToken token) { return(_taskAgentClient.GetTaskDefinitionAsync(taskId, taskVersion, null, null, null, token)); }
private async Task DownloadAsync(IExecutionContext executionContext, TaskReference task) { Trace.Entering(); ArgUtil.NotNull(executionContext, nameof(executionContext)); ArgUtil.NotNull(task, nameof(task)); ArgUtil.NotNullOrEmpty(task.Version, nameof(task.Version)); var jobServer = HostContext.GetService <IJobServer>(); // first check to see if we already have the task string destDirectory = GetDirectory(task); Trace.Info($"Ensuring task exists: ID '{task.Id}', version '{task.Version}', name '{task.Name}', directory '{destDirectory}'."); if (Directory.Exists(destDirectory)) { Trace.Info("Task already downloaded."); return; } Trace.Info("Getting task."); string zipFile; var version = new TaskVersion(task.Version); //download and extract task in a temp folder and rename it on success string tempDirectory = Path.Combine(IOUtil.GetTasksPath(HostContext), "_temp_" + Guid.NewGuid()); try { Directory.CreateDirectory(tempDirectory); zipFile = Path.Combine(tempDirectory, string.Format("{0}.zip", Guid.NewGuid())); //open zip stream in async mode using (FileStream fs = new FileStream(zipFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) { using (Stream result = await jobServer.GetTaskContentZipAsync(task.Id, version, executionContext.CancellationToken)) { //81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k). await result.CopyToAsync(fs, 81920, executionContext.CancellationToken); await fs.FlushAsync(executionContext.CancellationToken); } } ZipFile.ExtractToDirectory(zipFile, tempDirectory); File.Delete(zipFile); Directory.CreateDirectory(Path.GetDirectoryName(destDirectory)); Directory.Move(tempDirectory, destDirectory); Trace.Info("Finished getting task."); } finally { try { //if the temp folder wasn't moved -> wipe it if (Directory.Exists(tempDirectory)) { Trace.Verbose("Deleting task temp folder: {0}", tempDirectory); IOUtil.DeleteDirectory(tempDirectory, CancellationToken.None); // Don't cancel this cleanup and should be pretty fast. } } catch (Exception ex) { //it is not critical if we fail to delete the temp folder Trace.Warning("Failed to delete temp folder '{0}'. Exception: {1}", tempDirectory, ex); executionContext.Warning(StringUtil.Loc("FailedDeletingTempDirectory0Message1", tempDirectory, ex.Message)); } } }
private async Task DownloadAsync(IExecutionContext executionContext, TaskReference task) { Trace.Entering(); ArgUtil.NotNull(executionContext, nameof(executionContext)); ArgUtil.NotNull(task, nameof(task)); ArgUtil.NotNullOrEmpty(task.Version, nameof(task.Version)); var taskServer = HostContext.GetService<ITaskServer>(); // first check to see if we already have the task string destDirectory = GetDirectory(task); Trace.Info($"Ensuring task exists: ID '{task.Id}', version '{task.Version}', name '{task.Name}', directory '{destDirectory}'."); if (Directory.Exists(destDirectory)) { Trace.Info("Task already downloaded."); return; } Trace.Info("Getting task."); string zipFile; var version = new TaskVersion(task.Version); //download and extract task in a temp folder and rename it on success string tempDirectory = Path.Combine(IOUtil.GetTasksPath(HostContext), "_temp_" + Guid.NewGuid()); try { Directory.CreateDirectory(tempDirectory); zipFile = Path.Combine(tempDirectory, string.Format("{0}.zip", Guid.NewGuid())); //open zip stream in async mode using (FileStream fs = new FileStream(zipFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) { using (Stream result = await taskServer.GetTaskContentZipAsync(task.Id, version, executionContext.CancellationToken)) { //81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k). await result.CopyToAsync(fs, 81920, executionContext.CancellationToken); await fs.FlushAsync(executionContext.CancellationToken); } } ZipFile.ExtractToDirectory(zipFile, tempDirectory); File.Delete(zipFile); Directory.CreateDirectory(Path.GetDirectoryName(destDirectory)); Directory.Move(tempDirectory, destDirectory); Trace.Info("Finished getting task."); } finally { try { //if the temp folder wasn't moved -> wipe it if (Directory.Exists(tempDirectory)) { Trace.Verbose("Deleting task temp folder: {0}", tempDirectory); IOUtil.DeleteDirectory(tempDirectory, CancellationToken.None); // Don't cancel this cleanup and should be pretty fast. } } catch (Exception ex) { //it is not critical if we fail to delete the temp folder Trace.Warning("Failed to delete temp folder '{0}'. Exception: {1}", tempDirectory, ex); executionContext.Warning(StringUtil.Loc("FailedDeletingTempDirectory0Message1", tempDirectory, ex.Message)); } } }