Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed TRX file overwrite in certain circumstances #2508

Merged
16 commits merged into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@
</trans-unit>
</body>
</file>
</xliff>
</xliff>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,7 @@ Error Details: {1}:{2}</value>
<data name="PrefixAndNameProvidedError" xml:space="preserve">
<value>The parameters LogFileName and LogFilePrefix cannot be used together. </value>
</data>
<data name="Common_CannotGetNextTimestampFileName" xml:space="preserve">
<value>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Parametry LogFileName a LogFilePrefix nejde použít společně. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Die Parameter "LogFileName" und "LogFilePrefix" können nicht zusammen verwendet werden. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Los parámetros LogFileName y LogFilePrefix no se pueden usar juntos. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Les paramètres LogFileName et LogFilePrefix ne peuvent pas être utilisés ensemble. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Non è possibile usare insieme i parametri LogFileName e LogFilePrefix. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">パラメーター LogFileName と LogFilePrefix を同時に使用することはできません。</target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">LogFileName 및 LogFilePrefix 매개 변수는 함께 사용할 수 없습니다. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Parametry LogFileName i LogFilePrefix nie mogą być używane razem. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Os parâmetros LogFileName e LogFilePrefix não podem ser usados juntos. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">Параметры LogFileName и LogFilePrefix недопустимо использовать вместе. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">LogFileName ve LogFilePrefix parametreleri birlikte kullanılamaz. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="translated">"{1}" altında "{2}" biçimlendirmesi ve "{0}" ismi kullanılarak müsait bir dosya adı bulunamadı.</target>
Haplois marked this conversation as resolved.
Show resolved Hide resolved
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ Error Details: {1}:{2}</source>
<target state="new">The parameters LogFileName and LogFilePrefix cannot be given together. </target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">参数 LogFileName 和 LogFilePrefix 不能一起使用。</target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ Fehlerdetails: {1}: {2}</target>
<target state="translated">不能同時使用參數 LogFileName 和 LogFilePrefix。</target>
<note></note>
</trans-unit>
<trans-unit id="Common_CannotGetNextTimestampFileName">
<source>Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</source>
<target state="new">Cannot get find an available filename for {0} using timestamp format '{2}' at {1}.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>
52 changes: 31 additions & 21 deletions src/Microsoft.TestPlatform.Extensions.TrxLogger/TrxLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

namespace Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger
{
using Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
using Microsoft.TestPlatform.Extensions.TrxLogger.Utility;
using Microsoft.TestPlatform.Extensions.TrxLogger.XML;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
using NuGet.Frameworks;
using ObjectModel.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
Expand All @@ -11,17 +20,8 @@ namespace Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
using Microsoft.TestPlatform.Extensions.TrxLogger.Utility;
using Microsoft.TestPlatform.Extensions.TrxLogger.XML;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using NuGet.Frameworks;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
using ObjectModel.Logging;
using TrxLoggerConstants = Microsoft.TestPlatform.Extensions.TrxLogger.Utility.Constants;
using TrxLoggerObjectModel = Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
using TrxLoggerResources = Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger.Resources.TrxResource;
Expand All @@ -40,8 +40,8 @@ public class TrxLogger : ITestLoggerWithParameters
/// <summary>
/// Initializes a new instance of the <see cref="TrxLogger"/> class.
/// </summary>
public TrxLogger():
this (new Utilities.Helpers.FileHelper())
public TrxLogger() :
this(new Utilities.Helpers.FileHelper())
{
}

Expand All @@ -65,6 +65,10 @@ protected TrxLogger(IFileHelper fileHelper)
// The converter class
private Converter converter;


private const int MutexTimeout = 120 * 1000;
private static readonly Mutex createLogFileMutex = new Mutex(initiallyOwned: false, "Global\\Microsoft.TestPlatform.Extensions.TrxLogger.PopulateTrxFile");

private TrxLoggerObjectModel.TestRun testRun;
private ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestResult> results;
private ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestElement> testElements;
Expand Down Expand Up @@ -389,9 +393,17 @@ internal void TestRunCompleteHandler(object sender, TestRunCompleteEventArgs e)

helper.SaveObject(runSummary, rootElement, "ResultSummary", parameters);

//Save results to Trx file
this.DeriveTrxFilePath();
this.PopulateTrxFile(this.trxFilePath, rootElement);
EqtAssert.IsTrue(createLogFileMutex.WaitOne(MutexTimeout), "Cannot acquire the global file population mutex.");
Haplois marked this conversation as resolved.
Show resolved Hide resolved
try
{
//Save results to Trx file
this.DeriveTrxFilePath();
this.PopulateTrxFile(this.trxFilePath, rootElement);
}
finally
{
createLogFileMutex.ReleaseMutex();
}
}

/// <summary>
Expand Down Expand Up @@ -446,7 +458,7 @@ private void InitializeInternal()
this.results = new ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestResult>();
this.innerResults = new ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestResult>();
this.testElements = new ConcurrentDictionary<Guid, ITestElement>();
this.entries = new ConcurrentDictionary<Guid,TestEntry>();
this.entries = new ConcurrentDictionary<Guid, TestEntry>();
this.innerTestEntries = new ConcurrentDictionary<Guid, TestEntry>();
this.runLevelErrorsAndWarnings = new List<RunInfo>();
this.testRun = null;
Expand Down Expand Up @@ -487,17 +499,15 @@ private void DeriveTrxFilePath()

if (isLogFilePrefixParameterExists)
{
if (!string.IsNullOrWhiteSpace(logFilePrefixValue))
if (!string.IsNullOrWhiteSpace(logFilePrefixValue))
{
var framework = this.parametersDictionary[DefaultLoggerParameterNames.TargetFramework];
if (framework != null)
if (this.parametersDictionary.TryGetValue(DefaultLoggerParameterNames.TargetFramework, out var framework) && framework != null)
{
framework = NuGetFramework.Parse(framework).GetShortFolderName();
logFilePrefixValue = logFilePrefixValue + "_" + framework;
}

logFilePrefixValue = logFilePrefixValue + DateTime.Now.ToString("_yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo) + this.trxFileExtension;
this.trxFilePath = Path.Combine(this.testResultsDirPath, logFilePrefixValue);
this.trxFilePath = Microsoft.TestPlatform.Extensions.TrxLogger.Utility.FileHelper.GetNextTimestampFileName(this.testResultsDirPath, logFilePrefixValue + this.trxFileExtension, "_yyyyMMddHHmmss");
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.TestPlatform.Extensions.TrxLogger.Utility
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

using System.Threading;
using TrxLoggerResources = Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger.Resources.TrxResource;

/// <summary>
Expand Down Expand Up @@ -133,6 +133,45 @@ public static string GetNextIterationFileName(string parentDirectoryName, string
return GetNextIterationNameHelper(parentDirectoryName, originalFileName, new FileIterationHelper(checkMatchingDirectory));
}

/// <summary>
/// Constructs and returns first available timestamped file name.
/// This does not checks for the file permissions.
/// </summary>
/// <param name="directoryName">Directory to try timestamped file names in.</param>
/// <param name="fileName">Filename (with extension) of the desired file. Timestamp will be added just before extension.</param>
/// <param name="timestampFormat">Timestamp format to be passed into DateTime.ToString method.</param>
/// <returns>First available filename with the format of `FileName{Timestamp}.ext`.</returns>
/// <example>
/// <code>GetNextTimestampFileName("c:\data", "log.txt", "_yyyyMMddHHmmss")</code> will return "c:\data\log_20200801185521.txt", if available.
/// </example>
public static string GetNextTimestampFileName(string directoryName, string fileName, string timestampFormat)
{
EqtAssert.StringNotNullOrEmpty(directoryName, "parentDirectoryName");
EqtAssert.StringNotNullOrEmpty(fileName, "fileName");
EqtAssert.StringNotNullOrEmpty(timestampFormat, "timestampFormat");

uint iteration = 0;
var iterationStamp = DateTime.Now;
var fileNamePrefix = Path.GetFileNameWithoutExtension(fileName);
var extension = Path.GetExtension(fileName);
do
{
var tryMe = fileNamePrefix + iterationStamp.ToString(timestampFormat, DateTimeFormatInfo.InvariantInfo) + extension;

string tryMePath = Path.Combine(directoryName, tryMe);
if (!File.Exists(tryMePath))
{
return tryMePath;
}

iterationStamp = iterationStamp.AddSeconds(1);
++iteration;
}
while (iteration <= ushort.MaxValue);
Haplois marked this conversation as resolved.
Show resolved Hide resolved

throw new Exception(string.Format(CultureInfo.CurrentCulture, TrxLoggerResources.Common_CannotGetNextTimestampFileName, fileName, directoryName, timestampFormat));
}

public static string MakePathRelative(string path, string basePath)
{
EqtAssert.StringNotNullOrEmpty(path, "path");
Expand Down Expand Up @@ -278,6 +317,7 @@ private static string GetNextIterationNameHelper(
Debug.Assert(!string.IsNullOrEmpty(originalName), "originalName is Null");
Debug.Assert(helper != null, "helper is null");

var rng = new Random();
Haplois marked this conversation as resolved.
Show resolved Hide resolved
uint iteration = 0;
do
{
Expand All @@ -289,6 +329,8 @@ private static string GetNextIterationNameHelper(
return tryMePath;
}

// Sleep a random amount before trying the next iteration
Thread.Sleep(rng.Next(1, 150));
Haplois marked this conversation as resolved.
Show resolved Hide resolved
++iteration;
}
while (iteration != uint.MaxValue);
Expand Down
Loading