/// <inheritdoc/> public void AddAttachment(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName) { ValidateArg.NotNull(fileTransferInfo, nameof(fileTransferInfo)); if (string.IsNullOrEmpty(this.SessionOutputDirectory)) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error( "DataCollectionAttachmentManager.AddAttachment: Initialize not invoked."); } return; } if (!this.AttachmentSets.ContainsKey(fileTransferInfo.Context)) { var uriAttachmentSetMap = new Dictionary <Uri, AttachmentSet>(); this.AttachmentSets.Add(fileTransferInfo.Context, uriAttachmentSetMap); this.attachmentTasks.Add(fileTransferInfo.Context, new List <Task>()); } if (!this.AttachmentSets[fileTransferInfo.Context].ContainsKey(uri)) { this.AttachmentSets[fileTransferInfo.Context].Add(uri, new AttachmentSet(uri, friendlyName)); } this.AddNewFileTransfer(fileTransferInfo, sendFileCompletedCallback, uri, friendlyName); }
public void GetAttachmentsShouldNotReturnAttachmentsAfterCancelled() { var fileHelper = new Mock <IFileHelper>(); var testableAttachmentManager = new TestableDataCollectionAttachmentManager(fileHelper.Object); var attachmentPath = Path.Combine(TempDirectoryPath, "filename.txt"); File.WriteAllText(attachmentPath, string.Empty); var datacollectioncontext = new DataCollectionContext(this.sessionId); var friendlyName = "TestDataCollector"; var uri = new Uri("datacollector://Company/Product/Version"); var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, attachmentPath, true); var waitHandle = new AutoResetEvent(false); var handler = new AsyncCompletedEventHandler((a, e) => { Assert.Fail("Handler shouldn't be called since operation is canceled."); }); // We cancel the operation in the actual operation. This ensures the follow up task to is never called, attachments // are not added. Action cancelAddAttachment = () => testableAttachmentManager.Cancel(); fileHelper.Setup(fh => fh.MoveFile(It.IsAny <string>(), It.IsAny <string>())).Callback(cancelAddAttachment); testableAttachmentManager.Initialize(this.sessionId, TempDirectoryPath, this.messageSink.Object); testableAttachmentManager.AddAttachment(dataCollectorDataMessage, handler, uri, friendlyName); // Wait for the attachment transfer tasks to complete var result = testableAttachmentManager.GetAttachments(datacollectioncontext); Assert.AreEqual(0, result[0].Attachments.Count); }
public void GetAttachmentsShouldReturnAllAttachmets() { var filename = "filename1.txt"; File.WriteAllText(Path.Combine(TempDirectoryPath, filename), string.Empty); this.attachmentManager.Initialize(this.sessionId, TempDirectoryPath, this.messageSink.Object); var datacollectioncontext = new DataCollectionContext(this.sessionId); var friendlyName = "TestDataCollector"; var uri = new Uri("datacollector://Company/Product/Version"); var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(TempDirectoryPath, filename), true); this.attachmentManager.AddAttachment(dataCollectorDataMessage, null, uri, friendlyName); Assert.AreEqual(1, this.attachmentManager.AttachmentSets.Count); var result = this.attachmentManager.GetAttachments(datacollectioncontext); Assert.AreEqual(0, this.attachmentManager.AttachmentSets.Count); Assert.AreEqual(1, result.Count); Assert.AreEqual(friendlyName, result[0].DisplayName); Assert.AreEqual(uri, result[0].Uri); Assert.AreEqual(1, result[0].Attachments.Count); }
public override string tryGetFileFromGuest(string srcpath, out Exception errorOrNull) { try { NamePasswordAuthentication Auth = new NamePasswordAuthentication { Username = _spec.kernelVMUsername, Password = _spec.kernelVMPassword, InteractiveSession = true }; VimClientImpl vClient = conn.getConnection(); VirtualMachine underlyingVM = conn.getMachine(); GuestOperationsManager gom = (GuestOperationsManager)vClient.GetView(vClient.ServiceContent.GuestOperationsManager, null); GuestAuthManager guestAuthManager = vClient.GetView(gom.AuthManager, null) as GuestAuthManager; guestAuthManager.ValidateCredentialsInGuest(underlyingVM.MoRef, Auth); GuestFileManager GFM = vClient.GetView(gom.FileManager, null) as GuestFileManager; FileTransferInformation transferOutput = GFM.InitiateFileTransferFromGuest(underlyingVM.MoRef, Auth, srcpath); string nodeIpAddress = vClient.ServiceUrl; nodeIpAddress = nodeIpAddress.Remove(nodeIpAddress.LastIndexOf('/')); string url = transferOutput.Url.Replace("https://*", nodeIpAddress); using (WebClient webClient = new WebClient()) { errorOrNull = null; return(webClient.DownloadString(url)); } } catch (Exception e) { errorOrNull = e; return(null); } }
public void AddAttachmentShouldAddNewFileTransferAndCopyFileToOutputDirectoryIfDeleteFileIsFalse() { var filename = "filename.txt"; File.WriteAllText(Path.Combine(TempDirectoryPath, filename), string.Empty); this.attachmentManager.Initialize(this.sessionId, TempDirectoryPath, this.messageSink.Object); var datacollectioncontext = new DataCollectionContext(this.sessionId); var friendlyName = "TestDataCollector"; var uri = new Uri("datacollector://Company/Product/Version"); EventWaitHandle waitHandle = new AutoResetEvent(false); var handler = new AsyncCompletedEventHandler((a, e) => { waitHandle.Set(); }); var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(TempDirectoryPath, filename), false); this.attachmentManager.AddAttachment(dataCollectorDataMessage, handler, uri, friendlyName); // Wait for file operations to complete waitHandle.WaitOne(Timeout); Assert.IsTrue(File.Exists(Path.Combine(TempDirectoryPath, filename))); Assert.IsTrue(File.Exists(Path.Combine(TempDirectoryPath, this.sessionId.Id.ToString(), filename))); Assert.AreEqual(1, this.attachmentManager.AttachmentSets[datacollectioncontext][uri].Attachments.Count); }
public void AddAttachmentsShouldAddFilesCorrespondingToDifferentDataCollectors() { var filename = "filename.txt"; var filename1 = "filename1.txt"; File.WriteAllText(Path.Combine(TempDirectoryPath, filename), string.Empty); File.WriteAllText(Path.Combine(TempDirectoryPath, filename1), string.Empty); this.attachmentManager.Initialize(this.sessionId, TempDirectoryPath, this.messageSink.Object); var datacollectioncontext = new DataCollectionContext(this.sessionId); var friendlyName = "TestDataCollector"; var uri = new Uri("datacollector://Company/Product/Version"); var uri1 = new Uri("datacollector://Company/Product/Version1"); EventWaitHandle waitHandle = new AutoResetEvent(false); var handler = new AsyncCompletedEventHandler((a, e) => { waitHandle.Set(); }); var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(TempDirectoryPath, filename), false); this.attachmentManager.AddAttachment(dataCollectorDataMessage, handler, uri, friendlyName); // Wait for file operations to complete waitHandle.WaitOne(Timeout); waitHandle.Reset(); dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(TempDirectoryPath, filename1), false); this.attachmentManager.AddAttachment(dataCollectorDataMessage, handler, uri1, friendlyName); // Wait for file operations to complete waitHandle.WaitOne(Timeout); Assert.AreEqual(1, this.attachmentManager.AttachmentSets[datacollectioncontext][uri].Attachments.Count); Assert.AreEqual(1, this.attachmentManager.AttachmentSets[datacollectioncontext][uri1].Attachments.Count); }
/// <inheritdoc/> public void AddAttachment(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName) { ValidateArg.NotNull(fileTransferInfo, nameof(fileTransferInfo)); if (string.IsNullOrEmpty(this.SessionOutputDirectory)) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error( "DataCollectionAttachmentManager.AddAttachment: Initialize not invoked."); } return; } if (!this.AttachmentSets.ContainsKey(uri)) { this.AttachmentSets.Add(uri, new AttachmentSet(uri, friendlyName)); } if (fileTransferInfo != null) { this.AddNewFileTransfer(fileTransferInfo, sendFileCompletedCallback, uri, friendlyName); } else { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error("DataCollectionAttachmentManager.AddAttachment: Got unexpected message of type FileTransferInformationExtension."); } } }
public void SendFileAsyncShouldInvokeSendFileCompletedIfRegistered() { var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt"); File.WriteAllText(filename, string.Empty); var guid = Guid.NewGuid(); var sessionId = new SessionId(guid); var context = new DataCollectionContext(sessionId); var fileTransferInfo = new FileTransferInformation(context, filename, false); var attachmentManager = new DataCollectionAttachmentManager(); attachmentManager.Initialize(sessionId, AppContext.BaseDirectory, new Mock <IMessageSink>().Object); this.dataCollectionSink = new TestPlatformDataCollectionSink(attachmentManager, this.dataCollectorConfig); this.dataCollectionSink.SendFileCompleted += SendFileCompleted_Handler; this.dataCollectionSink.SendFileAsync(fileTransferInfo); var result = attachmentManager.GetAttachments(context); Assert.IsNotNull(result); Assert.IsTrue(this.isEventHandlerInvoked); }
/// <summary> /// Disposes of the timer when called to prevent further calls. /// Kills the other instance of procdump if launched for collecting trigger based dumps. /// Starts and waits for a new proc dump process to collect a single dump and then /// kills the testhost process. /// </summary> private void CollectDumpAndAbortTesthost() { EqtTrace.Info(string.Format(CultureInfo.CurrentUICulture, Resources.Resources.InactivityTimeout, (int)this.inactivityTimespan.TotalMinutes)); this.inactivityTimerAlreadyFired = true; try { EqtTrace.Verbose("Calling dispose on Inactivity timer."); this.inactivityTimer.Dispose(); } catch { EqtTrace.Verbose("Inactivity timer is already disposed."); } if (this.collectProcessDumpOnTrigger) { // Detach procdump from the testhost process to prevent testhost process from crashing // if/when we try to kill the existing proc dump process. this.processDumpUtility.DetachFromTargetProcess(this.testHostProcessId); } try { this.processDumpUtility.StartHangBasedProcessDump(this.testHostProcessId, this.attachmentGuid, this.GetResultsDirectory(), this.processFullDumpEnabled); } catch (Exception ex) { EqtTrace.Error($"BlameCollector.CollectDumpAndAbortTesthost: Failed with error {ex}"); } try { var dumpFile = this.processDumpUtility.GetDumpFile(); if (!string.IsNullOrEmpty(dumpFile)) { var fileTransferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true, this.fileHelper); this.dataCollectionSink.SendFileAsync(fileTransferInformation); } else { EqtTrace.Error("BlameCollector.CollectDumpAndAbortTesthost: blame:CollectDumpOnHang was enabled but dump file was not generated."); } } catch (Exception ex) { // Eat up any exception here and log it but proceed with killing the test host process. EqtTrace.Error(ex); } try { Process.GetProcessById(this.testHostProcessId).Kill(); } catch (Exception ex) { EqtTrace.Error(ex); } }
public override void SendFileAsync(FileTransferInformation fileTransferInformation) { this.IsSendFileAsyncInvoked = true; if (this.SendFileCompleted == null) { return; } }
/// <summary> /// Sends a file asynchronously. /// </summary> /// <param name="fileTransferInformation">Information about the file being transferred.</param> public override void SendFileAsync(FileTransferInformation fileTransferInformation) { ValidateArg.NotNull(fileTransferInformation, "fileTransferInformation"); Debug.Assert(System.IO.File.Exists(fileTransferInformation.Path), "DataCollector file '" + fileTransferInformation.Path + "' does not exist!"); this.AttachmentManager.AddAttachment(fileTransferInformation, this.SendFileCompleted, this.DataCollectorConfig.TypeUri, this.DataCollectorConfig.FriendlyName); }
/// <summary> /// Called when Session End event is invoked /// </summary> /// <param name="sender">Sender</param> /// <param name="args">SessionEndEventArgs</param> private void SessionEnded_Handler(object sender, SessionEndEventArgs args) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Blame Collector : Session End"); } try { // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment if (this.testStartCount > this.testEndCount) { var filepath = Path.Combine(this.GetResultsDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } if (this.processDumpEnabled) { // If there was a test case crash or if we need to collect dump on process exit. if (this.testStartCount > this.testEndCount || this.collectDumpAlways) { try { var dumpFile = this.processDumpUtility.GetDumpFile(); if (!string.IsNullOrEmpty(dumpFile)) { var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } else { EqtTrace.Warning("BlameCollector.SessionEnded_Handler: blame:CollectDump was enabled but dump file was not generated."); this.logger.LogWarning(args.Context, Resources.Resources.ProcDumpNotGenerated); } } catch (FileNotFoundException ex) { EqtTrace.Warning(ex.Message); this.logger.LogWarning(args.Context, ex.Message); } } } } finally { // Attempt to terminate the proc dump process if proc dump was enabled if (this.processDumpEnabled) { this.processDumpUtility.TerminateProcess(); } this.DeregisterEvents(); } }
public void FileTransferFromGuest(string guestFilePath, string localFilePath) { //throw new NotImplementedException(); FileTransferInformation fti = _vimService.InitiateFileTransferFromGuest( _morFileManager, //VimLib.VimServiceReference.ManagedObjectReference _this, _morVM, //VimLib.VimServiceReference.ManagedObjectReference vm, _NamePasswordAuthentication, //VimLib.VimServiceReference.GuestAuthentication auth, guestFilePath ); WebClient webClient = new WebClient(); webClient.DownloadFile(fti.url, localFilePath); }
public void SendFileAsyncShouldInvokeAttachmentManagerWithValidFileTransferInfo() { var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt"); File.WriteAllText(filename, string.Empty); var guid = Guid.NewGuid(); var sessionId = new SessionId(guid); var context = new DataCollectionContext(sessionId); var fileTransferInfo = new FileTransferInformation(context, filename, false); this.dataCollectionSink.SendFileAsync(fileTransferInfo); this.attachmentManager.Verify(x => x.AddAttachment(It.IsAny <FileTransferInformation>(), It.IsAny <AsyncCompletedEventHandler>(), It.IsAny <Uri>(), It.IsAny <string>()), Times.Once()); }
public void AddAttachmentShouldNotAddNewFileTransferIfSessionIsNotConfigured() { var filename = "filename.txt"; File.WriteAllText(Path.Combine(TempDirectoryPath, filename), string.Empty); var datacollectioncontext = new DataCollectionContext(this.sessionId); var friendlyName = "TestDataCollector"; var uri = new Uri("datacollector://Company/Product/Version"); var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(TempDirectoryPath, filename), false); this.attachmentManager.AddAttachment(dataCollectorDataMessage, null, uri, friendlyName); Assert.AreEqual(this.attachmentManager.AttachmentSets.Count, 0); }
/// <summary> /// Called when Session End event is invoked /// </summary> /// <param name="sender">Sender</param> /// <param name="args">SessionEndEventArgs</param> private void SessionEnded_Handler(object sender, SessionEndEventArgs args) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Blame Collector : Session End"); } // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment if (this.testStartCount > this.testEndCount) { var filepath = Path.Combine(this.GetResultsDirectory(), Constants.AttachmentFileName); filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, filepath); var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } this.DeregisterEvents(); }
/// <summary> /// Sanity checks on CopyRequestData /// </summary> /// <param name="fileTransferInfo"> /// The file Transfer Info. /// </param> /// <param name="localFilePath"> /// The local File Path. /// </param> private static void Validate(FileTransferInformation fileTransferInfo, string localFilePath) { if (!File.Exists(fileTransferInfo.FileName)) { throw new FileNotFoundException( string.Format( CultureInfo.CurrentCulture, "Could not find source file '{0}'.", fileTransferInfo.FileName)); } var directoryName = Path.GetDirectoryName(localFilePath); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } else if (File.Exists(localFilePath)) { File.Delete(localFilePath); } }
public void GetAttachmentsShouldNotReturnAttachmentsAfterCancelled() { var filename = "filename1.txt"; File.WriteAllText(Path.Combine(AppContext.BaseDirectory, filename), string.Empty); this.attachmentManager.Initialize(this.sessionId, AppContext.BaseDirectory, this.messageSink.Object); var datacollectioncontext = new DataCollectionContext(this.sessionId); var friendlyName = "TestDataCollector"; var uri = new Uri("datacollector://Company/Product/Version"); var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(AppContext.BaseDirectory, filename), true); this.attachmentManager.AddAttachment(dataCollectorDataMessage, null, uri, friendlyName); this.attachmentManager.Cancel(); var result = this.attachmentManager.GetAttachments(datacollectioncontext); Assert.AreEqual(0, result[0].Attachments.Count); }
/// <summary> /// Add a new file transfer (either copy/move) request. /// </summary> /// <param name="fileTransferInfo"> /// The file Transfer Info. /// </param> /// <param name="sendFileCompletedCallback"> /// The send File Completed Callback. /// </param> /// <param name="uri"> /// The uri. /// </param> /// <param name="friendlyName"> /// The friendly Name. /// </param> private void AddNewFileTransfer(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName) { var context = fileTransferInfo.Context; Debug.Assert( context != null, "DataCollectionManager.AddNewFileTransfer: FileDataHeaderMessage with null context."); var testCaseId = fileTransferInfo.Context.HasTestCase ? fileTransferInfo.Context.TestExecId.Id.ToString() : string.Empty; var directoryPath = Path.Combine( this.SessionOutputDirectory, testCaseId); var localFilePath = Path.Combine(directoryPath, Path.GetFileName(fileTransferInfo.FileName)); var task = Task.Factory.StartNew( () => { Validate(fileTransferInfo, localFilePath); if (this.cancellationTokenSource.Token.IsCancellationRequested) { this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); } try { if (fileTransferInfo.PerformCleanup) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moving file {0} to {1}", fileTransferInfo.FileName, localFilePath); } File.Move(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moved file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } else { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copying file {0} to {1}", fileTransferInfo.FileName, localFilePath); } File.Copy(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copied file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } } catch (Exception ex) { this.LogError( ex.Message, uri, friendlyName, Guid.Parse(testCaseId)); throw; } }, this.cancellationTokenSource.Token); var continuationTask = task.ContinueWith( (t) => { try { if (t.Exception == null) { this.AttachmentSets[uri].Attachments.Add(new UriDataAttachment(new Uri(localFilePath), fileTransferInfo.Description)); } if (sendFileCompletedCallback != null) { sendFileCompletedCallback(this, new AsyncCompletedEventArgs(t.Exception, false, fileTransferInfo.UserToken)); } } catch (Exception e) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error( "DataCollectionAttachmentManager.TriggerCallBack: Error occurred while raising the file transfer completed callback for {0}. Error: {1}", localFilePath, e.ToString()); } } }, this.cancellationTokenSource.Token); this.attachmentTasks.Add(continuationTask); }
/// <summary> /// Called when Session End event is invoked /// </summary> /// <param name="sender">Sender</param> /// <param name="args">SessionEndEventArgs</param> private void SessionEndedHandler(object sender, SessionEndEventArgs args) { this.ResetInactivityTimer(); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Blame Collector : Session End"); } try { // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment if (this.testStartCount > this.testEndCount) { var filepath = Path.Combine(this.GetTempDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); var fti = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); this.dataCollectionSink.SendFileAsync(fti); } else { if (this.collectProcessDumpOnTestHostHang) { this.logger.LogWarning(this.context.SessionDataCollectionContext, Resources.Resources.NotGeneratingSequenceFile); } } if (this.uploadDumpFiles) { try { var dumpFiles = this.processDumpUtility.GetDumpFiles(warnOnNoDumpFiles: this.collectDumpAlways); foreach (var dumpFile in dumpFiles) { if (!string.IsNullOrEmpty(dumpFile)) { try { var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } catch (FileNotFoundException ex) { EqtTrace.Warning(ex.ToString()); this.logger.LogWarning(args.Context, ex.ToString()); } } } } catch (FileNotFoundException ex) { EqtTrace.Warning(ex.ToString()); this.logger.LogWarning(args.Context, ex.ToString()); } } else { EqtTrace.Info("BlameCollector.CollectDumpAndAbortTesthost: Custom path to dump directory was provided via VSTEST_DUMP_PATH. Skipping attachment upload, the caller is responsible for collecting and uploading the dumps themselves."); } } finally { // Attempt to terminate the proc dump process if proc dump was enabled if (this.collectProcessDumpOnTrigger) { this.processDumpUtility.DetachFromTargetProcess(this.testHostProcessId); } this.DeregisterEvents(); } }
/// <summary> /// Disposes of the timer when called to prevent further calls. /// Kills the other instance of proc dump if launched for collecting trigger based dumps. /// Starts and waits for a new proc dump process to collect a single dump and then /// kills the testhost process. /// </summary> private void CollectDumpAndAbortTesthost() { this.inactivityTimerAlreadyFired = true; string value; string unit; if (this.inactivityTimespan.TotalSeconds <= 90) { value = ((int)this.inactivityTimespan.TotalSeconds).ToString(); unit = Resources.Resources.Seconds; } else { value = Math.Round(this.inactivityTimespan.TotalMinutes, 2).ToString(); unit = Resources.Resources.Minutes; } var message = string.Format(CultureInfo.CurrentUICulture, Resources.Resources.InactivityTimeout, value, unit); EqtTrace.Warning(message); this.logger.LogWarning(this.context.SessionDataCollectionContext, message); try { EqtTrace.Verbose("Calling dispose on Inactivity timer."); this.inactivityTimer.Dispose(); } catch { EqtTrace.Verbose("Inactivity timer is already disposed."); } try { Action <string> logWarning = m => this.logger.LogWarning(this.context.SessionDataCollectionContext, m); var dumpDirectory = this.GetDumpDirectory(); this.processDumpUtility.StartHangBasedProcessDump(this.testHostProcessId, dumpDirectory, this.processFullDumpEnabled, this.targetFramework, logWarning); } catch (Exception ex) { this.logger.LogError(this.context.SessionDataCollectionContext, $"Blame: Creating hang dump failed with error.", ex); } if (this.collectProcessDumpOnTrigger) { // Detach procdump from the testhost process to prevent testhost process from crashing // if/when we try to kill the existing proc dump process. this.processDumpUtility.DetachFromTargetProcess(this.testHostProcessId); } if (this.uploadDumpFiles) { try { var dumpFiles = this.processDumpUtility.GetDumpFiles(); foreach (var dumpFile in dumpFiles) { try { if (!string.IsNullOrEmpty(dumpFile)) { var fileTransferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true, this.fileHelper); this.dataCollectionSink.SendFileAsync(fileTransferInformation); } } catch (Exception ex) { // Eat up any exception here and log it but proceed with killing the test host process. EqtTrace.Error(ex); } if (!dumpFiles.Any()) { EqtTrace.Error("BlameCollector.CollectDumpAndAbortTesthost: blame:CollectDumpOnHang was enabled but dump file was not generated."); } } } catch (Exception ex) { this.logger.LogError(this.context.SessionDataCollectionContext, $"Blame: Collecting hang dump failed with error.", ex); } } else { EqtTrace.Info("BlameCollector.CollectDumpAndAbortTesthost: Custom path to dump directory was provided via VSTEST_DUMP_PATH. Skipping attachment upload, the caller is responsible for collecting and uploading the dumps themselves."); } try { var p = Process.GetProcessById(this.testHostProcessId); try { if (!p.HasExited) { p.Kill(); } } catch (InvalidOperationException) { } } catch (Exception ex) { EqtTrace.Error(ex); } }
/// <summary> /// The write event logs. /// </summary> /// <param name="eventLogEntries"> /// The event log entries. /// </param> /// <param name="maxLogEntries"> /// Max Log Entries. /// </param> /// <param name="dataCollectionContext"> /// The data collection context. /// </param> /// <param name="requestedDuration"> /// The requested duration. /// </param> /// <param name="timeRequestReceived"> /// The time request received. /// </param> /// <returns> /// The <see cref="string"/>. /// </returns> internal string WriteEventLogs(List <EventLogEntry> eventLogEntries, int maxLogEntries, DataCollectionContext dataCollectionContext, TimeSpan requestedDuration, DateTime timeRequestReceived) { // Generate a unique but friendly Directory name in the temp directory string eventLogDirName = string.Format( CultureInfo.InvariantCulture, "{0}-{1}-{2:yyyy}{2:MM}{2:dd}-{2:HH}{2:mm}{2:ss}.{2:fff}", "Event Log", Environment.MachineName, DateTime.Now); string eventLogDirPath = Path.Combine(Path.GetTempPath(), eventLogDirName); // Create the directory this.fileHelper.CreateDirectory(eventLogDirPath); string eventLogBasePath = Path.Combine(eventLogDirPath, EventLogFileName); bool unusedFilenameFound = false; string eventLogPath = eventLogBasePath + ".xml"; if (this.fileHelper.Exists(eventLogPath)) { for (int i = 1; !unusedFilenameFound; i++) { eventLogPath = eventLogBasePath + "-" + i.ToString(CultureInfo.InvariantCulture) + ".xml"; if (!this.fileHelper.Exists(eventLogPath)) { unusedFilenameFound = true; } } } DateTime minDate = DateTime.MinValue; // Limit entries to a certain time range if requested if (requestedDuration < TimeSpan.MaxValue) { try { minDate = timeRequestReceived - requestedDuration; } catch (ArgumentOutOfRangeException) { minDate = DateTime.MinValue; } } Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); EventLogXmlWriter.WriteEventLogEntriesToXmlFile( eventLogPath, eventLogEntries.Where( entry => entry.TimeGenerated > minDate && entry.TimeGenerated < DateTime.MaxValue).OrderBy(x => x.TimeGenerated).ToList().Take(maxLogEntries).ToList(), this.fileHelper); stopwatch.Stop(); if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose( string.Format( CultureInfo.InvariantCulture, "EventLogDataContainer: Wrote {0} event log entries to file '{1}' in {2} seconds", eventLogEntries.Count, eventLogPath, stopwatch.Elapsed.TotalSeconds.ToString(CultureInfo.InvariantCulture))); } // Write the event log file FileTransferInformation fileTransferInformation = new FileTransferInformation(dataCollectionContext, eventLogPath, true, this.fileHelper); this.dataSink.SendFileAsync(fileTransferInformation); if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose( "EventLogDataContainer: Event log successfully sent for data collection context '{0}'.", dataCollectionContext.ToString()); } return(eventLogPath); }
void IDataCollectionSink.SendFileAsync(FileTransferInformation fileInformation) { this.wrapped.SendFileAsync(fileInformation); }
/// <summary> /// Add a new file transfer (either copy/move) request. /// </summary> /// <param name="fileTransferInfo"> /// The file Transfer Info. /// </param> /// <param name="sendFileCompletedCallback"> /// The send File Completed Callback. /// </param> /// <param name="uri"> /// The uri. /// </param> /// <param name="friendlyName"> /// The friendly Name. /// </param> private void AddNewFileTransfer(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName) { var context = fileTransferInfo.Context; Debug.Assert( context != null, "DataCollectionManager.AddNewFileTransfer: FileDataHeaderMessage with null context."); var testCaseId = fileTransferInfo.Context.HasTestCase ? fileTransferInfo.Context.TestExecId.Id.ToString() : string.Empty; var directoryPath = Path.Combine( this.SessionOutputDirectory, testCaseId); var localFilePath = Path.Combine(directoryPath, Path.GetFileName(fileTransferInfo.FileName)); var task = Task.Factory.StartNew( () => { Validate(fileTransferInfo, localFilePath); if (this.cancellationTokenSource.Token.IsCancellationRequested) { this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); } try { if (fileTransferInfo.PerformCleanup) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moving file {0} to {1}", fileTransferInfo.FileName, localFilePath); } this.fileHelper.MoveFile(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moved file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } else { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copying file {0} to {1}", fileTransferInfo.FileName, localFilePath); } this.fileHelper.CopyFile(fileTransferInfo.FileName, localFilePath); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copied file {0} to {1}", fileTransferInfo.FileName, localFilePath); } } } catch (Exception ex) { this.LogError( ex.ToString(), uri, friendlyName, Guid.Parse(testCaseId)); throw; } }, this.cancellationTokenSource.Token); var continuationTask = task.ContinueWith( (t) => { try { if (t.Exception == null) { // Uri doesn't recognize file paths in unix. See https://github.com/dotnet/corefx/issues/1745 var attachmentUri = new UriBuilder() { Scheme = "file", Host = "", Path = localFilePath }.Uri; lock (attachmentTaskLock) { this.AttachmentSets[fileTransferInfo.Context][uri].Attachments.Add(new UriDataAttachment(attachmentUri, fileTransferInfo.Description)); } } sendFileCompletedCallback?.Invoke(this, new AsyncCompletedEventArgs(t.Exception, false, fileTransferInfo.UserToken)); } catch (Exception e) { if (EqtTrace.IsErrorEnabled) { EqtTrace.Error( "DataCollectionAttachmentManager.TriggerCallBack: Error occurred while raising the file transfer completed callback for {0}. Error: {1}", localFilePath, e.ToString()); } } }, this.cancellationTokenSource.Token); this.attachmentTasks[fileTransferInfo.Context].Add(continuationTask); }
/// <summary> /// Sends a file asynchronously. /// </summary> /// <param name="fileTransferInformation">Information about the file being transferred.</param> public override void SendFileAsync(FileTransferInformation fileTransferInformation) { ValidateArg.NotNull(fileTransferInformation, nameof(fileTransferInformation)); this.AttachmentManager.AddAttachment(fileTransferInformation, this.SendFileCompleted, this.DataCollectorConfig.TypeUri, this.DataCollectorConfig.FriendlyName); }
/// <summary> /// Called when Session End event is invoked /// </summary> /// <param name="sender">Sender</param> /// <param name="args">SessionEndEventArgs</param> private void SessionEndedHandler(object sender, SessionEndEventArgs args) { this.ResetInactivityTimer(); if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("Blame Collector : Session End"); } try { // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment if (this.testStartCount > this.testEndCount) { var filepath = Path.Combine(this.GetTempDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } if (this.collectProcessDumpOnTrigger) { // If there was a test case crash or if we need to collect dump on process exit. // // Do not try to collect dump when we already collected one from the hang dump // we won't dump the killed process again and that would just show a warning on the command line if ((this.testStartCount > this.testEndCount || this.collectDumpAlways) && !this.dumpWasCollectedByHangDumper) { try { var dumpFile = this.processDumpUtility.GetDumpFile(); if (!string.IsNullOrEmpty(dumpFile)) { var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true); this.dataCollectionSink.SendFileAsync(fileTranferInformation); } else { EqtTrace.Warning("BlameCollector.SessionEndedHandler: blame:CollectDump was enabled but dump file was not generated."); this.logger.LogWarning(args.Context, Resources.Resources.ProcDumpNotGenerated); } } catch (FileNotFoundException ex) { EqtTrace.Warning(ex.ToString()); this.logger.LogWarning(args.Context, ex.ToString()); } } } } finally { // Attempt to terminate the proc dump process if proc dump was enabled if (this.collectProcessDumpOnTrigger) { this.processDumpUtility.DetachFromTargetProcess(this.testHostProcessId); } this.DeregisterEvents(); } }