-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for record/playback on tests
- Loading branch information
Showing
74 changed files
with
6,236 additions
and
441 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
Push-Location | ||
|
||
dotnet test "$PSScriptRoot/../src/WinRMSharp.Tests/" --framework net7.0 --collect:"XPlat Code Coverage" | ||
dotnet test "$PSScriptRoot/../src/WinRMSharp.Tests/" --framework net7.0 --filter "Category!=Integration" --collect:"XPlat Code Coverage" | ||
|
||
$coverageFiles = Get-ChildItem -Path "$PSScriptRoot/../**/coverage.cobertura.xml" -Recurse | ||
$coverageFiles = $coverageFiles | Sort-Object -Property LastWriteTime -Descending | ||
|
||
$latestCoverageFile = $coverageFiles[0] | ||
|
||
reportgenerator.exe -reports:$latestCoverageFile -targetdir:"$PSScriptRoot/../coveragereport" -reporttypes:Html | ||
reportgenerator.exe -reports:$latestCoverageFile -targetdir:"$PSScriptRoot/../coveragereport" -reporttypes:Html | ||
|
||
Invoke-Expression "$PSScriptRoot/../coveragereport\index.html" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
dotnet test "$PSScriptRoot/../src/WinRMSharp.Tests/" --framework net7.0 --filter "Category!=Integration" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
using Xunit; | ||
|
||
namespace WinRMSharp.IntegrationTests | ||
{ | ||
public abstract class BaseProtocolTests | ||
{ | ||
[Fact] | ||
public async Task OpenCloseShell() | ||
{ | ||
Protocol protocol = GenerateProtocol(nameof(OpenCloseShell)); | ||
|
||
string shellId = await protocol.OpenShell(); | ||
await protocol.CloseShell(shellId); | ||
|
||
Assert.Matches(@"^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$", shellId); | ||
} | ||
|
||
[Fact] | ||
public async Task RunCommandWithArgsAndCleanup() | ||
{ | ||
Protocol protocol = GenerateProtocol(nameof(RunCommandWithArgsAndCleanup)); | ||
|
||
string shellId = await protocol.OpenShell(); | ||
string commandId = await protocol.RunCommand(shellId, "ipconfig", new string[] { "/all" }); | ||
|
||
await protocol.CloseCommand(shellId, commandId); | ||
await protocol.CloseShell(shellId); | ||
|
||
Assert.Matches(@"^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$", commandId); | ||
} | ||
|
||
[Fact] | ||
public async Task RunCommandWithoutArgsAndCleanup() | ||
{ | ||
Protocol protocol = GenerateProtocol(nameof(RunCommandWithoutArgsAndCleanup)); | ||
|
||
string shellId = await protocol.OpenShell(); | ||
string commandId = await protocol.RunCommand(shellId, "hostname"); | ||
|
||
await protocol.CloseCommand(shellId, commandId); | ||
await protocol.CloseShell(shellId); | ||
|
||
Assert.Matches(@"^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$", commandId); | ||
} | ||
|
||
[Fact] | ||
public async Task RunCommandWithEnv() | ||
{ | ||
Protocol protocol = GenerateProtocol(nameof(RunCommandWithEnv)); | ||
|
||
Dictionary<string, string> envVars = new Dictionary<string, string>() | ||
{ | ||
{ "TESTENV1", "hi mom" }, | ||
{ "TESTENV2", "another var" } | ||
}; | ||
|
||
string shellId = await protocol.OpenShell(envVars: envVars); | ||
string commandId = await protocol.RunCommand(shellId, "echo", new string[] { "%TESTENV1%", "%TESTENV2%" }); | ||
|
||
CommandState state = await protocol.PollCommandState(shellId, commandId); | ||
|
||
await protocol.CloseCommand(shellId, commandId); | ||
await protocol.CloseShell(shellId); | ||
|
||
Assert.Matches(@"hi mom another var", state.Stdout); | ||
} | ||
|
||
[Fact] | ||
public async Task GetCommandState() | ||
{ | ||
Protocol protocol = GenerateProtocol(nameof(GetCommandState)); | ||
|
||
string shellId = await protocol.OpenShell(); | ||
string commandId = await protocol.RunCommand(shellId, "ipconfig", new string[] { "/all" }); | ||
|
||
CommandState state = await protocol.PollCommandState(shellId, commandId); | ||
|
||
await protocol.CloseCommand(shellId, commandId); | ||
await protocol.CloseShell(shellId); | ||
|
||
Assert.Equal(0, state.StatusCode); | ||
Assert.Contains(@"Windows IP Configuration", state.Stdout); | ||
Assert.Equal(0, state.Stderr.Length); | ||
} | ||
|
||
[Fact] | ||
public async Task RunCommandExceedingOperationTimeout() | ||
{ | ||
Protocol protocol = GenerateProtocol(nameof(RunCommandExceedingOperationTimeout)); | ||
|
||
string shellId = await protocol.OpenShell(); | ||
string commandId = await protocol.RunCommand(shellId, $"powershell -Command Start-Sleep -s {protocol.OperationTimeout.TotalSeconds * 2}"); | ||
|
||
CommandState state = await protocol.PollCommandState(shellId, commandId); | ||
|
||
await protocol.CloseCommand(shellId, commandId); | ||
await protocol.CloseShell(shellId); | ||
|
||
Assert.Equal(0, state.StatusCode); | ||
Assert.Equal(0, state.Stderr.Length); | ||
} | ||
|
||
public abstract Protocol GenerateProtocol(string sessionName); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/WinRMSharp.IntegrationTests/IntegrationProtocolTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Net; | ||
using WinRMSharp.IntegrationTests.Recording; | ||
|
||
namespace WinRMSharp.IntegrationTests | ||
{ | ||
public class IntegrationProtocolTests : BaseProtocolTests, IDisposable | ||
{ | ||
private SessionManager _sessionManager = new SessionManager(); | ||
|
||
public IntegrationProtocolTests() | ||
{ | ||
|
||
} | ||
|
||
public void Dispose() | ||
{ | ||
_sessionManager.Dispose(); | ||
} | ||
|
||
public override Protocol GenerateProtocol(string sessionName) | ||
{ | ||
string baseUrl = Environment.GetEnvironmentVariable("WINRM_BASE_URL") ?? throw new ArgumentNullException("WINRM_BASE_URL"); | ||
string username = Environment.GetEnvironmentVariable("WINRM_USERNAME") ?? throw new ArgumentNullException("WINRM_USERNAME"); | ||
string password = Environment.GetEnvironmentVariable("WINRM_PASSWORD") ?? throw new ArgumentNullException("WINRM_PASSWORD"); | ||
|
||
SessionHandler handler = _sessionManager.GenerateSessionHandler(State.Recording, sessionName); | ||
|
||
ICredentials credentials = new NetworkCredential(username, password); | ||
ITransport transport = new Transport(baseUrl, handler, credentials); | ||
|
||
ProtocolOptions protocolOptions = new ProtocolOptions() | ||
{ | ||
OperationTimeout = TimeSpan.FromSeconds(5) | ||
}; | ||
|
||
return new Protocol(transport, new IncrementingGuidProvider(), protocolOptions); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/WinRMSharp.IntegrationTests/Recording/PassThruHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace WinRMSharp.IntegrationTests.Recording | ||
{ | ||
internal class PassThruHandler : SessionHandler | ||
{ | ||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | ||
{ | ||
return await base.SendAsync(request, cancellationToken); | ||
} | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
src/WinRMSharp.IntegrationTests/Recording/PlaybackHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using System.Net; | ||
using System.Xml.Linq; | ||
using WinRMSharp.Utils; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace WinRMSharp.IntegrationTests.Recording | ||
{ | ||
internal class PlaybackHandler : SessionHandler | ||
{ | ||
private int _playbackIndex = 0; | ||
private readonly List<Recording> _recordings = new List<Recording>(); | ||
|
||
private PlaybackHandler(List<Recording> recordings) | ||
{ | ||
_recordings = recordings; | ||
} | ||
|
||
public static PlaybackHandler Load(string sessionName) | ||
{ | ||
string path = Path.Join("sessions", $"{sessionName}.yml"); | ||
|
||
if (!File.Exists(path)) | ||
{ | ||
throw new FileNotFoundException($"Expected recording to exist at '{path}'"); | ||
} | ||
|
||
using StreamReader fileStream = File.OpenText(path); | ||
|
||
IDeserializer deserializer = new DeserializerBuilder().Build(); | ||
List<Recording> recordings = deserializer.Deserialize<List<Recording>>(fileStream); | ||
|
||
return new PlaybackHandler(recordings); | ||
} | ||
|
||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | ||
{ | ||
Recording recording = _recordings[_playbackIndex++]; | ||
|
||
XDocument? requestDocument = Xml.Parse(await request.Content!.ReadAsStringAsync(cancellationToken)); | ||
XDocument? recordingDocument = Xml.Parse(recording.Request.Body); | ||
|
||
if (!XNode.DeepEquals(requestDocument, recordingDocument)) | ||
{ | ||
throw new InvalidOperationException($"Expected '{requestDocument}' Actual: '{recordingDocument}'"); | ||
} | ||
|
||
HttpResponseMessage response = new HttpResponseMessage((HttpStatusCode)recording.Response.StatusCode) | ||
{ | ||
Content = new StringContent(recording.Response.Body!) | ||
}; | ||
|
||
foreach (KeyValuePair<string, string> kv in recording.Response.Headers) | ||
{ | ||
string key = kv.Key; | ||
string[] values = kv.Value.Split(';'); | ||
|
||
response.Headers.Add(key, values); | ||
} | ||
|
||
return response; | ||
} | ||
|
||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
src/WinRMSharp.IntegrationTests/Recording/RecordedRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
namespace WinRMSharp.IntegrationTests.Recording | ||
{ | ||
public class RecordedRequest | ||
{ | ||
public string Method { get; set; } | ||
public string? Url { get; set; } | ||
public Dictionary<string, string> Headers { get; set; } | ||
public string? Body { get; set; } | ||
|
||
public RecordedRequest() | ||
{ | ||
Method = string.Empty; | ||
Url = string.Empty; | ||
Headers = new Dictionary<string, string>(); | ||
Body = string.Empty; | ||
} | ||
|
||
public RecordedRequest(HttpRequestMessage requestMessage) | ||
{ | ||
Method = requestMessage.Method.Method; | ||
Url = requestMessage.RequestUri?.ToString(); | ||
Headers = ApplyFilters(requestMessage.Headers.ToDictionary(h => h.Key, h => string.Join(";", h.Value))); | ||
Body = requestMessage.Content?.ReadAsStringAsync().Result; | ||
} | ||
|
||
private static Dictionary<string, string> ApplyFilters(Dictionary<string, string> headers) | ||
{ | ||
HashSet<string> headersToFilter = new HashSet<string>() | ||
{ | ||
"Authorization" | ||
}; | ||
|
||
foreach (string headerToFilter in headersToFilter) | ||
{ | ||
if (!headers.ContainsKey(headerToFilter)) | ||
continue; | ||
|
||
headers.Remove(headerToFilter); | ||
} | ||
|
||
return headers; | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/WinRMSharp.IntegrationTests/Recording/RecordedResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using WinRMSharp.Utils; | ||
|
||
namespace WinRMSharp.IntegrationTests.Recording | ||
{ | ||
internal class RecordedResponse | ||
{ | ||
public int StatusCode { get; set; } | ||
public Dictionary<string, string> Headers { get; set; } | ||
public string? Body { get; set; } | ||
|
||
public RecordedResponse() { } | ||
|
||
public RecordedResponse(HttpResponseMessage responseMessage) | ||
{ | ||
StatusCode = (int)responseMessage.StatusCode; | ||
Headers = responseMessage.Headers.ToDictionary(h => h.Key, h => string.Join(";", h.Value)); | ||
Body = Xml.Format(responseMessage.Content?.ReadAsStringAsync().Result); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace WinRMSharp.IntegrationTests.Recording | ||
{ | ||
internal class RecordedSession | ||
{ | ||
public string Name { get; set; } | ||
public List<Recording> Recordings { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace WinRMSharp.IntegrationTests.Recording | ||
{ | ||
internal class Recording | ||
{ | ||
public RecordedRequest Request { get; set; } | ||
public RecordedResponse Response { get; set; } | ||
} | ||
} |
Oops, something went wrong.