Skip to content
This repository was archived by the owner on Sep 27, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

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
@@ -0,0 +1,19 @@
{
"type": "System.Management.Automation.ActionPreferenceStopException",
"transforms": [
{
"query": "select",
"property": "ErrorRecord",
"result": "System.Management.Automation.ErrorRecord"
},
{
"query": "select",
"property": "Exception",
"result": "Microsoft.Rest.Azure.CloudException"
},
{
"query": "select",
"property": "Body"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
<PackageReference Include="System.Management.Automation" Version="6.0.0-alpha17" />
<PackageReference Include="Microsoft.CSharp" Version="4.4.0-preview2-25405-01" />
<PackageReference Include="Newtonsoft.JSON" Version="10.0.1" />
<PackageReference Include="Newtonsoft.JSON" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<None Update="CloudErrorTransform.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="config.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace PSSwagger.LTF.ConsoleServer
using Lib.PowerShell;
using Lib.ServiceTracing;
using Newtonsoft.Json;
using PSSwagger.LTF.Lib.Transforms;
using System;
using System.Collections.Generic;
using System.Globalization;
Expand Down Expand Up @@ -81,7 +82,8 @@ static void Main(string[] args)
RunspaceManager = runspace,
ModulePath = serverArgs.ModulePath,
TracingManager = new ServiceTracingManager(),
SpecificationPaths = serverArgs.SpecificationPaths
SpecificationPaths = serverArgs.SpecificationPaths,
ObjectTransforms = serverArgs.GetTransforms()
});

try
Expand Down Expand Up @@ -109,6 +111,7 @@ class ServerArgs
public List<string> Errors { get; set; }
public bool EnablePipeLog { get; set; }
public bool EnableEventLog { get; set; }
public List<string> TransformDefinitionFiles { get; set; }

public ServerArgs()
{
Expand All @@ -118,6 +121,18 @@ public ServerArgs()
this.LogPipeName = "psswagger-ltf-consoleserver";
this.EnablePipeLog = true;
this.EnableEventLog = false;
this.TransformDefinitionFiles = new List<string>();
}

public IList<DynamicObjectTransform> GetTransforms()
{
List<DynamicObjectTransform> transforms = new List<DynamicObjectTransform>();
foreach (string file in this.TransformDefinitionFiles)
{
transforms.Add(JsonConvert.DeserializeObject<DynamicObjectTransform>(File.ReadAllText(file)));
}

return transforms;
}

public ServerArgs Parse(string[] args)
Expand Down Expand Up @@ -166,6 +181,10 @@ public ServerArgs Parse(string[] args)
case "logpipename":
this.LogPipeName = arg;
break;
case "transform":
// Let's merge these instead of overwriting maybe?
this.TransformDefinitionFiles.Add(arg);
break;
default:
this.Errors.Add(String.Format(CultureInfo.CurrentCulture, "Unknown argument: {0}", lastArg));
break;
Expand Down Expand Up @@ -216,6 +235,12 @@ public ServerArgs Parse(string jsonFilePath)
{
this.SpecificationPaths = fromFile.SpecificationPaths;
}

if (fromFile.TransformDefinitionFiles != null && fromFile.TransformDefinitionFiles.Count > 0)
{
// Let's merge these instead of overwriting maybe?
this.TransformDefinitionFiles.AddRange(fromFile.TransformDefinitionFiles);
}
}

return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
{
"TransformDefinitionFiles": [ "CloudErrorTransform.json" ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFrameworks>net452</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.JSON" Version="10.0.1" />
<PackageReference Include="Newtonsoft.JSON" Version="10.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
<PackageReference Include="Microsoft.CSharp" Version="4.4.0-preview2-25405-01" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace PSSwagger.LTF.Lib
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Transforms;

public class LiveTestServerStartParams
{
Expand All @@ -27,9 +28,11 @@ public class LiveTestServerStartParams
public IList<string> SpecificationPaths { get; set; }
public LiveTestCredentialFactory CredentialFactory { get; set; }
public ServiceTracingManager TracingManager { get; set; }
public IList<DynamicObjectTransform> ObjectTransforms { get; set; }
public LiveTestServerStartParams()
{
this.SpecificationPaths = new List<string>();
this.ObjectTransforms = new List<DynamicObjectTransform>();
}
}

Expand Down Expand Up @@ -187,7 +190,7 @@ public async Task RunAsync()
}
else
{
response = msg.MakeResponse(commandResult, serviceTracer, this.parameters.Logger);
response = msg.MakeResponse(commandResult, serviceTracer, parameters.ObjectTransforms, this.parameters.Logger);
}
}
catch (Exception exRequest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
// Licensed under the MIT license.
namespace PSSwagger.LTF.Lib.Messages
{
using Microsoft.Rest;
using System.Net.Http;

/// <summary>
/// Error response from test operation.
/// </summary>
public class LiveTestError
{
public long Code { get; set; }
public string Message { get; set; }
public LiveTestResult Data { get; set; }

public LiveTestError()
{
this.Data = new LiveTestResult();
}
public object Data { get; set; }
public HttpResponseMessage HttpResponse { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace PSSwagger.LTF.Lib.Messages
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Transforms;

/// <summary>
/// An Azure Live Test Framework JSON-RPC request.
Expand All @@ -28,7 +29,7 @@ public class LiveTestRequest : JsonRpcBase
[JsonIgnore]
public bool HttpResponse { get; set; }

public LiveTestResponse MakeResponse(CommandExecutionResult commandResult, IServiceTracer tracer, Logger logger)
public LiveTestResponse MakeResponse(CommandExecutionResult commandResult, IServiceTracer tracer, IList<DynamicObjectTransform> transforms, Logger logger)
{
LiveTestResponse response = MakeBaseResponse();
if (commandResult.HadErrors)
Expand All @@ -41,7 +42,31 @@ public LiveTestResponse MakeResponse(CommandExecutionResult commandResult, IServ

response.Error = new LiveTestError();
response.Error.Code = InvalidRequest;
response.Error.Data = GetLiveTestResult(commandResult.Errors, tracer);
List<object> errors = new List<object>();
foreach (object originalError in commandResult.Errors)
{
errors.AddRange(TransformObject(originalError, transforms));
}

response.Error.Data = errors.Count == 0 ? null : errors.Count == 1 ? errors[0] : errors;
if (this.HttpResponse)
{
HttpResponseMessage responseMessage = tracer.HttpResponses.LastOrDefault();
if (responseMessage != null)
{
// Kill the Content property - doesn't work with Newtonsoft.Json serialization
HttpResponseMessage clonedMessage = new HttpResponseMessage(responseMessage.StatusCode);
foreach (var header in responseMessage.Headers)
{
clonedMessage.Headers.Add(header.Key, header.Value);
}

clonedMessage.ReasonPhrase = responseMessage.ReasonPhrase;
clonedMessage.RequestMessage = responseMessage.RequestMessage;
clonedMessage.Version = responseMessage.Version;
response.Error.HttpResponse = clonedMessage;
}
}
}
else
{
Expand All @@ -50,7 +75,13 @@ public LiveTestResponse MakeResponse(CommandExecutionResult commandResult, IServ
logger.LogAsync("Command executed successfully.");
}

response.Result = GetLiveTestResult(commandResult.Results, tracer);
List<object> results = new List<object>();
foreach (object originalResult in commandResult.Results)
{
results.AddRange(TransformObject(originalResult, transforms));
}

response.Result = GetLiveTestResult(results, tracer);
}

return response;
Expand All @@ -61,10 +92,32 @@ public LiveTestResponse MakeResponse(Exception ex, int errorCode)
LiveTestResponse response = MakeBaseResponse();
response.Error = new LiveTestError();
response.Error.Code = errorCode;
response.Error.Data.Response = ex;
response.Error.Data = ex;
return response;
}

private IEnumerable<object> TransformObject(object obj, IList<DynamicObjectTransform> transforms)
{
bool transformed = false;
foreach (object result in transforms.Where(t => t.CanTransform(obj)).SelectMany(t => t.Transform(obj)))
{
transformed = true;
IEnumerable<object> transformedResults = TransformObject(result, transforms);
if (transformedResults != null)
{
foreach (object innerResult in transformedResults)
{
yield return innerResult;
}
}
}

if (!transformed)
{
yield return obj;
}
}

private LiveTestResult GetLiveTestResult(IEnumerable<object> resultsEnumerable, IServiceTracer tracer)
{
LiveTestResult result = new LiveTestResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFrameworks>net452</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.JSON" Version="10.0.1" />
<PackageReference Include="Newtonsoft.JSON" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PSSwagger.LTF.IO.Lib\PSSwagger.LTF.IO.Lib.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) Microsoft Corporation. All rights reserved.

// Licensed under the MIT license.
namespace PSSwagger.LTF.Lib.Transforms
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Defines transform steps for a single type.
/// </summary>
public class DynamicObjectTransform
{
/// <summary>
/// Gets or sets the type to apply transform to.
/// </summary>
public string Type { get; set; }

/// <summary>
/// Gets or sets the ordered list of transforms to apply to this type.
/// </summary>
public DynamicObjectTransformDefinition[] Transforms { get; set; }

/// <summary>
/// Checks if <paramref name="obj"/> exactly matches the Type property.
/// </summary>
/// <param name="obj">Object to check. Can be null.</param>
/// <returns>False if null or <paramref name="obj"/>.GetType().FullName does not match this.Type; True otherwise.</returns>
public bool CanTransform(object obj)
{
if (obj == null)
{
return false;
}

return obj.GetType().FullName.Equals(this.Type, StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Transform the given object into one or more objects. For multi-step transforms, all steps should define an expected output type. Otherwise, the client should re-query all transformers.
/// </summary>
/// <param name="obj">Object to transform. Can be null.</param>
/// <returns>Null if <paramref name="obj"/> is null. Otherwise, returns the result of valid transforms.</returns>
public IEnumerable<object> Transform(object obj)
{
if (this.Transforms != null)
{
List<object> toTransform = new List<object>();
List<object> transformResult = new List<object>();
List<object> swap = null;
toTransform.Add(obj);
foreach (DynamicObjectTransformDefinition definition in this.Transforms)
{
transformResult.Clear();
foreach (object transformObject in toTransform)
{
IEnumerable<object> newObjects = definition.Transform(transformObject);
if (!String.IsNullOrEmpty(definition.Result))
{
newObjects = newObjects.Where(o => o.GetType().FullName.Equals(definition.Result, StringComparison.OrdinalIgnoreCase));
}

transformResult.AddRange(newObjects);
}

// Nothing to transform to the next phase, just return the previous phase
if (transformResult.Count == 0)
{
return toTransform;
}

swap = toTransform;
toTransform = transformResult;
transformResult = swap;
}

// The result of the last phase will be in toTransform
return toTransform;
}

return null;
}
}
}
Loading