Skip to content

Commit

Permalink
Enabled Diag logging for DataCollector (#589)
Browse files Browse the repository at this point in the history
* Enabled Diag logging.

* Refactored code to fix DRY violation.

* nit changes.

* PR feedback.

* Added verification for diag files.
  • Loading branch information
harshjain2 committed Mar 16, 2017
1 parent 4cef686 commit 342062c
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 174 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers
{
using System.Collections.Generic;

/// <summary>
/// Helper class for processing arguments passed to a process.
/// </summary>
public class CommandLineArgumentsHelper
{
/// <summary>
/// Parse command line arguments to a dictionary.
/// </summary>
/// <param name="args">Command line arguments. Ex: <c>{ "--port", "12312", "--parentprocessid", "2312", "--testsourcepath", "C:\temp\1.dll" }</c></param>
/// <returns>Dictionary of arguments keys and values.</returns>
public static IDictionary<string, string> GetArgumentsDictionary(string[] args)
{
var argsDictionary = new Dictionary<string, string>();
if (args == null)
{
return argsDictionary;
}

for (int i = 0; i < args.Length; i++)
{
if (args[i].StartsWith("-"))
{
if (i < args.Length - 1 && !args[i + 1].StartsWith("-"))
{
argsDictionary.Add(args[i], args[i + 1]);
i++;
}
else
{
argsDictionary.Add(args[i], null);
}
}
}

return argsDictionary;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;

using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces;
Expand All @@ -24,6 +26,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection
internal class ProxyDataCollectionManager : IProxyDataCollectionManager
{
private const string PortOption = "--port";
private const string DiagOption = "--diag";

private IDataCollectionRequestSender dataCollectionRequestSender;
private IDataCollectionLauncher dataCollectionLauncher;
Expand Down Expand Up @@ -216,7 +219,20 @@ private IList<string> GetCommandLineArguments(int portNumber)
commandlineArguments.Add(PortOption);
commandlineArguments.Add(portNumber.ToString());

if (!string.IsNullOrEmpty(EqtTrace.LogFile))
{
commandlineArguments.Add(DiagOption);
commandlineArguments.Add(this.GetTimestampedLogFile(EqtTrace.LogFile));
}

return commandlineArguments;
}

private string GetTimestampedLogFile(string logFile)
{
return Path.ChangeExtension(logFile,
string.Format("datacollector.{0}_{1}{2}", DateTime.Now.ToString("yy-MM-dd_HH-mm-ss_fffff"),
Thread.CurrentThread.ManagedThreadId, Path.GetExtension(logFile)));
}
}
}
60 changes: 31 additions & 29 deletions src/datacollector/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ namespace Microsoft.VisualStudio.TestPlatform.DataCollector
using System.Diagnostics;
using System.Net.Sockets;

using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection;
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using Microsoft.VisualStudio.TestPlatform.Utilities;

/// <summary>
/// The program.
Expand All @@ -23,9 +25,14 @@ public class Program
private const int ClientListenTimeOut = 5 * 1000;

/// <summary>
/// Port where vstest.console is listening
/// Port number used to communicate with test runner process.
/// </summary>
private const string PortArgument = "--port";

/// <summary>
/// Log file for writing eqt trace logs.
/// </summary>
private static int port;
private const string LogFileArgument = "--diag";

/// <summary>
/// The main.
Expand All @@ -37,9 +44,8 @@ public static void Main(string[] args)
{
try
{
ParseArgs(args);
WaitForDebuggerIfEnabled();
Run();
Run(args);
}
catch (SocketException ex)
{
Expand All @@ -51,39 +57,35 @@ public static void Main(string[] args)
}
}

/// <summary>
/// Parse args.
/// </summary>
/// <param name="args">The args.</param>
private static void ParseArgs(string[] args)
private static void Run(string[] args)
{
port = -1;
var argsDictionary = CommandLineArgumentsHelper.GetArgumentsDictionary(args);
var requestHandler = DataCollectionRequestHandler.Create(new SocketCommunicationManager(), new MessageSink());

for (var i = 0; i < args.Length; i++)
// Setup logging if enabled
string logFile;
if (argsDictionary.TryGetValue(LogFileArgument, out logFile))
{
if (string.Equals("--port", args[i], StringComparison.OrdinalIgnoreCase) || string.Equals("-p", args[i], StringComparison.OrdinalIgnoreCase))
{
if (i < args.Length - 1)
{
int.TryParse(args[i + 1], out port);
}

break;
}
EqtTrace.InitializeVerboseTrace(logFile);
}

if (port < 0)
// Get server port and initialize communication.
string portValue;
int port = argsDictionary.TryGetValue(PortArgument, out portValue) ? int.Parse(portValue) : 0;

if (port <= 0)
{
throw new ArgumentException("Incorrect/No Port number");
}
}

private static void Run()
{
var requestHandler = DataCollectionRequestHandler.Create(new SocketCommunicationManager(), new MessageSink());

requestHandler.InitializeCommunication(port);

// Can only do this after InitializeCommunication because datacollector cannot "Send Log" unless communications are initialized
if (!string.IsNullOrEmpty(EqtTrace.LogFile))
{
requestHandler.SendDataCollectionMessage(new DataCollectionMessageEventArgs(TestMessageLevel.Informational, string.Format("Logging DataCollector Diagnostics in file: {0}", EqtTrace.LogFile)));
}

// Wait for the connection to the sender and start processing requests from sender
if (requestHandler.WaitForRequestSenderConnection(ClientListenTimeOut))
{
Expand All @@ -95,7 +97,7 @@ private static void Run()
requestHandler.Close();
throw new TimeoutException();
}
}
}

private static void WaitForDebuggerIfEnabled()
{
Expand Down
30 changes: 2 additions & 28 deletions src/testhost.x86/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.VisualStudio.TestPlatform.TestHost

using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing;

/// <summary>
Expand Down Expand Up @@ -44,7 +45,7 @@ public static void Main(string[] args)

private static void Run(string[] args)
{
var argsDictionary = GetArguments(args);
var argsDictionary = CommandLineArgumentsHelper.GetArgumentsDictionary(args);
// Invoke the engine with arguments
GetEngineInvoker(argsDictionary).Invoke(argsDictionary);
}
Expand Down Expand Up @@ -72,33 +73,6 @@ private static IEngineInvoker GetEngineInvoker(IDictionary<string, string> argsD
return invoker ?? new DefaultEngineInvoker();
}

/// <summary>
/// Parse command line arguments to a dictionary.
/// </summary>
/// <param name="args">Command line arguments. Ex: <c>{ "--port", "12312", "--parentprocessid", "2312", "--testsourcepath", "C:\temp\1.dll" }</c></param>
/// <returns>Dictionary of arguments keys and values.</returns>
private static IDictionary<string, string> GetArguments(string[] args)
{
IDictionary<string, string> argsDictionary = new Dictionary<string, string>();
for (int i = 0; i < args.Length; i++)
{
if (args[i].StartsWith("-"))
{
if (i < args.Length - 1 && !args[i + 1].StartsWith("-"))
{
argsDictionary.Add(args[i], args[i + 1]);
i++;
}
else
{
argsDictionary.Add(args[i], null);
}
}
}

return argsDictionary;
}

private static void WaitForDebuggerIfEnabled()
{
var debugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_DEBUG");
Expand Down
72 changes: 40 additions & 32 deletions test/Microsoft.TestPlatform.AcceptanceTests/DataCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public DataCollectionTests()
[TestCleanup]
public void Cleanup()
{
Directory.Delete(resultsDir, true);
Directory.Delete(this.resultsDir, true);
}

[CustomDataTestMethod]
Expand All @@ -37,42 +37,18 @@ public void ExecuteTestsWithDataCollection(string runnerFramework, string target
AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerFramework, targetFramework, targetRuntime);

var assemblyPaths = this.BuildMultipleAssemblyPath("SimpleTestProject2.dll").Trim('\"');
string runSettings = GetRunsettingsFilePath();
string runSettings = this.GetRunsettingsFilePath();
string diagFileName = Path.Combine(this.resultsDir, "diaglog.txt");

var arguments = PrepareArguments(assemblyPaths, this.GetTestAdapterPath(), runSettings, this.FrameworkArgValue);
arguments = string.Concat(arguments, $" /ResultsDirectory:{resultsDir}");
arguments = string.Concat(arguments, $" /ResultsDirectory:{resultsDir}", $" /Diag:{diagFileName}");
this.InvokeVsTest(arguments);

this.ValidateSummaryStatus(1, 1, 1);
this.VaildateDataCollectorOutput();
}

private string GetRunsettingsFilePath()
{
var runsettingsPath = Path.Combine(
Path.GetTempPath(),
"test_" + Guid.NewGuid() + ".runsettings");
var dataCollectionAttributes = new Dictionary<string, string>();

dataCollectionAttributes.Add("friendlyName", "SampleDataCollector");
dataCollectionAttributes.Add("uri", "my://sample/datacollector");
var codebase = Path.Combine(
this.testEnvironment.TestAssetsPath,
Path.GetFileNameWithoutExtension("OutOfProcDataCollector"),
"bin",
this.testEnvironment.BuildConfiguration,
this.testEnvironment.RunnerFramework,
"OutOfProcDataCollector.dll");

var outOfProcAssemblyPath = this.testEnvironment.GetTestAsset("OutOfProcDataCollector.dll");

dataCollectionAttributes.Add("assemblyQualifiedName", string.Format("OutOfProcDataCollector.SampleDataCollector, {0}", AssemblyUtility.GetAssemblyName(outOfProcAssemblyPath)));
dataCollectionAttributes.Add("codebase", codebase);
CreateDataCollectionRunSettingsFile(runsettingsPath, dataCollectionAttributes);
return runsettingsPath;
}

public static void CreateDataCollectionRunSettingsFile(string destinationRunsettingsPath, Dictionary<string, string> dataCollectionAttributes)
private static void CreateDataCollectionRunSettingsFile(string destinationRunsettingsPath, Dictionary<string, string> dataCollectionAttributes)
{
var doc = new XmlDocument();
var xmlDeclaration = doc.CreateNode(XmlNodeType.XmlDeclaration, string.Empty, string.Empty);
Expand All @@ -98,7 +74,7 @@ public static void CreateDataCollectionRunSettingsFile(string destinationRunsett
}
}

public void VaildateDataCollectorOutput()
private void VaildateDataCollectorOutput()
{
// Output of datacollection attachment.
this.StdOutputContains("filename.txt");
Expand All @@ -110,8 +86,9 @@ public void VaildateDataCollectorOutput()
this.StdErrorContains("Diagnostic data adapter caught an exception of type 'System.Exception': 'my exception'. More details: .");

// Verify attachments
bool isTestRunLevelAttachmentFound = false;
int testCaseLevelAttachmentsCount = 0;
var isTestRunLevelAttachmentFound = false;
var testCaseLevelAttachmentsCount = 0;
var diaglogsFileCount = 0;

var resultFiles = Directory.GetFiles(this.resultsDir, "*.txt", SearchOption.AllDirectories);

Expand All @@ -128,10 +105,41 @@ public void VaildateDataCollectorOutput()
{
testCaseLevelAttachmentsCount++;
}

if (file.Contains("diaglog"))
{
diaglogsFileCount++;
}
}

Assert.IsTrue(isTestRunLevelAttachmentFound);
Assert.AreEqual(3, testCaseLevelAttachmentsCount);
Assert.AreEqual(3, diaglogsFileCount);
}

private string GetRunsettingsFilePath()
{
var runsettingsPath = Path.Combine(
Path.GetTempPath(),
"test_" + Guid.NewGuid() + ".runsettings");
var dataCollectionAttributes = new Dictionary<string, string>();

dataCollectionAttributes.Add("friendlyName", "SampleDataCollector");
dataCollectionAttributes.Add("uri", "my://sample/datacollector");
var codebase = Path.Combine(
this.testEnvironment.TestAssetsPath,
Path.GetFileNameWithoutExtension("OutOfProcDataCollector"),
"bin",
this.testEnvironment.BuildConfiguration,
this.testEnvironment.RunnerFramework,
"OutOfProcDataCollector.dll");

var outOfProcAssemblyPath = this.testEnvironment.GetTestAsset("OutOfProcDataCollector.dll");

dataCollectionAttributes.Add("assemblyQualifiedName", string.Format("OutOfProcDataCollector.SampleDataCollector, {0}", AssemblyUtility.GetAssemblyName(outOfProcAssemblyPath)));
dataCollectionAttributes.Add("codebase", codebase);
CreateDataCollectionRunSettingsFile(runsettingsPath, dataCollectionAttributes);
return runsettingsPath;
}
}
}
Loading

0 comments on commit 342062c

Please sign in to comment.