Skip to content

Commit ffd4aa3

Browse files
added a bunch of tests
1 parent ada91c6 commit ffd4aa3

File tree

12 files changed

+659
-49
lines changed

12 files changed

+659
-49
lines changed

src/Azure.Functions.PowerShell.Worker/Function/FunctionInfo.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ namespace Microsoft.Azure.Functions.PowerShellWorker
1010
{
1111
public class FunctionInfo
1212
{
13-
public MapField<string, BindingInfo> Bindings {get; private set;}
14-
public string Directory {get; private set;}
15-
public string HttpOutputName {get; private set;}
16-
public string Name {get; private set;}
17-
public MapField<string, BindingInfo> OutputBindings {get; private set;}
13+
public string Directory {get; set;}
14+
public string HttpOutputName {get; set;}
15+
public string Name {get; set;}
16+
public MapField<string, BindingInfo> Bindings { get; } = new MapField<string, BindingInfo>();
17+
public MapField<string, BindingInfo> OutputBindings { get; } = new MapField<string, BindingInfo>();
18+
19+
public FunctionInfo() { }
1820

1921
public FunctionInfo(RpcFunctionMetadata metadata)
2022
{
2123
Name = metadata.Name;
2224
Directory = metadata.Directory;
23-
Bindings = new MapField<string, BindingInfo>();
24-
OutputBindings = new MapField<string, BindingInfo>();
2525
HttpOutputName = "";
2626

2727
foreach (var binding in metadata.Bindings)

src/Azure.Functions.PowerShell.Worker/Http/HttpRequestContext.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,30 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6+
using System;
67
using Google.Protobuf.Collections;
78

89
namespace Microsoft.Azure.Functions.PowerShellWorker
910
{
10-
public class HttpRequestContext
11+
public class HttpRequestContext : IEquatable<HttpRequestContext>
1112
{
1213
public object Body {get; set;}
1314
public MapField<string, string> Headers {get; set;}
1415
public string Method {get; set;}
1516
public string Url {get; set;}
16-
public string OriginalUrl {get; set;}
1717
public MapField<string, string> Params {get; set;}
1818
public MapField<string, string> Query {get; set;}
1919
public object RawBody {get; set;}
20+
21+
public bool Equals(HttpRequestContext other)
22+
{
23+
return Method == other.Method
24+
&& Url == other.Url
25+
&& Headers.Equals(other.Headers)
26+
&& Params.Equals(other.Params)
27+
&& Query.Equals(other.Query)
28+
&& (Body == other.Body || Body.Equals(other.Body))
29+
&& (RawBody == other.RawBody || RawBody.Equals(other.RawBody));
30+
}
2031
}
2132
}

src/Azure.Functions.PowerShell.Worker/Http/HttpResponseContext.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,37 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6+
using System;
67
using System.Collections;
78

89
namespace Microsoft.Azure.Functions.PowerShellWorker
910
{
10-
public class HttpResponseContext
11+
public class HttpResponseContext : IEquatable<HttpResponseContext>
1112
{
1213
public object Body {get; set;}
1314
public string ContentType {get; set;} = "text/plain";
1415
public bool EnableContentNegotiation {get; set;} = false;
1516
public Hashtable Headers {get; set;} = new Hashtable();
1617
public string StatusCode {get; set;} = "200";
18+
19+
public bool Equals(HttpResponseContext other)
20+
{
21+
bool sameHeaders = true;
22+
foreach (DictionaryEntry dictionaryEntry in Headers)
23+
{
24+
if (!other.Headers.ContainsKey(dictionaryEntry.Key)
25+
|| dictionaryEntry.Value != other.Headers[dictionaryEntry.Key])
26+
{
27+
sameHeaders = false;
28+
break;
29+
}
30+
}
31+
32+
return ContentType == other.ContentType
33+
&& EnableContentNegotiation == other.EnableContentNegotiation
34+
&& StatusCode == other.StatusCode
35+
&& sameHeaders
36+
&& (Body == other.Body || Body.Equals(other.Body));
37+
}
1738
}
1839
}

src/Azure.Functions.PowerShell.Worker/PowerShell/Host/AzureFunctionsHost.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.PowerShell.Host
1616
/// applications. Not all members are implemented. Those that aren't throw a
1717
/// NotImplementedException.
1818
/// </summary>
19-
class AzureFunctionsHost : PSHost
19+
class AzureFunctionsPowerShellHost : PSHost
2020
{
2121
/// <summary>
2222
/// The private reference of the logger.
@@ -82,7 +82,7 @@ class AzureFunctionsHost : PSHost
8282
/// </summary>
8383
public override Version Version => new Version(1, 0, 0, 0);
8484

85-
public AzureFunctionsHost(RpcLogger logger)
85+
public AzureFunctionsPowerShellHost(RpcLogger logger)
8686
{
8787
_logger = logger;
8888
HostUI = new HostUserInterface(logger);

src/Azure.Functions.PowerShell.Worker/StartupArguments.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public class StartupArguments
1717

1818
public static StartupArguments Parse(string[] args)
1919
{
20+
if (args.Length != 10)
21+
{
22+
Console.WriteLine("usage --host <host> --port <port> --workerId <workerId> --requestId <requestId> --grpcMaxMessageLength <length>");
23+
throw new InvalidOperationException("Incorrect startup arguments were given.");
24+
}
25+
2026
StartupArguments arguments = new StartupArguments();
2127
for (int i = 1; i < 10; i+=2)
2228
{

src/Azure.Functions.PowerShell.Worker/Utility/TypeExtensions.cs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Utility
1515
{
1616
public static class TypeExtensions
1717
{
18-
public static HttpRequestContext ToHttpContext (this RpcHttp rpcHttp)
18+
static HttpRequestContext ToHttpRequestContext (this RpcHttp rpcHttp)
1919
{
2020
var httpRequestContext = new HttpRequestContext
2121
{
2222
Method = rpcHttp.Method,
2323
Url = rpcHttp.Url,
24-
OriginalUrl = rpcHttp.Url,
2524
Headers = rpcHttp.Headers,
2625
Params = rpcHttp.Params,
2726
Query = rpcHttp.Query
@@ -34,7 +33,7 @@ public static HttpRequestContext ToHttpContext (this RpcHttp rpcHttp)
3433

3534
if (rpcHttp.RawBody != null)
3635
{
37-
httpRequestContext.Body = rpcHttp.RawBody.ToObject();
36+
httpRequestContext.RawBody = rpcHttp.RawBody.ToObject();
3837
}
3938

4039
return httpRequestContext;
@@ -52,15 +51,15 @@ public static object ToObject (this TypedData data)
5251
case TypedData.DataOneofCase.Json:
5352
return JsonConvert.DeserializeObject<Hashtable>(data.Json);
5453
case TypedData.DataOneofCase.Bytes:
55-
return data.Bytes;
54+
return data.Bytes.ToByteArray();
5655
case TypedData.DataOneofCase.Double:
5756
return data.Double;
5857
case TypedData.DataOneofCase.Http:
59-
return data.Http.ToHttpContext();
58+
return data.Http.ToHttpRequestContext();
6059
case TypedData.DataOneofCase.Int:
6160
return data.Int;
6261
case TypedData.DataOneofCase.Stream:
63-
return data.Stream;
62+
return data.Stream.ToByteArray();
6463
case TypedData.DataOneofCase.String:
6564
return data.String;
6665
case TypedData.DataOneofCase.None:
@@ -80,7 +79,7 @@ public static RpcException ToRpcException (this Exception exception)
8079
};
8180
}
8281

83-
public static RpcHttp ToRpcHttp (this HttpResponseContext httpResponseContext)
82+
static RpcHttp ToRpcHttp (this HttpResponseContext httpResponseContext)
8483
{
8584
var rpcHttp = new RpcHttp
8685
{
@@ -97,7 +96,12 @@ public static RpcHttp ToRpcHttp (this HttpResponseContext httpResponseContext)
9796
{
9897
rpcHttp.Headers.Add(item.Key.ToString(), item.Value.ToString());
9998
}
100-
rpcHttp.Headers.Add("content-type", httpResponseContext.ContentType);
99+
100+
// Allow the user to set content-type in the Headers
101+
if (!rpcHttp.Headers.ContainsKey("content-type"))
102+
{
103+
rpcHttp.Headers.Add("content-type", httpResponseContext.ContentType);
104+
}
101105

102106
return rpcHttp;
103107
}
@@ -111,29 +115,26 @@ public static TypedData ToTypedData(this object value)
111115
return typedData;
112116
}
113117

114-
if (LanguagePrimitives.TryConvertTo<byte[]>(
115-
value, out byte[] arr))
118+
if (LanguagePrimitives.TryConvertTo(value, out byte[] arr))
116119
{
117120
typedData.Bytes = ByteString.CopyFrom(arr);
118121
}
119-
else if(LanguagePrimitives.TryConvertTo<HttpResponseContext>(
120-
value, out HttpResponseContext http))
122+
else if(LanguagePrimitives.TryConvertTo(value, out HttpResponseContext http))
121123
{
122124
typedData.Http = http.ToRpcHttp();
123125
}
124-
else if (LanguagePrimitives.TryConvertTo<Hashtable>(
125-
value, out Hashtable hashtable))
126+
else if (LanguagePrimitives.TryConvertTo(value, out Hashtable hashtable))
126127
{
127128
typedData.Json = JsonConvert.SerializeObject(hashtable);
128129
}
129-
else if (LanguagePrimitives.TryConvertTo<string>(
130-
value, out string str))
130+
else if (LanguagePrimitives.TryConvertTo(value, out string str))
131131
{
132132
// Attempt to parse the string into json. If it fails,
133133
// fallback to storing as a string
134134
try
135135
{
136-
typedData.Json = JsonConvert.SerializeObject(str);
136+
JsonConvert.DeserializeObject(str);
137+
typedData.Json = str;
137138
}
138139
catch
139140
{

src/Azure.Functions.PowerShell.Worker/Worker.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static class Worker
2525

2626
static void InitPowerShell()
2727
{
28-
var host = new AzureFunctionsHost(s_logger);
28+
var host = new AzureFunctionsPowerShellHost(s_logger);
2929

3030
s_runspace = RunspaceFactory.CreateRunspace(host);
3131
s_runspace.Open();
@@ -44,11 +44,6 @@ static void InitPowerShell()
4444

4545
public async static Task Main(string[] args)
4646
{
47-
if (args.Length != 10)
48-
{
49-
Console.WriteLine("usage --host <host> --port <port> --workerId <workerId> --requestId <requestId> --grpcMaxMessageLength <length>");
50-
return;
51-
}
5247
StartupArguments startupArguments = StartupArguments.Parse(args);
5348

5449
// Initialize Rpc client, logger, and PowerShell
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
using System;
2+
using Microsoft.Azure.Functions.PowerShellWorker;
3+
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
4+
using Xunit;
5+
6+
namespace Azure.Functions.PowerShell.Worker.Test
7+
{
8+
public class FunctionLoaderTests
9+
{
10+
[Fact]
11+
public void TestFunctionLoaderGetFunc()
12+
{
13+
var functionId = Guid.NewGuid().ToString();
14+
var directory = "/Users/tylerleonhardt/Desktop/Tech/PowerShell/AzureFunctions/azure-functions-powershell-worker/examples/PSCoreApp/MyHttpTrigger";
15+
var scriptPathExpected = $"{directory}/run.ps1";
16+
var metadata = new RpcFunctionMetadata
17+
{
18+
Name = "MyHttpTrigger",
19+
EntryPoint = "",
20+
Directory = directory,
21+
ScriptFile = scriptPathExpected
22+
};
23+
metadata.Bindings.Add("req", new BindingInfo
24+
{
25+
Direction = BindingInfo.Types.Direction.In,
26+
Type = "httpTrigger"
27+
});
28+
metadata.Bindings.Add("res", new BindingInfo
29+
{
30+
Direction = BindingInfo.Types.Direction.Out,
31+
Type = "http"
32+
});
33+
34+
var functionLoader = new FunctionLoader();
35+
functionLoader.Load(functionId, metadata);
36+
37+
(string scriptPathResult, string entryPointResult) = functionLoader.GetFunc(functionId);
38+
39+
Assert.Equal(scriptPathExpected, scriptPathResult);
40+
Assert.Equal("", entryPointResult);
41+
}
42+
43+
[Fact]
44+
public void TestFunctionLoaderGetFuncWithEntryPoint()
45+
{
46+
var functionId = Guid.NewGuid().ToString();
47+
var directory = "/Users/tylerleonhardt/Desktop/Tech/PowerShell/AzureFunctions/azure-functions-powershell-worker/examples/PSCoreApp/MyHttpTrigger";
48+
var scriptPathExpected = $"{directory}/run.ps1";
49+
var entryPointExpected = "Foo";
50+
var metadata = new RpcFunctionMetadata
51+
{
52+
Name = "MyHttpTrigger",
53+
EntryPoint = entryPointExpected,
54+
Directory = directory,
55+
ScriptFile = scriptPathExpected
56+
};
57+
metadata.Bindings.Add("req", new BindingInfo
58+
{
59+
Direction = BindingInfo.Types.Direction.In,
60+
Type = "httpTrigger"
61+
});
62+
metadata.Bindings.Add("res", new BindingInfo
63+
{
64+
Direction = BindingInfo.Types.Direction.Out,
65+
Type = "http"
66+
});
67+
68+
var functionLoader = new FunctionLoader();
69+
functionLoader.Load(functionId, metadata);
70+
71+
(string scriptPathResult, string entryPointResult) = functionLoader.GetFunc(functionId);
72+
73+
Assert.Equal(scriptPathExpected, scriptPathResult);
74+
Assert.Equal(entryPointExpected, entryPointResult);
75+
}
76+
77+
[Fact]
78+
public void TestFunctionLoaderGetInfo()
79+
{
80+
var functionId = Guid.NewGuid().ToString();
81+
var directory = "/Users/tylerleonhardt/Desktop/Tech/PowerShell/AzureFunctions/azure-functions-powershell-worker/examples/PSCoreApp/MyHttpTrigger";
82+
var scriptPathExpected = $"{directory}/run.ps1";
83+
var name = "MyHttpTrigger";
84+
var metadata = new RpcFunctionMetadata
85+
{
86+
Name = name,
87+
EntryPoint = "",
88+
Directory = directory,
89+
ScriptFile = scriptPathExpected
90+
};
91+
metadata.Bindings.Add("req", new BindingInfo
92+
{
93+
Direction = BindingInfo.Types.Direction.In,
94+
Type = "httpTrigger"
95+
});
96+
metadata.Bindings.Add("res", new BindingInfo
97+
{
98+
Direction = BindingInfo.Types.Direction.Out,
99+
Type = "http"
100+
});
101+
102+
var infoExpected = new FunctionInfo
103+
{
104+
Directory = directory,
105+
HttpOutputName = "",
106+
Name = name
107+
};
108+
infoExpected.Bindings.Add("req", new BindingInfo
109+
{
110+
Direction = BindingInfo.Types.Direction.In,
111+
Type = "httpTrigger"
112+
});
113+
infoExpected.Bindings.Add("res", new BindingInfo
114+
{
115+
Direction = BindingInfo.Types.Direction.Out,
116+
Type = "http"
117+
});
118+
119+
infoExpected.OutputBindings.Add("res", new BindingInfo
120+
{
121+
Direction = BindingInfo.Types.Direction.Out,
122+
Type = "http"
123+
});
124+
125+
var functionLoader = new FunctionLoader();
126+
functionLoader.Load(functionId, metadata);
127+
128+
var infoResult = functionLoader.GetInfo(functionId);
129+
130+
Assert.Equal(directory, infoResult.Directory);
131+
Assert.Equal("res", infoResult.HttpOutputName);
132+
Assert.Equal(name, infoResult.Name);
133+
Assert.Equal(infoExpected.Bindings.Count, infoResult.Bindings.Count);
134+
Assert.Equal(infoExpected.OutputBindings.Count, infoResult.OutputBindings.Count);
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)