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

Map incoming and outgoing requests #3314

Merged
merged 15 commits into from
Feb 22, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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.CommunicationUtilities;

/// <summary>
/// This interface holds additional values for a request handler when rewriting paths is used.
/// This is in case when --local-path and --remote-path parameters are provided and testhost is running
/// in a remote deployment. This interface is used only to avoid changes to public API of TestRequestHandler.
/// </summary>
internal interface IDeploymentAwareTestRequestHandler
{
string LocalPath { get; set; }
string RemotePath { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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.CommunicationUtilities;

using System.Collections.Generic;
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
using System.Collections.ObjectModel;

using ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;

internal interface IPathConverter
{
string? UpdatePath(string? path, PathConversionDirection updateDirection);

IEnumerable<string?> UpdatePaths(IEnumerable<string?> paths, PathConversionDirection updateDirection);

TestCase UpdateTestCase(TestCase testCase, PathConversionDirection updateDirection);

IEnumerable<TestCase> UpdateTestCases(IEnumerable<TestCase> testCases, PathConversionDirection updateDirection);

TestRunCompleteEventArgs UpdateTestRunCompleteEventArgs(TestRunCompleteEventArgs testRunCompleteEventArgs, PathConversionDirection updateDirection);

TestRunChangedEventArgs UpdateTestRunChangedEventArgs(TestRunChangedEventArgs testRunChangedArgs, PathConversionDirection updateDirection);

Collection<AttachmentSet> UpdateAttachmentSets(Collection<AttachmentSet> attachmentSets, PathConversionDirection updateDirection);

ICollection<AttachmentSet> UpdateAttachmentSets(ICollection<AttachmentSet> attachmentSets, PathConversionDirection updateDirection);
Evangelink marked this conversation as resolved.
Show resolved Hide resolved

DiscoveryCriteria UpdateDiscoveryCriteria(DiscoveryCriteria discoveryCriteria, PathConversionDirection updateDirection);

TestRunCriteriaWithSources UpdateTestRunCriteriaWithSources(TestRunCriteriaWithSources testRunCriteriaWithSources, PathConversionDirection updateDirection);

TestRunCriteriaWithTests UpdateTestRunCriteriaWithTests(TestRunCriteriaWithTests testRunCriteriaWithTests, PathConversionDirection updateDirection);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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.CommunicationUtilities;

using System.Collections.Generic;
using ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using System.Collections.ObjectModel;
using System;

internal class NullPathConverter : IPathConverter
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
{
private static readonly Lazy<NullPathConverter> LazyInstance = new(() => new NullPathConverter());

private NullPathConverter() { }

public static NullPathConverter Instance => LazyInstance.Value;

Collection<AttachmentSet> IPathConverter.UpdateAttachmentSets(Collection<AttachmentSet> attachmentSets, PathConversionDirection _) => attachmentSets;

ICollection<AttachmentSet> IPathConverter.UpdateAttachmentSets(ICollection<AttachmentSet> attachmentSets, PathConversionDirection _) => attachmentSets;

DiscoveryCriteria IPathConverter.UpdateDiscoveryCriteria(DiscoveryCriteria discoveryCriteria, PathConversionDirection _) => discoveryCriteria;

string? IPathConverter.UpdatePath(string? path, PathConversionDirection _) => path;

IEnumerable<string?> IPathConverter.UpdatePaths(IEnumerable<string?> paths, PathConversionDirection _) => paths;

TestCase IPathConverter.UpdateTestCase(TestCase testCase, PathConversionDirection _) => testCase;

IEnumerable<TestCase> IPathConverter.UpdateTestCases(IEnumerable<TestCase> testCases, PathConversionDirection _) => testCases;

TestRunChangedEventArgs IPathConverter.UpdateTestRunChangedEventArgs(TestRunChangedEventArgs testRunChangedArgs, PathConversionDirection _) => testRunChangedArgs;

TestRunCompleteEventArgs IPathConverter.UpdateTestRunCompleteEventArgs(TestRunCompleteEventArgs testRunCompleteEventArgs, PathConversionDirection _) => testRunCompleteEventArgs;

TestRunCriteriaWithSources IPathConverter.UpdateTestRunCriteriaWithSources(TestRunCriteriaWithSources testRunCriteriaWithSources, PathConversionDirection _) => testRunCriteriaWithSources;

TestRunCriteriaWithTests IPathConverter.UpdateTestRunCriteriaWithTests(TestRunCriteriaWithTests testRunCriteriaWithTests, PathConversionDirection _) => testRunCriteriaWithTests;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// 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.CommunicationUtilities;

internal enum PathConversionDirection
{
Receive,
Send
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// 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.CommunicationUtilities;

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.IO;

using ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;

/// <summary>
/// Converts paths in received and sent objects, to make testhost seem like it run a local test,
/// while it was in fact running a test on a remote system, in a totally different path. This is for UWP which
/// does testhost deployment.
/// The modifications here rely on combination of side-effects, and actually replacing the values, because
/// we cannot modify the properties on our public objects, and add setters.
/// </summary>
internal class PathConverter : IPathConverter
{
// The path on this computer to which we deployed the test dll and test runner
private readonly string _deploymentPath = "";
// The path on the remote system where test dll was originally placed, and from which we
// copied it to this system. For vstest.console, which is on the other side of this, the names
// are inverted, it sends us their local path, and thinks about our local path as remote.
private readonly string _originalPath = "";

public PathConverter(string originalPath!!, string deploymentPath!!, IFileHelper fileHelper!!)
{
_originalPath = fileHelper.GetFullPath(originalPath).TrimEnd('\\').TrimEnd('/') + Path.DirectorySeparatorChar;
_deploymentPath = fileHelper.GetFullPath(deploymentPath).TrimEnd('\\').TrimEnd('/') + Path.DirectorySeparatorChar;
}

public string? UpdatePath(string? path, PathConversionDirection updateDirection)
{
if (path == null)
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
return path;

string find;
string replaceWith;
if (updateDirection == PathConversionDirection.Receive)
{
// Request is incoming, the path that is local to the sender (for us that is "remote" path)
// needs to be replaced with our path
find = _originalPath;
replaceWith = _deploymentPath;
}
else
{
find = _deploymentPath;
replaceWith = _originalPath;
}

var result = path?.Replace(find, replaceWith);
return result;
}

public IEnumerable<string?> UpdatePaths(IEnumerable<string?> paths!!, PathConversionDirection updateDirection)
{
return paths.Select(i => UpdatePath(i, updateDirection)).ToList();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to match same style as other implementations:

Suggested change
return paths.Select(i => UpdatePath(i, updateDirection)).ToList();
paths.ToList().ForEach(i => UpdatePath(i, updateDirection));
return paths;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would not work, strings are immutable, so you would create a new string and output it to null, so the original string would not be updated.

}

public TestCase UpdateTestCase(TestCase testCase!!, PathConversionDirection updateDirection)
{
testCase.CodeFilePath = UpdatePath(testCase.CodeFilePath, updateDirection);
testCase.Source = UpdatePath(testCase.Source, updateDirection);
return testCase;
}

public IEnumerable<TestCase> UpdateTestCases(IEnumerable<TestCase> testCases!!, PathConversionDirection updateDirection)
{
testCases.ToList().ForEach(tc => UpdateTestCase(tc, updateDirection));
return testCases;
}

public TestRunCompleteEventArgs UpdateTestRunCompleteEventArgs(TestRunCompleteEventArgs testRunCompleteEventArgs!!, PathConversionDirection updateDirection)
{
UpdateAttachmentSets(testRunCompleteEventArgs.AttachmentSets, updateDirection);
return testRunCompleteEventArgs;
}

public TestRunChangedEventArgs UpdateTestRunChangedEventArgs(TestRunChangedEventArgs testRunChangedArgs!!, PathConversionDirection updateDirection)
{
UpdateTestResults(testRunChangedArgs.NewTestResults, updateDirection);
UpdateTestCases(testRunChangedArgs.ActiveTests, updateDirection);
return testRunChangedArgs;
}

public Collection<AttachmentSet> UpdateAttachmentSets(Collection<AttachmentSet> attachmentSets!!, PathConversionDirection updateDirection)
{
attachmentSets.ToList().ForEach(i => UpdateAttachmentSet(i, updateDirection));
return attachmentSets;
}

public ICollection<AttachmentSet> UpdateAttachmentSets(ICollection<AttachmentSet> attachmentSets!!, PathConversionDirection updateDirection)
{
attachmentSets.ToList().ForEach(i => UpdateAttachmentSet(i, updateDirection));
return attachmentSets;
}

private AttachmentSet UpdateAttachmentSet(AttachmentSet attachmentSet!!, PathConversionDirection updateDirection)
{
attachmentSet.Attachments.ToList().ForEach(a => UpdateAttachment(a, updateDirection));
return attachmentSet;
}

private UriDataAttachment UpdateAttachment(UriDataAttachment attachment!!, PathConversionDirection _)
{
// todo: convert uri? https://github.com/microsoft/vstest/issues/3367
return attachment;
}

private IEnumerable<TestResult> UpdateTestResults(IEnumerable<TestResult> testResults!!, PathConversionDirection updateDirection)
{
foreach (var tr in testResults)
{
UpdateAttachmentSets(tr.Attachments, updateDirection);
UpdateTestCase(tr.TestCase, updateDirection);
}
return testResults;
}

public DiscoveryCriteria UpdateDiscoveryCriteria(DiscoveryCriteria discoveryCriteria!!, PathConversionDirection updateDirection)
{
discoveryCriteria.Package = UpdatePath(discoveryCriteria.Package, updateDirection);
foreach (var adapter in discoveryCriteria.AdapterSourceMap.ToList())
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
{
var updatedPaths = UpdatePaths(adapter.Value, updateDirection);
discoveryCriteria.AdapterSourceMap[adapter.Key] = updatedPaths;
}
return discoveryCriteria;
}

public TestRunCriteriaWithSources UpdateTestRunCriteriaWithSources(TestRunCriteriaWithSources testRunCriteriaWithSources!!, PathConversionDirection updateDirection)
{
testRunCriteriaWithSources.AdapterSourceMap.ToList().ForEach(adapter => testRunCriteriaWithSources.AdapterSourceMap[adapter.Key] = UpdatePaths(adapter.Value, updateDirection));
var package = UpdatePath(testRunCriteriaWithSources.Package, updateDirection);
return new TestRunCriteriaWithSources(testRunCriteriaWithSources.AdapterSourceMap, package, testRunCriteriaWithSources.RunSettings, testRunCriteriaWithSources.TestExecutionContext);
}

public TestRunCriteriaWithTests UpdateTestRunCriteriaWithTests(TestRunCriteriaWithTests testRunCriteriaWithTests!!, PathConversionDirection updateDirection)
{
var tests = UpdateTestCases(testRunCriteriaWithTests.Tests, updateDirection);
var package = UpdatePath(testRunCriteriaWithTests.Package, updateDirection);
return new TestRunCriteriaWithTests(tests, package, testRunCriteriaWithTests.RunSettings, testRunCriteriaWithTests.TestExecutionContext);
}
}
Loading