From d2dbd2b35164ef161ba3c40e53dcac35c175d692 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 8 Jun 2022 19:13:05 +0200 Subject: [PATCH 01/31] WIP: add gRPC tests --- src/libraries/tests.proj | 3 + .../Android/Device_Emulator/gRPC/.gitignore | 1 + .../Android.Device_Emulator.gRPC.Test.csproj | 83 +++++++++++++++++++ .../Android/Device_Emulator/gRPC/NuGet.config | 6 ++ .../Android/Device_Emulator/gRPC/Program.cs | 78 +++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 5bae35e0fad87..c24fd18fb67d7 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -188,6 +188,9 @@ + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore new file mode 100644 index 0000000000000..bd0de9af79ac4 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore @@ -0,0 +1 @@ +grpc-dotnet \ No newline at end of file diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj new file mode 100644 index 0000000000000..7cf4bbf5f4838 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -0,0 +1,83 @@ + + + Exe + + true + $(NetCoreAppCurrent) + Android.Device_Emulator.gRPC.Test.dll + 42 + + false + true + true + true + + true + true + + enable + enable + + + + + + + + CS8981;SYSLIB0039 + + $(MSBuildProjectDirectory)\grpc-dotnet + + + BLAZOR_WASM + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config new file mode 100644 index 0000000000000..95e879eff2bbb --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs new file mode 100644 index 0000000000000..16cc70a254572 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -0,0 +1,78 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +// The code of the tests is cloned from https://github.com/grpc/grpc-dotnet +using Grpc.Shared.TestAssets; + +int failedTests = 0; +var skippedTests = new[] +{ + "compute_engine_creds", + "jwt_token_creds", + "oauth2_auth_token", + "per_rpc_creds", + "client_compressed_streaming", // flaky test +}; + +var configurations = new[] +{ + new ClientOptions + { + ServerHost = "grpc.rozsival.com", // TODO + ServerPort = 443, + UseTls = true, + }, +}; + +// var services = new ServiceCollection(); +// services.AddLogging(configure => +// { +// configure.SetMinimumLevel(LogLevel.Trace); +// configure.AddConsole(loggerOptions => loggerOptions.IncludeScopes = true); +// }); + +// using var serviceProvider = services.BuildServiceProvider(); +// var loggerFactory = serviceProvider.GetRequiredService(); +var loggerFactory = Microsoft.Extensions.Logging.Abstractions.NullLoggerFactory.Instance; + +foreach (var options in configurations) { + Console.WriteLine($$""" + gRPC client options + ------------------- + ClientType: {options.ClientType} + ServerHost: {options.ServerHost} + ServerHostOverride: {options.ServerHostOverride} + ServerPort: {options.ServerPort} + UseTls: {options.UseTls} + UseTestCa: {options.UseTestCa} + DefaultServiceAccount: {options.DefaultServiceAccount} + OAuthScope: {options.OAuthScope} + ServiceAccountKeyFile: {options.ServiceAccountKeyFile} + GrpcWebMode: {options.GrpcWebMode} + UseWinHttp: {options.UseWinHttp} + UseHttp3: {options.UseHttp3} + """); + + foreach (var testName in InteropClient.TestNames) { + if (skippedTests.Contains(testName)) { + Console.WriteLine($"TestCase: {testName} ... FAILED"); + continue; + } + + options.TestCase = testName; + var client = new InteropClient(options, loggerFactory); + + try { + Console.WriteLine($"TestCase: {testName} ... STARTED"); + await client.Run(); + Console.WriteLine($"TestCase: {testName} ... PASSED"); + } catch (Exception e) { + Console.WriteLine($"TestCase: {testName} ... FAILED"); + Console.Error.WriteLine(e); + failedTests++; + } + } +} + +return 42 + failedTests; From 1dcf0e8b15e800bae34c7fca9b4064ebebe0fbd6 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 9 Jun 2022 14:57:23 +0200 Subject: [PATCH 02/31] Fix AOT and trimming --- .../Android.Device_Emulator.gRPC.Test.csproj | 16 ++--- .../Android/Device_Emulator/gRPC/Program.cs | 65 ++++++++++++------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index 7cf4bbf5f4838..ca58cf5c1d0bf 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -1,7 +1,6 @@ Exe - true $(NetCoreAppCurrent) Android.Device_Emulator.gRPC.Test.dll @@ -11,19 +10,14 @@ true true true - + true true enable enable - - - - - CS8981;SYSLIB0039 $(MSBuildProjectDirectory)\grpc-dotnet @@ -67,17 +61,15 @@ - - - + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index 16cc70a254572..ec381c4917c86 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -1,11 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; // The code of the tests is cloned from https://github.com/grpc/grpc-dotnet using Grpc.Shared.TestAssets; -int failedTests = 0; var skippedTests = new[] { "compute_engine_creds", @@ -19,27 +19,19 @@ { new ClientOptions { - ServerHost = "grpc.rozsival.com", // TODO + ServerHost = "TODO", ServerPort = 443, UseTls = true, }, }; -// var services = new ServiceCollection(); -// services.AddLogging(configure => -// { -// configure.SetMinimumLevel(LogLevel.Trace); -// configure.AddConsole(loggerOptions => loggerOptions.IncludeScopes = true); -// }); - -// using var serviceProvider = services.BuildServiceProvider(); -// var loggerFactory = serviceProvider.GetRequiredService(); -var loggerFactory = Microsoft.Extensions.Logging.Abstractions.NullLoggerFactory.Instance; +int failedTests = 0; -foreach (var options in configurations) { - Console.WriteLine($$""" - gRPC client options - ------------------- +foreach (var options in configurations) +{ + Console.WriteLine($""" + gRPC client options: + -------------------- ClientType: {options.ClientType} ServerHost: {options.ServerHost} ServerHostOverride: {options.ServerHostOverride} @@ -52,23 +44,27 @@ gRPC client options GrpcWebMode: {options.GrpcWebMode} UseWinHttp: {options.UseWinHttp} UseHttp3: {options.UseHttp3} + --- """); - foreach (var testName in InteropClient.TestNames) { - if (skippedTests.Contains(testName)) { - Console.WriteLine($"TestCase: {testName} ... FAILED"); + foreach (var testName in InteropClient.TestNames) + { + if (skippedTests.Contains(testName)) + { + Log(testName, "SKIPPED"); continue; } options.TestCase = testName; - var client = new InteropClient(options, loggerFactory); + var client = new InteropClientWrapper(options); - try { - Console.WriteLine($"TestCase: {testName} ... STARTED"); + try + { + Log(testName, "STARTED"); await client.Run(); - Console.WriteLine($"TestCase: {testName} ... PASSED"); + Log(testName, "PASSED"); } catch (Exception e) { - Console.WriteLine($"TestCase: {testName} ... FAILED"); + Log(testName, "FAILED"); Console.Error.WriteLine(e); failedTests++; } @@ -76,3 +72,24 @@ gRPC client options } return 42 + failedTests; + +void Log(string testName, string status) + => Console.WriteLine($"TestCase: {testName} ... {status}"); + +sealed class InteropClientWrapper +{ + private readonly InteropClient interopClient; + + [DynamicDependency(DynamicallyAccessedMemberTypes.All, "Grpc.Testing.TestService.TestServiceClient", "Android.Device_Emulator.gRPC.Test")] + [DynamicDependency(DynamicallyAccessedMemberTypes.All, "Grpc.Testing.UnimplementedService.UnimplementedServiceClient", "Android.Device_Emulator.gRPC.Test")] + public InteropClientWrapper(ClientOptions options) + { + interopClient = new InteropClient( + options, + Microsoft.Extensions.Logging.Abstractions.NullLoggerFactory.Instance + ); + } + + public Task Run() + => interopClient.Run(); +} From 2941f152dfd53b58e7c1913edc723d819d3b1640 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 23 Jun 2022 17:07:47 +0200 Subject: [PATCH 03/31] WIP --- .../sample/Android/AndroidSampleApp.csproj | 1 + src/mono/sample/Android/Makefile | 2 +- src/mono/sample/Android/Program.cs | 40 ++++++++++++++++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/mono/sample/Android/AndroidSampleApp.csproj b/src/mono/sample/Android/AndroidSampleApp.csproj index dabf1700dce5f..80c25fed3ef12 100644 --- a/src/mono/sample/Android/AndroidSampleApp.csproj +++ b/src/mono/sample/Android/AndroidSampleApp.csproj @@ -86,6 +86,7 @@ MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackDir)runtimes\android-$(TargetArchitecture)\native\include\mono-2.0" Assemblies="@(BundleAssemblies)" MainLibraryFileName="$(AssemblyName).dll" + IncludeNetworkSecurityConfig="$(IncludeNetworkSecurityConfig)" StripDebugSymbols="$(StripDebugSymbols)" RuntimeComponents="$(RuntimeComponents)" DiagnosticPorts="$(DiagnosticPorts)" diff --git a/src/mono/sample/Android/Makefile b/src/mono/sample/Android/Makefile index cbcf63db861f6..f656fc15bf45c 100644 --- a/src/mono/sample/Android/Makefile +++ b/src/mono/sample/Android/Makefile @@ -1,5 +1,5 @@ MONO_CONFIG=Release -MONO_ARCH?=x64 +MONO_ARCH?=arm64 DOTNET := ../../../../dotnet.sh USE_LLVM=true AOT=false diff --git a/src/mono/sample/Android/Program.cs b/src/mono/sample/Android/Program.cs index 7dcc0f375db87..89b7d2794f338 100644 --- a/src/mono/sample/Android/Program.cs +++ b/src/mono/sample/Android/Program.cs @@ -1,13 +1,41 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +#nullable enable using System; +using System.Net; +using System.Net.Sockets; +using System.Net.Security; +using System.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; -public static class Program +TestAuthenticateAsClient(hostname: "microsoft.com"); +TestAuthenticateAsClient(hostname: "self-signed.badssl.com"); +TestAuthenticateAsClient(hostname: "expired.badssl.com"); + +void TestAuthenticateAsClient(string hostname, int port = 443) { - public static int Main(string[] args) + using var tcpClient = new TcpClient(); + IAsyncResult result = tcpClient.BeginConnect(hostname, port, null, null); + var connected = result.AsyncWaitHandle.WaitOne(2000, true); + if (connected) { - Console.WriteLine("Hello, Android!"); // logcat - return 42; + tcpClient.EndConnect(result); + var stream = new SslStream(tcpClient.GetStream(), false, ValidateServerCertificate, null); + try + { + stream.AuthenticateAsClient(hostname); + + Console.WriteLine($"OK - {hostname}:{port}"); + } + catch (Exception ex) + { + Console.WriteLine($"!! - {hostname}:{port} ({ex.Message})"); + Console.WriteLine(ex); + } } } + +bool ValidateServerCertificate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) +{ + return true; +} From 66b29397c43ef48837a2a6d05beb509b287d4c59 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 27 Jun 2022 11:51:11 +0200 Subject: [PATCH 04/31] Implement IncludeNetworkSecurityConfig --- .../AndroidAppBuilder/AndroidAppBuilder.cs | 3 ++ src/tasks/AndroidAppBuilder/ApkBuilder.cs | 29 ++++++++++++++++++- .../Templates/AndroidManifest.xml | 3 +- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs index b2ae7276fe90b..66eef2cd542c8 100644 --- a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs +++ b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -80,6 +80,8 @@ public class AndroidAppBuilderTask : Task /// public string? NativeMainSource { get; set; } + public bool IncludeNetworkSecurityConfig { get; set; } + public string? KeyStorePath { get; set; } public bool ForceInterpreter { get; set; } @@ -105,6 +107,7 @@ public override bool Execute() apkBuilder.BuildToolsVersion = BuildToolsVersion; apkBuilder.StripDebugSymbols = StripDebugSymbols; apkBuilder.NativeMainSource = NativeMainSource; + apkBuilder.IncludeNetworkSecurityConfig = IncludeNetworkSecurityConfig; apkBuilder.KeyStorePath = KeyStorePath; apkBuilder.ForceInterpreter = ForceInterpreter; apkBuilder.ForceAOT = ForceAOT; diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index ace6fcb0c0c91..40c0f4c5978f1 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -24,6 +24,7 @@ public class ApkBuilder public string OutputDir { get; set; } = ""!; public bool StripDebugSymbols { get; set; } public string? NativeMainSource { get; set; } + public bool IncludeNetworkSecurityConfig { get; set; } public string? KeyStorePath { get; set; } public bool ForceInterpreter { get; set; } public bool ForceAOT { get; set; } @@ -57,6 +58,12 @@ public ApkBuilder(TaskLoggingHelper logger) throw new ArgumentException($"MainLibraryFileName='{mainLibraryFileName}' was not found in AppDir='{AppDir}'"); } + var networkSecurityConfigFilePath = Path.Combine(AppDir, "res", "xml", "network_security_config.xml"); + if (IncludeNetworkSecurityConfig && !File.Exists(networkSecurityConfigFilePath)) + { + throw new ArgumentException($"IncludeNetworkSecurityConfig is set but the file '{networkSecurityConfigFilePath}' was not found"); + } + if (string.IsNullOrEmpty(abi)) { throw new ArgumentException("abi should not be empty (e.g. x86, x86_64, armeabi-v7a or arm64-v8a"); @@ -172,6 +179,7 @@ public ApkBuilder(TaskLoggingHelper logger) Directory.CreateDirectory(Path.Combine(OutputDir, "obj")); Directory.CreateDirectory(Path.Combine(OutputDir, "assets-tozip")); Directory.CreateDirectory(Path.Combine(OutputDir, "assets")); + Directory.CreateDirectory(Path.Combine(OutputDir, "res")); var extensionsToIgnore = new List { ".so", ".a", ".gz" }; if (StripDebugSymbols) @@ -183,6 +191,7 @@ public ApkBuilder(TaskLoggingHelper logger) // Copy sourceDir to OutputDir/assets-tozip (ignore native files) // these files then will be zipped and copied to apk/assets/assets.zip var assetsToZipDirectory = Path.Combine(OutputDir, "assets-tozip"); + Utils.DirectoryCopy(AppDir, assetsToZipDirectory, file => { string fileName = Path.GetFileName(file); @@ -199,9 +208,20 @@ public ApkBuilder(TaskLoggingHelper logger) // aapt complains on such files return false; } + if (file.Contains("/res/")) + { + // exclude everything in the `res` folder + return false; + } return true; }); + // copy the res directory as is + if (Directory.Exists(Path.Combine(AppDir, "res"))) + { + Utils.DirectoryCopy(Path.Combine(AppDir, "res"), Path.Combine(OutputDir, "res")); + } + // add AOT .so libraries foreach (var aotlib in aotLibraryFiles) { @@ -373,6 +393,11 @@ public ApkBuilder(TaskLoggingHelper logger) if (!string.IsNullOrEmpty(NativeMainSource)) File.Copy(NativeMainSource, javaActivityPath, true); + string networkSecurityConfigAttribute = + IncludeNetworkSecurityConfig + ? "a:networkSecurityConfig=\"@xml/network_security_config\"" + : string.Empty; + string envVariables = ""; foreach (ITaskItem item in EnvironmentVariables) { @@ -390,6 +415,7 @@ public ApkBuilder(TaskLoggingHelper logger) File.WriteAllText(Path.Combine(OutputDir, "AndroidManifest.xml"), Utils.GetEmbeddedResource("AndroidManifest.xml") .Replace("%PackageName%", packageId) + .Replace("%NetworkSecurityConfig%", networkSecurityConfigAttribute) .Replace("%MinSdkLevel%", MinApiLevel)); string javaCompilerArgs = $"-d obj -classpath src -bootclasspath {androidJar} -source 1.8 -target 1.8 "; @@ -414,7 +440,8 @@ public ApkBuilder(TaskLoggingHelper logger) string debugModeArg = StripDebugSymbols ? string.Empty : "--debug-mode"; string apkFile = Path.Combine(OutputDir, "bin", $"{ProjectName}.unaligned.apk"); - Utils.RunProcess(logger, aapt, $"package -f -m -F {apkFile} -A assets -M AndroidManifest.xml -I {androidJar} {debugModeArg}", workingDir: OutputDir); + string resources = IncludeNetworkSecurityConfig ? "-S res" : string.Empty; + Utils.RunProcess(logger, aapt, $"package -f -m -F {apkFile} -A assets {resources} -M AndroidManifest.xml -I {androidJar} {debugModeArg}", workingDir: OutputDir); var dynamicLibs = new List(); dynamicLibs.Add(Path.Combine(OutputDir, "monodroid", "libmonodroid.so")); diff --git a/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml b/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml index 9d28b5efbdf3c..befd2e446a650 100644 --- a/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml +++ b/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml @@ -7,7 +7,8 @@ - From 6ef8d851235bf93b500faa102e6efb28c340ee81 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 27 Jun 2022 11:52:39 +0200 Subject: [PATCH 05/31] Use IncludeNetworkSecurityConfig --- eng/testing/tests.mobile.targets | 1 + src/tests/build.proj | 1 + 2 files changed, 2 insertions(+) diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets index edeed52b946f1..78e421042fd7b 100644 --- a/eng/testing/tests.mobile.targets +++ b/eng/testing/tests.mobile.targets @@ -153,6 +153,7 @@ MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackNativeDir)include\mono-2.0" Assemblies="@(BundleAssemblies)" MainLibraryFileName="$(MainLibraryFileName)" + IncludeNetworkSecurityConfig="$(IncludeNetworkSecurityConfig)" EnvironmentVariables="@(_AndroidEnv)" ForceAOT="$(RunAOTCompilation)" ForceInterpreter="$(MonoForceInterpreter)" diff --git a/src/tests/build.proj b/src/tests/build.proj index 063e3059c4385..e83ee2129ed1a 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -247,6 +247,7 @@ RuntimeIdentifier="$(RuntimeIdentifier)" ProjectName="$(Category)" MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackDir)/native/include/mono-2.0" + IncludeNetworkSecurityConfig="$(IncludeNetworkSecurityConfig)" RuntimeComponents="$(RuntimeComponents)" DiagnosticPorts="$(DiagnosticPorts)" StripDebugSymbols="$(StripDebugSymbols)" From 5740a9b04aaf6dcde810e106b7498d84191c8616 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 27 Jun 2022 11:53:45 +0200 Subject: [PATCH 06/31] Fix gRPC test --- .../Android/Device_Emulator/gRPC/.gitignore | 3 +- .../Android.Device_Emulator.gRPC.Test.csproj | 50 ++++++++++--------- .../Android/Device_Emulator/gRPC/Program.cs | 4 +- .../gRPC/res/xml/network_security_config.xml | 9 ++++ 4 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore index bd0de9af79ac4..496f04873305a 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore @@ -1 +1,2 @@ -grpc-dotnet \ No newline at end of file +grpc-dotnet +res/raw \ No newline at end of file diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index ca58cf5c1d0bf..44ec39056a2ea 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -26,8 +26,16 @@ BLAZOR_WASM + + true + + + + + PreserveNewest + @@ -37,39 +45,33 @@ - - - - - - - + + - - - + - - PreserveNewest - - - - - + + + - - + + - + - + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index ec381c4917c86..4621ece91858e 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -19,8 +19,8 @@ { new ClientOptions { - ServerHost = "TODO", - ServerPort = 443, + ServerHost = "localhost", + ServerPort = 50052, UseTls = true, }, }; diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml new file mode 100644 index 0000000000000..6ae87169b9e1e --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file From b99fc44f8d79fafe6f7431e2f8f1759a2b12f77a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 27 Jun 2022 20:48:26 +0200 Subject: [PATCH 07/31] Avoid git checkout --- .../Android/Device_Emulator/gRPC/.gitignore | 2 - .../Android.Device_Emulator.gRPC.Test.csproj | 35 +- .../Android/Device_Emulator/gRPC/README.md | 2 + .../test/Shared/HttpEventSourceListener.cs | 120 +++ .../testassets/Certs/InteropTests/README.md | 8 + .../testassets/Certs/InteropTests/ca.pem | 20 + .../testassets/Certs/InteropTests/server1.key | 28 + .../testassets/Certs/InteropTests/server1.pem | 22 + .../testassets/Proto/grpc/testing/empty.proto | 28 + .../Proto/grpc/testing/messages.proto | 165 ++++ .../testassets/Proto/grpc/testing/test.proto | 79 ++ .../grpc-dotnet/testassets/Shared/Assert.cs | 129 +++ .../Shared/AsyncStreamExtensions.cs | 81 ++ .../testassets/Shared/ExceptionAssert.cs | 54 ++ .../testassets/Shared/IChannelWrapper.cs | 62 ++ .../testassets/Shared/InteropClient.cs | 906 ++++++++++++++++++ .../testassets/Shared/TestCredentials.cs | 74 ++ .../Device_Emulator/gRPC/res/raw/ca.pem | 20 + .../gRPC/res/xml/network_security_config.xml | 1 - 19 files changed, 1809 insertions(+), 27 deletions(-) delete mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md create mode 100755 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/test/Shared/HttpEventSourceListener.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/ca.pem create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.key create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pem create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/empty.proto create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/messages.proto create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/test.proto create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/Assert.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/AsyncStreamExtensions.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/ExceptionAssert.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/TestCredentials.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/ca.pem diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore deleted file mode 100644 index 496f04873305a..0000000000000 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -grpc-dotnet -res/raw \ No newline at end of file diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index 44ec39056a2ea..4c1133ca0e52d 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -19,8 +19,6 @@ CS8981;SYSLIB0039 - - $(MSBuildProjectDirectory)\grpc-dotnet BLAZOR_WASM @@ -38,40 +36,29 @@ - - - - + + - + - + - - - - + + + + - - diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md new file mode 100644 index 0000000000000..32bf183798b84 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md @@ -0,0 +1,2 @@ +res - Android resource folder +dotnet-grpc - copied from https://github.com/grpc/grpc-dotnet diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/test/Shared/HttpEventSourceListener.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/test/Shared/HttpEventSourceListener.cs new file mode 100755 index 0000000000000..d03fe0dc2b750 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/test/Shared/HttpEventSourceListener.cs @@ -0,0 +1,120 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System.Diagnostics.Tracing; +using System.Text; +using Microsoft.Extensions.Logging; + +namespace Grpc.Tests.Shared +{ + public sealed class HttpEventSourceListener : EventListener + { + private readonly StringBuilder _messageBuilder = new StringBuilder(); + private readonly ILogger? _logger; + private readonly object _lock = new object(); + private bool _disposed; + + public HttpEventSourceListener(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(nameof(HttpEventSourceListener)); + _logger.LogDebug($"Starting {nameof(HttpEventSourceListener)}."); + } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + base.OnEventSourceCreated(eventSource); + + if (IsHttpEventSource(eventSource)) + { + lock (_lock) + { + if (!_disposed) + { + EnableEvents(eventSource, EventLevel.LogAlways, EventKeywords.All); + } + } + } + } + + private static bool IsHttpEventSource(EventSource eventSource) + { + return eventSource.Name.Contains("System.Net.Quic") || eventSource.Name.Contains("System.Net.Http"); + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + base.OnEventWritten(eventData); + + if (!IsHttpEventSource(eventData.EventSource)) + { + return; + } + + string message; + lock (_messageBuilder) + { + _messageBuilder.Append("<- Event "); + _messageBuilder.Append(eventData.EventSource.Name); + _messageBuilder.Append(" - "); + _messageBuilder.Append(eventData.EventName); + _messageBuilder.Append(" : "); +#if !NET472 + _messageBuilder.AppendJoin(',', eventData.Payload!); +#else + _messageBuilder.Append(string.Join(",", eventData.Payload!.ToArray())); +#endif + _messageBuilder.Append(" ->"); + message = _messageBuilder.ToString(); + _messageBuilder.Clear(); + } + + // We don't know the state of the logger after dispose. + // Ensure that any messages written in the background aren't + // logged after the listener has been disposed in the test. + lock (_lock) + { + if (!_disposed) + { + // EventListener base constructor subscribes to events. + // It is possible to start getting events before the + // super constructor is run and logger is assigned. + _logger?.LogDebug(message); + } + } + } + + public override string ToString() + { + return _messageBuilder.ToString(); + } + + public override void Dispose() + { + base.Dispose(); + + lock (_lock) + { + if (!_disposed) + { + _logger?.LogDebug($"Stopping {nameof(HttpEventSourceListener)}."); + _disposed = true; + } + } + } + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md new file mode 100644 index 0000000000000..79206a4863a5d --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md @@ -0,0 +1,8 @@ +Keys taken from https://github.com/grpc/grpc/tree/master/src/core/tsi/test_creds +so that interop server in this project is compatible with interop clients +implemented in other gRPC languages. + +The server1.pem and server1.key were combined into server1.pfx. The password is 1111. These certs are not secure, do not use in production. +``` +openssl pkcs12 -export -out server1.pfx -inkey server1.key -in server1.pem -certfile ca.pem +``` diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/ca.pem b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/ca.pem new file mode 100644 index 0000000000000..49d39cd8ed5f8 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIUWrP0VvHcy+LP6UuYNtiL9gBhD5owDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw +MDMxNzE4NTk1MVoXDTMwMDMxNTE4NTk1MVowVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGdGVzdGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAsGL0oXflF0LzoM+Bh+qUU9yhqzw2w8OOX5mu/iNCyUOBrqaHi7mGHx73GD01 +diNzCzvlcQqdNIH6NQSL7DTpBjca66jYT9u73vZe2MDrr1nVbuLvfu9850cdxiUO +Inv5xf8+sTHG0C+a+VAvMhsLiRjsq+lXKRJyk5zkbbsETybqpxoJ+K7CoSy3yc/k +QIY3TipwEtwkKP4hzyo6KiGd/DPexie4nBUInN3bS1BUeNZ5zeaIC2eg3bkeeW7c +qT55b+Yen6CxY0TEkzBK6AKt/WUialKMgT0wbTxRZO7kUCH3Sq6e/wXeFdJ+HvdV +LPlAg5TnMaNpRdQih/8nRFpsdwIDAQABoyAwHjAMBgNVHRMEBTADAQH/MA4GA1Ud +DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEAkTrKZjBrJXHps/HrjNCFPb5a +THuGPCSsepe1wkKdSp1h4HGRpLoCgcLysCJ5hZhRpHkRihhef+rFHEe60UePQO3S +CVTtdJB4CYWpcNyXOdqefrbJW5QNljxgi6Fhvs7JJkBqdXIkWXtFk2eRgOIP2Eo9 +/OHQHlYnwZFrk6sp4wPyR+A95S0toZBcyDVz7u+hOW0pGK3wviOe9lvRgj/H3Pwt +bewb0l+MhRig0/DVHamyVxrDRbqInU1/GTNCwcZkXKYFWSf92U+kIcTth24Q1gcw +eZiLl5FfrWokUNytFElXob0V0a5/kbhiLc3yWmvWqHTpqCALbVyF+rKJo2f5Kw== +-----END CERTIFICATE----- diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.key b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.key new file mode 100644 index 0000000000000..086462992cfbe --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnE443EknxvxBq +6+hvn/t09hl8hx366EBYvZmVM/NC+7igXRAjiJiA/mIaCvL3MS0Iz5hBLxSGICU+ +WproA3GCIFITIwcf/ETyWj/5xpgZ4AKrLrjQmmX8mhwUajfF3UvwMJrCOVqPp67t +PtP+2kBXaqrXdvnvXR41FsIB8V7zIAuIZB6bHQhiGVlc1sgZYsE2EGG9WMmHtS86 +qkAOTjG2XyjmPTGAwhGDpYkYrpzp99IiDh4/Veai81hn0ssQkbry0XRD/Ig3jcHh +23WiriPNJ0JsbgXUSLKRPZObA9VgOLy2aXoN84IMaeK3yy+cwSYG/99w93fUZJte +MXwz4oYZAgMBAAECggEBAIVn2Ncai+4xbH0OLWckabwgyJ4IM9rDc0LIU368O1kU +koais8qP9dujAWgfoh3sGh/YGgKn96VnsZjKHlyMgF+r4TaDJn3k2rlAOWcurGlj +1qaVlsV4HiEzp7pxiDmHhWvp4672Bb6iBG+bsjCUOEk/n9o9KhZzIBluRhtxCmw5 +nw4Do7z00PTvN81260uPWSc04IrytvZUiAIx/5qxD72bij2xJ8t/I9GI8g4FtoVB +8pB6S/hJX1PZhh9VlU6Yk+TOfOVnbebG4W5138LkB835eqk3Zz0qsbc2euoi8Hxi +y1VGwQEmMQ63jXz4c6g+X55ifvUK9Jpn5E8pq+pMd7ECgYEA93lYq+Cr54K4ey5t +sWMa+ye5RqxjzgXj2Kqr55jb54VWG7wp2iGbg8FMlkQwzTJwebzDyCSatguEZLuB +gRGroRnsUOy9vBvhKPOch9bfKIl6qOgzMJB267fBVWx5ybnRbWN/I7RvMQf3k+9y +biCIVnxDLEEYyx7z85/5qxsXg/MCgYEA7wmWKtCTn032Hy9P8OL49T0X6Z8FlkDC +Rk42ygrc/MUbugq9RGUxcCxoImOG9JXUpEtUe31YDm2j+/nbvrjl6/bP2qWs0V7l +dTJl6dABP51pCw8+l4cWgBBX08Lkeen812AAFNrjmDCjX6rHjWHLJcpS18fnRRkP +V1d/AHWX7MMCgYEA6Gsw2guhp0Zf2GCcaNK5DlQab8OL4Hwrpttzo4kuTlwtqNKp +Q9H4al9qfF4Cr1TFya98+EVYf8yFRM3NLNjZpe3gwYf2EerlJj7VLcahw0KKzoN1 +QBENfwgPLRk5sDkx9VhSmcfl/diLroZdpAwtv3vo4nEoxeuGFbKTGx3Qkf0CgYEA +xyR+dcb05Ygm3w4klHQTowQ10s1H80iaUcZBgQuR1ghEtDbUPZHsoR5t1xCB02ys +DgAwLv1bChIvxvH/L6KM8ovZ2LekBX4AviWxoBxJnfz/EVau98B0b1auRN6eSC83 +FRuGldlSOW1z/nSh8ViizSYE5H5HX1qkXEippvFRE88CgYB3Bfu3YQY60ITWIShv +nNkdcbTT9eoP9suaRJjw92Ln+7ZpALYlQMKUZmJ/5uBmLs4RFwUTQruLOPL4yLTH +awADWUzs3IRr1fwn9E+zM8JVyKCnUEM3w4N5UZskGO2klashAd30hWO+knRv/y0r +uGIYs9Ek7YXlXIRVrzMwcsrt1w== +-----END PRIVATE KEY----- diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pem b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pem new file mode 100644 index 0000000000000..88244f856c622 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIUbJfTREJ6k6/+oInWhV1O1j3ZT0IwDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw +MDMxODAzMTA0MloXDTMwMDMxNjAzMTA0MlowZTELMAkGA1UEBhMCVVMxETAPBgNV +BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRUwEwYDVQQKDAxFeGFtcGxl +LCBDby4xGjAYBgNVBAMMESoudGVzdC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5xOONxJJ8b8Qauvob5/7dPYZfIcd+uhAWL2ZlTPz +Qvu4oF0QI4iYgP5iGgry9zEtCM+YQS8UhiAlPlqa6ANxgiBSEyMHH/xE8lo/+caY +GeACqy640Jpl/JocFGo3xd1L8DCawjlaj6eu7T7T/tpAV2qq13b5710eNRbCAfFe +8yALiGQemx0IYhlZXNbIGWLBNhBhvVjJh7UvOqpADk4xtl8o5j0xgMIRg6WJGK6c +6ffSIg4eP1XmovNYZ9LLEJG68tF0Q/yIN43B4dt1oq4jzSdCbG4F1EiykT2TmwPV +YDi8tml6DfOCDGnit8svnMEmBv/fcPd31GSbXjF8M+KGGQIDAQABo2swaTAJBgNV +HRMEAjAAMAsGA1UdDwQEAwIF4DBPBgNVHREESDBGghAqLnRlc3QuZ29vZ2xlLmZy +ghh3YXRlcnpvb2kudGVzdC5nb29nbGUuYmWCEioudGVzdC55b3V0dWJlLmNvbYcE +wKgBAzANBgkqhkiG9w0BAQsFAAOCAQEAS8hDQA8PSgipgAml7Q3/djwQ644ghWQv +C2Kb+r30RCY1EyKNhnQnIIh/OUbBZvh0M0iYsy6xqXgfDhCB93AA6j0i5cS8fkhH +Jl4RK0tSkGQ3YNY4NzXwQP/vmUgfkw8VBAZ4Y4GKxppdATjffIW+srbAmdDruIRM +wPeikgOoRrXf0LA1fi4TqxARzeRwenQpayNfGHTvVF9aJkl8HoaMunTAdG5pIVcr +9GKi/gEMpXUJbbVv3U5frX1Wo4CFo+rZWJ/LyCMeb0jciNLxSdMwj/E/ZuExlyeZ +gc9ctPjSMvgSyXEKv6Vwobleeg88V2ZgzenziORoWj4KszG/lbQZvg== +-----END CERTIFICATE----- diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/empty.proto b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/empty.proto new file mode 100644 index 0000000000000..6a0aa88dfde13 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/empty.proto @@ -0,0 +1,28 @@ + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +// An empty message that you can re-use to avoid defining duplicated empty +// messages in your project. A typical example is to use it as argument or the +// return value of a service API. For instance: +// +// service Foo { +// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; +// }; +// +message Empty {} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/messages.proto b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/messages.proto new file mode 100644 index 0000000000000..7b1b7286dced1 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/messages.proto @@ -0,0 +1,165 @@ + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Message definitions to be used by integration test service definitions. + +syntax = "proto3"; + +package grpc.testing; + +// TODO(dgq): Go back to using well-known types once +// https://github.com/grpc/grpc/issues/6980 has been fixed. +// import "google/protobuf/wrappers.proto"; +message BoolValue { + // The bool value. + bool value = 1; +} + +// The type of payload that should be returned. +enum PayloadType { + // Compressable text format. + COMPRESSABLE = 0; +} + +// A block of data, to simply increase gRPC message size. +message Payload { + // The type of data in body. + PayloadType type = 1; + // Primary contents of payload. + bytes body = 2; +} + +// A protobuf representation for grpc status. This is used by test +// clients to specify a status that the server should attempt to return. +message EchoStatus { + int32 code = 1; + string message = 2; +} + +// Unary request. +message SimpleRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, server randomly chooses one from other formats. + PayloadType response_type = 1; + + // Desired payload size in the response from the server. + int32 response_size = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether SimpleResponse should include username. + bool fill_username = 4; + + // Whether SimpleResponse should include OAuth scope. + bool fill_oauth_scope = 5; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue response_compressed = 6; + + // Whether server should return a given status + EchoStatus response_status = 7; + + // Whether the server should expect this request to be compressed. + BoolValue expect_compressed = 8; +} + +// Unary response, as configured by the request. +message SimpleResponse { + // Payload to increase message size. + Payload payload = 1; + // The user the request came from, for verifying authentication was + // successful when the client expected it. + string username = 2; + // OAuth scope. + string oauth_scope = 3; +} + +// Client-streaming request. +message StreamingInputCallRequest { + // Optional input payload sent along with the request. + Payload payload = 1; + + // Whether the server should expect this request to be compressed. This field + // is "nullable" in order to interoperate seamlessly with servers not able to + // implement the full compression tests by introspecting the call to verify + // the request's compression status. + BoolValue expect_compressed = 2; + + // Not expecting any payload from the response. +} + +// Client-streaming response. +message StreamingInputCallResponse { + // Aggregated size of payloads received from the client. + int32 aggregated_payload_size = 1; +} + +// Configuration for a particular response. +message ResponseParameters { + // Desired payload sizes in responses from the server. + int32 size = 1; + + // Desired interval between consecutive responses in the response stream in + // microseconds. + int32 interval_us = 2; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue compressed = 3; +} + +// Server-streaming request. +message StreamingOutputCallRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, the payload from each response in the stream + // might be of different types. This is to simulate a mixed type of payload + // stream. + PayloadType response_type = 1; + + // Configuration for each expected response message. + repeated ResponseParameters response_parameters = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether server should return a given status + EchoStatus response_status = 7; +} + +// Server-streaming response, as configured by the request and parameters. +message StreamingOutputCallResponse { + // Payload to increase response size. + Payload payload = 1; +} + +// For reconnect interop test only. +// Client tells server what reconnection parameters it used. +message ReconnectParams { + int32 max_reconnect_backoff_ms = 1; +} + +// For reconnect interop test only. +// Server tells client whether its reconnects are following the spec and the +// reconnect backoffs it saw. +message ReconnectInfo { + bool passed = 1; + repeated int32 backoff_ms = 2; +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/test.proto b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/test.proto new file mode 100644 index 0000000000000..86d6ab60506a4 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Proto/grpc/testing/test.proto @@ -0,0 +1,79 @@ + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. + +syntax = "proto3"; + +import "empty.proto"; +import "messages.proto"; + +package grpc.testing; + +// A simple service to test the various types of RPCs and experiment with +// performance with various types of payload. +service TestService { + // One empty request followed by one empty response. + rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); + + // One request followed by one response. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by one response. Response has cache control + // headers set such that a caching HTTP proxy (such as GFE) can + // satisfy subsequent requests. + rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by a sequence of responses (streamed download). + // The server returns the payload with client desired type and sizes. + rpc StreamingOutputCall(StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by one response (streamed upload). + // The server returns the aggregated size of client payload as the result. + rpc StreamingInputCall(stream StreamingInputCallRequest) + returns (StreamingInputCallResponse); + + // A sequence of requests with each request served by the server immediately. + // As one request could lead to multiple responses, this interface + // demonstrates the idea of full duplexing. + rpc FullDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by a sequence of responses. + // The server buffers all the client requests and then serves them in order. A + // stream of responses are returned to the client when the server starts with + // first request. + rpc HalfDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // The test server will not implement this method. It will be used + // to test the behavior when clients call unimplemented methods. + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A simple service NOT implemented at servers so clients can test for +// that case. +service UnimplementedService { + // A call that no server should implement + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A service used to control reconnect server. +service ReconnectService { + rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty); + rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/Assert.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/Assert.cs new file mode 100644 index 0000000000000..7f15a7f962f95 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/Assert.cs @@ -0,0 +1,129 @@ +#region Copyright notice and license + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System.Collections; + +namespace Grpc.Shared.TestAssets +{ + internal static class Assert + { + public static void IsTrue(bool condition) + { + if (!condition) + { + throw new InvalidOperationException("Expected true but got false."); + } + } + + public static void IsFalse(bool condition) + { + if (condition) + { + throw new InvalidOperationException("Expected false but got true."); + } + } + + public static void AreEqual(object expected, object actual) + { + if (!Equals(expected, actual)) + { + throw new InvalidOperationException($"Expected {expected} but got {actual}."); + } + } + + public static void IsNotNull(object value) + { + if (value == null) + { + throw new InvalidOperationException("Expected not null but got null."); + } + } + + public static void Fail() + { + throw new InvalidOperationException("Failure assert."); + } + + public static async Task ThrowsAsync(Func action) where TException : Exception + { + try + { + await action(); + } + catch (Exception ex) + { + if (ex.GetType() == typeof(TException)) + { + return (TException)ex; + } + + throw new InvalidOperationException($"Expected ${typeof(TException)} but got ${ex.GetType()}."); + } + + throw new InvalidOperationException("No exception thrown."); + } + + public static TException Throws(Action action) where TException : Exception + { + try + { + action(); + } + catch (Exception ex) + { + if (ex.GetType() == typeof(TException)) + { + return (TException)ex; + } + + throw new InvalidOperationException($"Expected ${typeof(TException)} but got ${ex.GetType()}."); + } + + throw new InvalidOperationException("No exception thrown."); + } + + public static void Contains(object expected, ICollection actual) + { + foreach (var item in actual) + { + if (Equals(item, expected)) + { + return; + } + } + + throw new InvalidOperationException($"Could not find {expected} in the collection."); + } + } + + internal static class CollectionAssert + { + public static void AreEqual(IList expected, IList actual) + { + if (expected.Count != actual.Count) + { + throw new InvalidOperationException($"Collection lengths differ. {expected.Count} but got {actual.Count}."); + } + + for (var i = 0; i < expected.Count; i++) + { + Assert.AreEqual(expected[i]!, actual[i]!); + } + } + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/AsyncStreamExtensions.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/AsyncStreamExtensions.cs new file mode 100644 index 0000000000000..c129d45ed81c8 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/AsyncStreamExtensions.cs @@ -0,0 +1,81 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Grpc.Core; + +namespace Grpc.Shared.TestAssets +{ + // Implementation copied from https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs + internal static class AsyncStreamExtensions + { + /// + /// Reads the entire stream and executes an async action for each element. + /// + public static async Task ForEachAsync(this IAsyncStreamReader streamReader, Func asyncAction) + where T : class + { + while (await streamReader.MoveNext().ConfigureAwait(false)) + { + await asyncAction(streamReader.Current).ConfigureAwait(false); + } + } + + /// + /// Reads the entire stream and creates a list containing all the elements read. + /// + public static async Task> ToListAsync(this IAsyncStreamReader streamReader) + where T : class + { + var result = new List(); + while (await streamReader.MoveNext().ConfigureAwait(false)) + { + result.Add(streamReader.Current); + } + return result; + } + + /// + /// Writes all elements from given enumerable to the stream. + /// Completes the stream afterwards unless close = false. + /// + public static async Task WriteAllAsync(this IClientStreamWriter streamWriter, IEnumerable elements, bool complete = true) + where T : class + { + foreach (var element in elements) + { + await streamWriter.WriteAsync(element).ConfigureAwait(false); + } + if (complete) + { + await streamWriter.CompleteAsync().ConfigureAwait(false); + } + } + + /// + /// Writes all elements from given enumerable to the stream. + /// + public static async Task WriteAllAsync(this IServerStreamWriter streamWriter, IEnumerable elements) + where T : class + { + foreach (var element in elements) + { + await streamWriter.WriteAsync(element).ConfigureAwait(false); + } + } + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/ExceptionAssert.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/ExceptionAssert.cs new file mode 100644 index 0000000000000..7321b62df0871 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/ExceptionAssert.cs @@ -0,0 +1,54 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +namespace Grpc.Shared.TestAssets +{ + public static class ExceptionAssert + { + public static async Task ThrowsAsync(Func action, params string[] possibleMessages) + where TException : Exception + { + try + { + await action(); + } + catch (TException ex) + { + if (possibleMessages == null || possibleMessages.Length == 0) + { + return ex; + } + foreach (string possibleMessage in possibleMessages) + { + if (Assert.Equals(possibleMessage, ex.Message)) + { + return ex; + } + } + + throw new Exception("Unexpected exception message." + Environment.NewLine + "Expected one of: " + string.Join(Environment.NewLine, possibleMessages) + Environment.NewLine + "Got: " + ex.Message + Environment.NewLine + Environment.NewLine + ex); + } + catch (Exception ex) + { + throw new Exception($"Exception of type {typeof(TException).Name} expected; got exception of type {ex.GetType().Name}.", ex); + } + + throw new Exception($"Exception of type {typeof(TException).Name} expected. No exception thrown."); + } + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs new file mode 100644 index 0000000000000..d14ffe1a54bc4 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs @@ -0,0 +1,62 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Grpc.Core; +using Grpc.Net.Client; + +namespace Grpc.Shared.TestAssets +{ + public interface IChannelWrapper + { + ChannelBase Channel { get; } + Task ShutdownAsync(); + } + + public class GrpcChannelWrapper : IChannelWrapper + { + public ChannelBase Channel { get; } + + public GrpcChannelWrapper(GrpcChannel channel) + { + Channel = channel; + } + + public Task ShutdownAsync() + { + return Task.CompletedTask; + } + } + +#if !BLAZOR_WASM + public class CoreChannelWrapper : IChannelWrapper + { + private readonly Channel _channel; + public ChannelBase Channel => _channel; + + public CoreChannelWrapper(Channel channel) + { + _channel = channel; + } + + public Task ShutdownAsync() + { + return _channel.ShutdownAsync(); + } + } +#endif +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs new file mode 100644 index 0000000000000..9039cf0c70b0d --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs @@ -0,0 +1,906 @@ +#region Copyright notice and license + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System.Security.Cryptography.X509Certificates; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Net.Client; +using Grpc.Net.Client.Web; +using Grpc.Testing; +using Microsoft.Extensions.Logging; +using Empty = Grpc.Testing.Empty; +using System.Security.Authentication; + +#if !BLAZOR_WASM +using Google.Apis.Auth.OAuth2; +using Grpc.Auth; +using Grpc.Core.Logging; +using Grpc.Gateway.Testing; +using Newtonsoft.Json.Linq; +#endif + +namespace Grpc.Shared.TestAssets +{ + public class ClientOptions + { + public string? ClientType { get; set; } + public string? ServerHost { get; set; } + public string? ServerHostOverride { get; set; } + public int ServerPort { get; set; } + public string? TestCase { get; set; } + public bool UseTls { get; set; } + public bool UseTestCa { get; set; } + public string? DefaultServiceAccount { get; set; } + public string? OAuthScope { get; set; } + public string? ServiceAccountKeyFile { get; set; } + public string? GrpcWebMode { get; set; } + public bool UseWinHttp { get; set; } + public bool UseHttp3 { get; set; } + } + + public class InteropClient + { + internal const string CompressionRequestAlgorithmMetadataKey = "grpc-internal-encoding-request"; + + private readonly ClientOptions options; + private readonly ILoggerFactory loggerFactory; + private readonly ILogger logger; + + public InteropClient(ClientOptions options, ILoggerFactory loggerFactory) + { + this.options = options; + this.loggerFactory = loggerFactory; + this.logger = loggerFactory.CreateLogger(); + } + + public async Task Run() + { +#if !BLAZOR_WASM + var channel = IsHttpClient() ? await HttpClientCreateChannel() : await CoreCreateChannel(); +#else + var channel = await HttpClientCreateChannel(); +#endif + try + { + var message = "Running " + options.TestCase; + if (options.GrpcWebMode != null) + { + message += $" ({options.GrpcWebMode})"; + } + logger.LogInformation(message); + await RunTestCaseAsync(channel, options); + logger.LogInformation("Passed!"); + } + catch (Exception ex) + { + logger.LogInformation(ex, "Failed!"); + throw; + } + await channel.ShutdownAsync(); + } + + private async Task HttpClientCreateChannel() + { + var credentials = await CreateCredentialsAsync(useTestCaOverride: false); + + string scheme; + if (!options.UseTls) + { + scheme = "http"; + } + else + { + scheme = "https"; + } + + HttpMessageHandler httpMessageHandler; + if (!options.UseWinHttp) + { + httpMessageHandler = CreateHttpClientHandler(); + } + else + { + httpMessageHandler = CreateWinHttpHandler(); + } + + if (!string.IsNullOrEmpty(options.GrpcWebMode) && !string.Equals(options.GrpcWebMode, "None", StringComparison.OrdinalIgnoreCase)) + { + var mode = (GrpcWebMode)Enum.Parse(typeof(GrpcWebMode), options.GrpcWebMode); + httpMessageHandler = new GrpcWebHandler(mode, httpMessageHandler) + { + HttpVersion = new Version(1, 1) + }; + } + if (options.UseHttp3) + { +#if NET6_0_OR_GREATER + httpMessageHandler = new Http3DelegatingHandler(httpMessageHandler); +#else + throw new Exception("HTTP/3 requires .NET 6 or later."); +#endif + } + + var channel = GrpcChannel.ForAddress($"{scheme}://{options.ServerHost}:{options.ServerPort}", new GrpcChannelOptions + { + Credentials = credentials, + HttpHandler = httpMessageHandler, + LoggerFactory = loggerFactory + }); + + return new GrpcChannelWrapper(channel); + } + +#if NET6_0_OR_GREATER + private class Http3DelegatingHandler : DelegatingHandler + { + private static readonly Version Http3Version = new Version(3, 0); + + public Http3DelegatingHandler(HttpMessageHandler innerHandler) + { + InnerHandler = innerHandler; + } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + request.Version = Http3Version; + request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; + return base.SendAsync(request, cancellationToken); + } + } +#endif + + private static WinHttpHandler CreateWinHttpHandler() + { +#pragma warning disable CA1416 // Validate platform compatibility + var handler = new WinHttpHandler(); + handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; + handler.ServerCertificateValidationCallback = (message, cert, chain, errors) => true; + return handler; +#pragma warning restore CA1416 // Validate platform compatibility + } + + private HttpClientHandler CreateHttpClientHandler() + { + var httpClientHandler = new HttpClientHandler(); + httpClientHandler.ServerCertificateCustomValidationCallback = (a, b, c, d) => true; +#if !BLAZOR_WASM + httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; + + if (options.UseTestCa) + { + var pem = File.ReadAllText("Certs/ca.pem"); + var certData = GetBytesFromPem(pem, "CERTIFICATE"); + var cert = new X509Certificate2(certData!); + + httpClientHandler.ClientCertificates.Add(cert); + } +#endif + return httpClientHandler; + } + +#if !BLAZOR_WASM + private async Task CoreCreateChannel() + { + var credentials = await CreateCredentialsAsync(); + + List? channelOptions = null; + if (!string.IsNullOrEmpty(options.ServerHostOverride)) + { + channelOptions = new List + { + new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) + }; + } + var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); + await channel.ConnectAsync(); + return new CoreChannelWrapper(channel); + } +#endif + + private async Task CreateCredentialsAsync(bool? useTestCaOverride = null) + { + var credentials = ChannelCredentials.Insecure; + if (options.UseTls) + { +#if !BLAZOR_WASM + if (useTestCaOverride ?? options.UseTestCa) + { + credentials = TestCredentials.CreateSslCredentials(); + } + else +#endif + { + credentials = new SslCredentials(); + } + } + +#if !BLAZOR_WASM + if (options.TestCase == "jwt_token_creds") + { + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsTrue(googleCredential.IsCreateScopedRequired); + credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); + } + + if (options.TestCase == "compute_engine_creds") + { + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsFalse(googleCredential.IsCreateScopedRequired); + credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); + } +#else + await Task.Yield(); +#endif + return credentials; + } + + private bool IsHttpClient() => string.Equals(options.ClientType, "httpclient", StringComparison.OrdinalIgnoreCase); + + private static TClient CreateClient(IChannelWrapper channel) where TClient : ClientBase + { + return (TClient)Activator.CreateInstance(typeof(TClient), channel.Channel)!; + } + + public static IEnumerable TestNames => Tests.Keys; + + private static readonly Dictionary> Tests = new Dictionary> + { + ["empty_unary"] = RunEmptyUnary, + ["large_unary"] = RunLargeUnary, + ["client_streaming"] = RunClientStreamingAsync, + ["server_streaming"] = RunServerStreamingAsync, + ["ping_pong"] = RunPingPongAsync, + ["empty_stream"] = RunEmptyStreamAsync, + ["compute_engine_creds"] = RunComputeEngineCreds, +#if !BLAZOR_WASM + ["jwt_token_creds"] = RunJwtTokenCreds, + ["oauth2_auth_token"] = RunOAuth2AuthTokenAsync, + ["per_rpc_creds"] = RunPerRpcCredsAsync, +#endif + ["cancel_after_begin"] = RunCancelAfterBeginAsync, + ["cancel_after_first_response"] = RunCancelAfterFirstResponseAsync, + ["timeout_on_sleeping_server"] = RunTimeoutOnSleepingServerAsync, + ["custom_metadata"] = RunCustomMetadataAsync, + ["status_code_and_message"] = RunStatusCodeAndMessageAsync, + ["special_status_message"] = RunSpecialStatusMessageAsync, + ["unimplemented_service"] = RunUnimplementedService, + ["unimplemented_method"] = RunUnimplementedMethod, + ["client_compressed_unary"] = RunClientCompressedUnary, + ["client_compressed_streaming"] = RunClientCompressedStreamingAsync, + ["server_compressed_unary"] = RunServerCompressedUnary, + ["server_compressed_streaming"] = RunServerCompressedStreamingAsync + }; + + private async Task RunTestCaseAsync(IChannelWrapper channel, ClientOptions options) + { + if (!Tests.TryGetValue(options.TestCase!, out var test)) + { + throw new ArgumentException("Unknown test case " + options.TestCase); + } + + await test(channel, options); + } + + public static async Task RunEmptyUnary(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var response = await client.EmptyCallAsync(new Empty()); + Assert.IsNotNull(response); + } + + public static async Task RunLargeUnary(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var request = new SimpleRequest + { + ResponseSize = 314159, + Payload = CreateZerosPayload(271828) + }; + var response = await client.UnaryCallAsync(request); + + Assert.AreEqual(314159, response.Payload.Body.Length); + } + + public static async Task RunClientStreamingAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var bodySizes = new List { 27182, 8, 1828, 45904 }.Select((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); + + using (var call = client.StreamingInputCall()) + { + await call.RequestStream.WriteAllAsync(bodySizes); + + var response = await call.ResponseAsync; + Assert.AreEqual(74922, response.AggregatedPayloadSize); + } + } + + public static async Task RunServerStreamingAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var bodySizes = new List { 31415, 9, 2653, 58979 }; + + var request = new StreamingOutputCallRequest + { + ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size }) } + }; + + using (var call = client.StreamingOutputCall(request)) + { + var responseList = await call.ResponseStream.ToListAsync(); + CollectionAssert.AreEqual(bodySizes, responseList.Select((item) => item.Payload.Body.Length).ToList()); + } + } + + public static async Task RunPingPongAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + using (var call = client.FullDuplexCall()) + { + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseParameters = { new ResponseParameters { Size = 31415 } }, + Payload = CreateZerosPayload(27182) + }); + + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); + + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseParameters = { new ResponseParameters { Size = 9 } }, + Payload = CreateZerosPayload(8) + }); + + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); + + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseParameters = { new ResponseParameters { Size = 2653 } }, + Payload = CreateZerosPayload(1828) + }); + + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); + + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseParameters = { new ResponseParameters { Size = 58979 } }, + Payload = CreateZerosPayload(45904) + }); + + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); + + await call.RequestStream.CompleteAsync(); + + Assert.IsFalse(await call.ResponseStream.MoveNext()); + } + } + + public static async Task RunEmptyStreamAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + using (var call = client.FullDuplexCall()) + { + await call.RequestStream.CompleteAsync(); + + var responseList = await call.ResponseStream.ToListAsync(); + Assert.AreEqual(0, responseList.Count); + } + } + + public static async Task RunComputeEngineCreds(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + var defaultServiceAccount = options.DefaultServiceAccount!; + var oauthScope = options.OAuthScope!; + + var request = new SimpleRequest + { + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + FillUsername = true, + FillOauthScope = true + }; + + // not setting credentials here because they were set on channel already + var response = await client.UnaryCallAsync(request); + + Assert.AreEqual(314159, response.Payload.Body.Length); + Assert.IsFalse(string.IsNullOrEmpty(response.OauthScope)); + Assert.IsTrue(oauthScope.Contains(response.OauthScope)); + Assert.AreEqual(defaultServiceAccount, response.Username); + } + +#if !BLAZOR_WASM + public static async Task RunJwtTokenCreds(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var request = new SimpleRequest + { + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + FillUsername = true, + }; + + // not setting credentials here because they were set on channel already + var response = await client.UnaryCallAsync(request); + + Assert.AreEqual(314159, response.Payload.Body.Length); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); + } + + public static async Task RunOAuth2AuthTokenAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + var oauthScope = options.OAuthScope!; + + ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); + var oauth2Token = await credential.GetAccessTokenForRequestAsync(); + + var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token); + var request = new SimpleRequest + { + FillUsername = true, + FillOauthScope = true + }; + + var response = await client.UnaryCallAsync(request, new CallOptions(credentials: credentials)); + + Assert.IsFalse(string.IsNullOrEmpty(response.OauthScope)); + Assert.IsTrue(oauthScope.Contains(response.OauthScope)); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); + } + + public static async Task RunPerRpcCredsAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + var oauthScope = options.OAuthScope!; + + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + + var credentials = googleCredential.ToCallCredentials(); + var request = new SimpleRequest + { + FillUsername = true, + }; + + var response = await client.UnaryCallAsync(request, new CallOptions(credentials: credentials)); + + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); + } +#endif + + public static async Task RunCancelAfterBeginAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var cts = new CancellationTokenSource(); + using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) + { + // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. + await Task.Delay(1000); + cts.Cancel(); + + var ex = await Assert.ThrowsAsync(() => call.ResponseAsync); + Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); + } + } + + public static async Task RunCancelAfterFirstResponseAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var cts = new CancellationTokenSource(); + using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) + { + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseParameters = { new ResponseParameters { Size = 31415 } }, + Payload = CreateZerosPayload(27182) + }); + + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); + + cts.Cancel(); + + try + { + // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. + await call.ResponseStream.MoveNext(); + Assert.Fail(); + } + catch (RpcException ex) + { + Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); + } + } + } + + public static async Task RunTimeoutOnSleepingServerAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var deadline = DateTime.UtcNow.AddMilliseconds(1); + using (var call = client.FullDuplexCall(deadline: deadline)) + { + try + { + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) }); + } + catch (InvalidOperationException) + { + // Deadline was reached before write has started. Eat the exception and continue. + } + catch (RpcException) + { + // Deadline was reached before write has started. Eat the exception and continue. + } + + try + { + await call.ResponseStream.MoveNext(); + Assert.Fail(); + } + catch (RpcException ex) + { + Assert.AreEqual(StatusCode.DeadlineExceeded, ex.StatusCode); + } + } + } + + public static async Task RunCustomMetadataAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + { + // step 1: test unary call + var request = new SimpleRequest + { + ResponseSize = 314159, + Payload = CreateZerosPayload(271828) + }; + + var call = client.UnaryCallAsync(request, headers: CreateTestMetadata()); + await call.ResponseAsync; + + var responseHeaders = await call.ResponseHeadersAsync; + var responseTrailers = call.GetTrailers(); + + Assert.AreEqual("test_initial_metadata_value", responseHeaders.GetValue("x-grpc-test-echo-initial")!); + CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.GetValueBytes("x-grpc-test-echo-trailing-bin")!); + } + + { + // step 2: test full duplex call + var request = new StreamingOutputCallRequest + { + ResponseParameters = { new ResponseParameters { Size = 31415 } }, + Payload = CreateZerosPayload(27182) + }; + + var call = client.FullDuplexCall(headers: CreateTestMetadata()); + + await call.RequestStream.WriteAsync(request); + await call.RequestStream.CompleteAsync(); + await call.ResponseStream.ToListAsync(); + + var responseHeaders = await call.ResponseHeadersAsync; + var responseTrailers = call.GetTrailers(); + + Assert.AreEqual("test_initial_metadata_value", responseHeaders.GetValue("x-grpc-test-echo-initial")!); + CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.GetValueBytes("x-grpc-test-echo-trailing-bin")!); + } + } + + public static async Task RunStatusCodeAndMessageAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var echoStatus = new EchoStatus + { + Code = 2, + Message = "test status message" + }; + + { + // step 1: test unary call + var request = new SimpleRequest { ResponseStatus = echoStatus }; + + var e = await ExceptionAssert.ThrowsAsync(async () => await client.UnaryCallAsync(request)); + Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); + Assert.AreEqual(echoStatus.Message, e.Status.Detail); + } + + // We want to test a unary call in gRPC-Web but skip the unsupported full duplex call. +#if !BLAZOR_WASM + { + // step 2: test full duplex call + var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus }; + + var call = client.FullDuplexCall(); + await call.RequestStream.WriteAsync(request); + await call.RequestStream.CompleteAsync(); + + try + { + // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. + await call.ResponseStream.ToListAsync(); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); + Assert.AreEqual(echoStatus.Message, e.Status.Detail); + } + } +#endif + } + + public static async Task RunSpecialStatusMessageAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var echoStatus = new EchoStatus + { + Code = 2, + Message = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n" + }; + + try + { + await client.UnaryCallAsync(new SimpleRequest + { + ResponseStatus = echoStatus + }); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); + Assert.AreEqual(echoStatus.Message, e.Status.Detail); + } + } + + public static async Task RunUnimplementedService(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var e = await ExceptionAssert.ThrowsAsync(async () => await client.UnimplementedCallAsync(new Empty())); + + Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); + } + + public static async Task RunUnimplementedMethod(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var e = await ExceptionAssert.ThrowsAsync(async () => await client.UnimplementedCallAsync(new Empty())); + + Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); + } + + public static async Task RunClientCompressedUnary(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var probeRequest = new SimpleRequest + { + ExpectCompressed = new BoolValue + { + Value = true // lie about compression + }, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828) + }; + var e = await ExceptionAssert.ThrowsAsync(async () => await client.UnaryCallAsync(probeRequest, CreateClientCompressionMetadata(false))); + Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode); + + var compressedRequest = new SimpleRequest + { + ExpectCompressed = new BoolValue + { + Value = true + }, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828) + }; + var response1 = await client.UnaryCallAsync(compressedRequest, CreateClientCompressionMetadata(true)); + Assert.AreEqual(314159, response1.Payload.Body.Length); + + var uncompressedRequest = new SimpleRequest + { + ExpectCompressed = new BoolValue + { + Value = false + }, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828) + }; + var response2 = await client.UnaryCallAsync(uncompressedRequest, CreateClientCompressionMetadata(false)); + Assert.AreEqual(314159, response2.Payload.Body.Length); + } + + public static async Task RunClientCompressedStreamingAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + try + { + var probeCall = client.StreamingInputCall(CreateClientCompressionMetadata(false)); + await probeCall.RequestStream.WriteAsync(new StreamingInputCallRequest + { + ExpectCompressed = new BoolValue + { + Value = true + }, + Payload = CreateZerosPayload(27182) + }); + + // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. + await probeCall; + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode); + } + + var call = client.StreamingInputCall(CreateClientCompressionMetadata(true)); + await call.RequestStream.WriteAsync(new StreamingInputCallRequest + { + ExpectCompressed = new BoolValue + { + Value = true + }, + Payload = CreateZerosPayload(27182) + }); + + call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); + await call.RequestStream.WriteAsync(new StreamingInputCallRequest + { + ExpectCompressed = new BoolValue + { + Value = false + }, + Payload = CreateZerosPayload(45904) + }); + await call.RequestStream.CompleteAsync(); + + var response = await call.ResponseAsync; + Assert.AreEqual(73086, response.AggregatedPayloadSize); + } + + public static async Task RunServerCompressedUnary(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var request = new SimpleRequest + { + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + ResponseCompressed = new BoolValue { Value = true } + }; + var response = await client.UnaryCallAsync(request); + + // Compression of response message is not verified because there is no API available + Assert.AreEqual(314159, response.Payload.Body.Length); + + request = new SimpleRequest + { + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + ResponseCompressed = new BoolValue { Value = false } + }; + response = await client.UnaryCallAsync(request); + + // Compression of response message is not verified because there is no API available + Assert.AreEqual(314159, response.Payload.Body.Length); + } + + public static async Task RunServerCompressedStreamingAsync(IChannelWrapper channel, ClientOptions options) + { + var client = CreateClient(channel); + + var bodySizes = new List { 31415, 92653 }; + + var request = new StreamingOutputCallRequest + { + ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size, Compressed = new BoolValue { Value = true } }) } + }; + + using (var call = client.StreamingOutputCall(request)) + { + // Compression of response message is not verified because there is no API available + var responseList = await call.ResponseStream.ToListAsync(); + CollectionAssert.AreEqual(bodySizes, responseList.Select((item) => item.Payload.Body.Length).ToList()); + } + } + + private static Payload CreateZerosPayload(int size) + { + return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; + } + + private static Metadata CreateClientCompressionMetadata(bool compressed) + { + var algorithmName = compressed ? "gzip" : "identity"; + return new Metadata + { + { new Metadata.Entry(CompressionRequestAlgorithmMetadataKey, algorithmName) } + }; + } + + // extracts the client_email field from service account file used for auth test cases +#if !BLAZOR_WASM + private static string GetEmailFromServiceAccountFile() + { + string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS")!; + Assert.IsNotNull(keyFile); + var jobject = JObject.Parse(File.ReadAllText(keyFile)); + string email = jobject.GetValue("client_email")!.Value(); + Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. + return email; + } +#endif + + private static Metadata CreateTestMetadata() + { + return new Metadata + { + {"x-grpc-test-echo-initial", "test_initial_metadata_value"}, + {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}} + }; + } + + // TODO(JamesNK): PEM loading logic from https://stackoverflow.com/a/10498045/11829 + // .NET does not have a built-in API for loading pem files + // Consider providing ca file in a different format and removing method + private byte[]? GetBytesFromPem(string pemString, string section) + { + var header = $"-----BEGIN {section}-----"; + var footer = $"-----END {section}-----"; + + var start = pemString.IndexOf(header, StringComparison.Ordinal); + if (start == -1) + { + return null; + } + + start += header.Length; + var end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start; + + if (end == -1) + { + return null; + } + + return Convert.FromBase64String(pemString.Substring(start, end)); + } + } +} \ No newline at end of file diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/TestCredentials.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/TestCredentials.cs new file mode 100644 index 0000000000000..28b0bffd4e81c --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/TestCredentials.cs @@ -0,0 +1,74 @@ +#region Copyright notice and license + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System.Reflection; +using Grpc.Core; + +namespace Grpc.Shared.TestAssets +{ + /// + /// SSL Credentials for testing. + /// + public static class TestCredentials + { + public const string DefaultHostOverride = "foo.test.google.fr"; + + public static string ClientCertAuthorityPath + { + get + { + return GetPath("data/ca.pem"); + } + } + + public static string ServerCertChainPath + { + get + { + return GetPath("data/server1.pem"); + } + } + + public static string ServerPrivateKeyPath + { + get + { + return GetPath("data/server1.key"); + } + } + + public static SslCredentials CreateSslCredentials() + { + return new SslCredentials(File.ReadAllText(ClientCertAuthorityPath)); + } + + public static SslServerCredentials CreateSslServerCredentials() + { + var keyCertPair = new KeyCertificatePair( + File.ReadAllText(ServerCertChainPath), + File.ReadAllText(ServerPrivateKeyPath)); + return new SslServerCredentials(new[] { keyCertPair }); + } + + private static string GetPath(string relativePath) + { + var assemblyDir = Path.GetDirectoryName(typeof(TestCredentials).GetTypeInfo().Assembly.Location); + return Path.Combine(assemblyDir!, relativePath); + } + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/ca.pem b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/ca.pem new file mode 100644 index 0000000000000..49d39cd8ed5f8 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIUWrP0VvHcy+LP6UuYNtiL9gBhD5owDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw +MDMxNzE4NTk1MVoXDTMwMDMxNTE4NTk1MVowVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGdGVzdGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAsGL0oXflF0LzoM+Bh+qUU9yhqzw2w8OOX5mu/iNCyUOBrqaHi7mGHx73GD01 +diNzCzvlcQqdNIH6NQSL7DTpBjca66jYT9u73vZe2MDrr1nVbuLvfu9850cdxiUO +Inv5xf8+sTHG0C+a+VAvMhsLiRjsq+lXKRJyk5zkbbsETybqpxoJ+K7CoSy3yc/k +QIY3TipwEtwkKP4hzyo6KiGd/DPexie4nBUInN3bS1BUeNZ5zeaIC2eg3bkeeW7c +qT55b+Yen6CxY0TEkzBK6AKt/WUialKMgT0wbTxRZO7kUCH3Sq6e/wXeFdJ+HvdV +LPlAg5TnMaNpRdQih/8nRFpsdwIDAQABoyAwHjAMBgNVHRMEBTADAQH/MA4GA1Ud +DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEAkTrKZjBrJXHps/HrjNCFPb5a +THuGPCSsepe1wkKdSp1h4HGRpLoCgcLysCJ5hZhRpHkRihhef+rFHEe60UePQO3S +CVTtdJB4CYWpcNyXOdqefrbJW5QNljxgi6Fhvs7JJkBqdXIkWXtFk2eRgOIP2Eo9 +/OHQHlYnwZFrk6sp4wPyR+A95S0toZBcyDVz7u+hOW0pGK3wviOe9lvRgj/H3Pwt +bewb0l+MhRig0/DVHamyVxrDRbqInU1/GTNCwcZkXKYFWSf92U+kIcTth24Q1gcw +eZiLl5FfrWokUNytFElXob0V0a5/kbhiLc3yWmvWqHTpqCALbVyF+rKJo2f5Kw== +-----END CERTIFICATE----- diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml index 6ae87169b9e1e..4abc812459235 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml @@ -2,7 +2,6 @@ - From be51a783799d6b1ae512871eac73b60fd5b7426c Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 27 Jun 2022 21:02:34 +0200 Subject: [PATCH 08/31] Remove unnecessary code --- .../Android.Device_Emulator.gRPC.Test.csproj | 4 - .../testassets/Shared/IChannelWrapper.cs | 18 -- .../testassets/Shared/InteropClient.cs | 222 +----------------- 3 files changed, 10 insertions(+), 234 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index 4c1133ca0e52d..2edfe952e7231 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -19,9 +19,6 @@ CS8981;SYSLIB0039 - - - BLAZOR_WASM @@ -57,7 +54,6 @@ - diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs index d14ffe1a54bc4..b14bee133db0d 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/IChannelWrapper.cs @@ -41,22 +41,4 @@ public Task ShutdownAsync() return Task.CompletedTask; } } - -#if !BLAZOR_WASM - public class CoreChannelWrapper : IChannelWrapper - { - private readonly Channel _channel; - public ChannelBase Channel => _channel; - - public CoreChannelWrapper(Channel channel) - { - _channel = channel; - } - - public Task ShutdownAsync() - { - return _channel.ShutdownAsync(); - } - } -#endif } diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs index 9039cf0c70b0d..02b37a3491e16 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs @@ -26,14 +26,6 @@ using Empty = Grpc.Testing.Empty; using System.Security.Authentication; -#if !BLAZOR_WASM -using Google.Apis.Auth.OAuth2; -using Grpc.Auth; -using Grpc.Core.Logging; -using Grpc.Gateway.Testing; -using Newtonsoft.Json.Linq; -#endif - namespace Grpc.Shared.TestAssets { public class ClientOptions @@ -70,11 +62,8 @@ public InteropClient(ClientOptions options, ILoggerFactory loggerFactory) public async Task Run() { -#if !BLAZOR_WASM - var channel = IsHttpClient() ? await HttpClientCreateChannel() : await CoreCreateChannel(); -#else - var channel = await HttpClientCreateChannel(); -#endif + var channel = HttpClientCreateChannel(); + try { var message = "Running " + options.TestCase; @@ -94,9 +83,9 @@ public async Task Run() await channel.ShutdownAsync(); } - private async Task HttpClientCreateChannel() + private IChannelWrapper HttpClientCreateChannel() { - var credentials = await CreateCredentialsAsync(useTestCaOverride: false); + var credentials = CreateCredentials(useTestCaOverride: false); string scheme; if (!options.UseTls) @@ -176,78 +165,14 @@ private static WinHttpHandler CreateWinHttpHandler() private HttpClientHandler CreateHttpClientHandler() { - var httpClientHandler = new HttpClientHandler(); - httpClientHandler.ServerCertificateCustomValidationCallback = (a, b, c, d) => true; -#if !BLAZOR_WASM - httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - - if (options.UseTestCa) + return new HttpClientHandler { - var pem = File.ReadAllText("Certs/ca.pem"); - var certData = GetBytesFromPem(pem, "CERTIFICATE"); - var cert = new X509Certificate2(certData!); - - httpClientHandler.ClientCertificates.Add(cert); - } -#endif - return httpClientHandler; - } - -#if !BLAZOR_WASM - private async Task CoreCreateChannel() - { - var credentials = await CreateCredentialsAsync(); - - List? channelOptions = null; - if (!string.IsNullOrEmpty(options.ServerHostOverride)) - { - channelOptions = new List - { - new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) - }; - } - var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); - await channel.ConnectAsync(); - return new CoreChannelWrapper(channel); + ServerCertificateCustomValidationCallback = (request, cert, chain, sslPolicyErrors) => true + }; } -#endif - private async Task CreateCredentialsAsync(bool? useTestCaOverride = null) - { - var credentials = ChannelCredentials.Insecure; - if (options.UseTls) - { -#if !BLAZOR_WASM - if (useTestCaOverride ?? options.UseTestCa) - { - credentials = TestCredentials.CreateSslCredentials(); - } - else -#endif - { - credentials = new SslCredentials(); - } - } - -#if !BLAZOR_WASM - if (options.TestCase == "jwt_token_creds") - { - var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); - Assert.IsTrue(googleCredential.IsCreateScopedRequired); - credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); - } - - if (options.TestCase == "compute_engine_creds") - { - var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); - Assert.IsFalse(googleCredential.IsCreateScopedRequired); - credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); - } -#else - await Task.Yield(); -#endif - return credentials; - } + private ChannelCredentials CreateCredentials(bool? useTestCaOverride = null) + => options.UseTls ? new SslCredentials() : ChannelCredentials.Insecure; private bool IsHttpClient() => string.Equals(options.ClientType, "httpclient", StringComparison.OrdinalIgnoreCase); @@ -267,11 +192,6 @@ private static TClient CreateClient(IChannelWrapper channel) where TCli ["ping_pong"] = RunPingPongAsync, ["empty_stream"] = RunEmptyStreamAsync, ["compute_engine_creds"] = RunComputeEngineCreds, -#if !BLAZOR_WASM - ["jwt_token_creds"] = RunJwtTokenCreds, - ["oauth2_auth_token"] = RunOAuth2AuthTokenAsync, - ["per_rpc_creds"] = RunPerRpcCredsAsync, -#endif ["cancel_after_begin"] = RunCancelAfterBeginAsync, ["cancel_after_first_response"] = RunCancelAfterFirstResponseAsync, ["timeout_on_sleeping_server"] = RunTimeoutOnSleepingServerAsync, @@ -435,66 +355,6 @@ public static async Task RunComputeEngineCreds(IChannelWrapper channel, ClientOp Assert.AreEqual(defaultServiceAccount, response.Username); } -#if !BLAZOR_WASM - public static async Task RunJwtTokenCreds(IChannelWrapper channel, ClientOptions options) - { - var client = CreateClient(channel); - - var request = new SimpleRequest - { - ResponseSize = 314159, - Payload = CreateZerosPayload(271828), - FillUsername = true, - }; - - // not setting credentials here because they were set on channel already - var response = await client.UnaryCallAsync(request); - - Assert.AreEqual(314159, response.Payload.Body.Length); - Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); - } - - public static async Task RunOAuth2AuthTokenAsync(IChannelWrapper channel, ClientOptions options) - { - var client = CreateClient(channel); - var oauthScope = options.OAuthScope!; - - ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); - var oauth2Token = await credential.GetAccessTokenForRequestAsync(); - - var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token); - var request = new SimpleRequest - { - FillUsername = true, - FillOauthScope = true - }; - - var response = await client.UnaryCallAsync(request, new CallOptions(credentials: credentials)); - - Assert.IsFalse(string.IsNullOrEmpty(response.OauthScope)); - Assert.IsTrue(oauthScope.Contains(response.OauthScope)); - Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); - } - - public static async Task RunPerRpcCredsAsync(IChannelWrapper channel, ClientOptions options) - { - var client = CreateClient(channel); - var oauthScope = options.OAuthScope!; - - var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); - - var credentials = googleCredential.ToCallCredentials(); - var request = new SimpleRequest - { - FillUsername = true, - }; - - var response = await client.UnaryCallAsync(request, new CallOptions(credentials: credentials)); - - Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); - } -#endif - public static async Task RunCancelAfterBeginAsync(IChannelWrapper channel, ClientOptions options) { var client = CreateClient(channel); @@ -636,30 +496,6 @@ public static async Task RunStatusCodeAndMessageAsync(IChannelWrapper channel, C Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); Assert.AreEqual(echoStatus.Message, e.Status.Detail); } - - // We want to test a unary call in gRPC-Web but skip the unsupported full duplex call. -#if !BLAZOR_WASM - { - // step 2: test full duplex call - var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus }; - - var call = client.FullDuplexCall(); - await call.RequestStream.WriteAsync(request); - await call.RequestStream.CompleteAsync(); - - try - { - // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. - await call.ResponseStream.ToListAsync(); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); - Assert.AreEqual(echoStatus.Message, e.Status.Detail); - } - } -#endif } public static async Task RunSpecialStatusMessageAsync(IChannelWrapper channel, ClientOptions options) @@ -856,19 +692,6 @@ private static Metadata CreateClientCompressionMetadata(bool compressed) }; } - // extracts the client_email field from service account file used for auth test cases -#if !BLAZOR_WASM - private static string GetEmailFromServiceAccountFile() - { - string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS")!; - Assert.IsNotNull(keyFile); - var jobject = JObject.Parse(File.ReadAllText(keyFile)); - string email = jobject.GetValue("client_email")!.Value(); - Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. - return email; - } -#endif - private static Metadata CreateTestMetadata() { return new Metadata @@ -877,30 +700,5 @@ private static Metadata CreateTestMetadata() {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}} }; } - - // TODO(JamesNK): PEM loading logic from https://stackoverflow.com/a/10498045/11829 - // .NET does not have a built-in API for loading pem files - // Consider providing ca file in a different format and removing method - private byte[]? GetBytesFromPem(string pemString, string section) - { - var header = $"-----BEGIN {section}-----"; - var footer = $"-----END {section}-----"; - - var start = pemString.IndexOf(header, StringComparison.Ordinal); - if (start == -1) - { - return null; - } - - start += header.Length; - var end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start; - - if (end == -1) - { - return null; - } - - return Convert.FromBase64String(pemString.Substring(start, end)); - } } -} \ No newline at end of file +} From 28629aec216504b7fff5f1861d48c1d62d44dd8a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 20 Jul 2022 13:57:22 +0200 Subject: [PATCH 09/31] WIP: start working on CI configuration --- eng/pipelines/android-grpc-client-tests.yml | 66 ++++++++ .../testassets/InteropTestsWebsite/Dockerfile | 14 ++ .../InteropTestsWebsite.csproj | 29 ++++ .../testassets/InteropTestsWebsite/Program.cs | 79 ++++++++++ .../testassets/InteropTestsWebsite/README.md | 27 ++++ .../testassets/InteropTestsWebsite/Startup.cs | 54 +++++++ .../InteropTestsWebsite/TestServiceImpl.cs | 149 ++++++++++++++++++ 7 files changed, 418 insertions(+) create mode 100644 eng/pipelines/android-grpc-client-tests.yml create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Dockerfile create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Program.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/README.md create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Startup.cs create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/TestServiceImpl.cs diff --git a/eng/pipelines/android-grpc-client-tests.yml b/eng/pipelines/android-grpc-client-tests.yml new file mode 100644 index 0000000000000..7a0625d2cf191 --- /dev/null +++ b/eng/pipelines/android-grpc-client-tests.yml @@ -0,0 +1,66 @@ +# TODO file name == pipeline name (/azp run android-grpc-client-tests ?) +# +# TODO description + instructions +# +# We run this pipeline on a schedule and also developers can run it +# via /azp run command on PRs. +# +# Setting batch to true, triggers one build at a time. +# if there is a push while a build in progress, it will wait, +# until the running build finishes, and produce a build with all the changes +# that happened during the last build. +trigger: none + +schedules: + - cron: "0 9,21 * * *" # run at 9:00 and 21:00 (UTC) which is 1:00 and 13:00 (PST). + displayName: grpc-dotnet Android client test schedule + branches: + include: + - main + always: true # the test is independent of the changes to the main branch since the client code is in another repo + +# TODO do we need those variables? +# variables: +# - template: /eng/pipelines/common/variables.yml + +jobs: + +# TODO we basically need to: +# +# 1) cd src/tests/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet +# 2) docker build -t grpc-server -f testassets/InteropTestsWebsite . +# 3) docker run --name grpc-server -d -p 50052:50052 -p 80:80 grpc-server +# 4) adb reverse tcp:50052 tcp:50052; adb reverse tcp:80 tcp:80 +# 5) dotnet build -t:Run -p:Configuration=Release ../Android.Device_Emulator.gRPC.Test.csproj +# 6) ... expect the result to be 42 +# 7) docker stop grpc-server (if we care) +# +# so... 1-4) are helix pre-scripts, 5) is the main command, 7) is helix post-script? + +# +# Android devices +# Build the whole product using Mono and run libraries tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + # TODO which job template? + # jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + # - Android_arm TODO do we need/want it? + - Android_arm64 + jobParameters: + testGroup: innerloop + nameSuffix: AllSubsets_Mono # TODO ??? + # we don't want to build the whole .net + # buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAdditionalTimezoneChecks=true + timeoutInMinutes: 180 + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + +# TODO Android_x64, Android_x86 - do those queues have docker? \ No newline at end of file diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Dockerfile b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Dockerfile new file mode 100644 index 0000000000000..03cd06a5beddf --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Dockerfile @@ -0,0 +1,14 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env +WORKDIR /app + +# Copy everything +COPY . ./ +RUN dotnet --info +RUN dotnet restore testassets/InteropTestsWebsite +RUN dotnet publish testassets/InteropTestsWebsite --framework net6.0 -c Release -o out -p:LatestFramework=true + +# Build runtime image +FROM mcr.microsoft.com/dotnet/aspnet:6.0 +WORKDIR /app +COPY --from=build-env /app/out . +ENTRYPOINT ["dotnet", "InteropTestsWebsite.dll", "--port_http1", "80"] \ No newline at end of file diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj new file mode 100644 index 0000000000000..ec382ae658f4c --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + InProcess + false + enable + + + + CS8981;SYSLIB0039 + + + + + + + + + + + PreserveNewest + + + + + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Program.cs new file mode 100644 index 0000000000000..aae9586823225 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Program.cs @@ -0,0 +1,79 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Microsoft.AspNetCore.Server.Kestrel.Core; + +namespace InteropTestsWebsite +{ + public class Program + { + private const LogLevel MinimumLogLevel = LogLevel.Debug; + + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddLogging(builder => builder.SetMinimumLevel(MinimumLogLevel)); + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.ConfigureKestrel((context, options) => + { + // Support --port and --use_tls cmdline arguments normally supported + // by gRPC interop servers. + var http2Port = context.Configuration.GetValue("port", 50052); + var http1Port = context.Configuration.GetValue("port_http1", -1); + var http3Port = context.Configuration.GetValue("port_http3", -1); + var useTls = context.Configuration.GetValue("use_tls", false); + + options.Limits.MinRequestBodyDataRate = null; + options.ListenAnyIP(http2Port, o => ConfigureEndpoint(o, useTls, HttpProtocols.Http2)); + if (http1Port != -1) + { + options.ListenAnyIP(http1Port, o => ConfigureEndpoint(o, useTls, HttpProtocols.Http1)); + } + if (http3Port != -1) + { +#pragma warning disable CA2252 // This API requires opting into preview features + options.ListenAnyIP(http3Port, o => ConfigureEndpoint(o, useTls, HttpProtocols.Http3)); +#pragma warning restore CA2252 // This API requires opting into preview features + } + + void ConfigureEndpoint(ListenOptions listenOptions, bool useTls, HttpProtocols httpProtocols) + { + Console.WriteLine($"Enabling connection encryption: {useTls}"); + + if (useTls) + { + var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location); + var certPath = Path.Combine(basePath!, "Certs", "server1.pfx"); + + listenOptions.UseHttps(certPath, "1111"); + } + listenOptions.Protocols = httpProtocols; + } + }); + webBuilder.UseStartup(); + }); + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/README.md b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/README.md new file mode 100644 index 0000000000000..91c7085da85e2 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/README.md @@ -0,0 +1,27 @@ +Running Grpc.Core interop client against Grpc.AspNetCore.Server interop server. +Context: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md + +## Start the InteropTestsWebsite + +``` +# From this directory +$ dotnet run +Now listening on: http://localhost:50052 +``` + +## Build gRPC C# as a developer: +Follow https://github.com/grpc/grpc/tree/master/src/csharp +``` +python tools/run_tests/run_tests.py -l csharp -c dbg --build_only +``` + +## Running the interop client + +``` +cd src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 + +mono Grpc.IntegrationTesting.Client.exe --server_host=localhost --server_port=50052 --test_case=large_unary +``` + +NOTE: Currently the some tests will fail because not all the features are implemented +by Grpc.AspNetCore.Server diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Startup.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Startup.cs new file mode 100644 index 0000000000000..72cb5274edbe7 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/Startup.cs @@ -0,0 +1,54 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Grpc.Testing; + +namespace InteropTestsWebsite +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddGrpc(); + services.AddCors(o => + { + o.AddPolicy("InteropTests", builder => + { + builder.AllowAnyOrigin(); + builder.AllowAnyMethod(); + builder.AllowAnyHeader(); + builder.WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding", "x-grpc-test-echo-initial", "x-grpc-test-echo-trailing-bin"); + }); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.UseRouting(); + app.UseCors(); + app.UseGrpcWeb(); + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService().RequireCors("InteropTests").EnableGrpcWeb(); + }); + } + } +} diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/TestServiceImpl.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/TestServiceImpl.cs new file mode 100644 index 0000000000000..e9f46fea6a05c --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/TestServiceImpl.cs @@ -0,0 +1,149 @@ +#region Copyright notice and license + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Google.Protobuf; +using Grpc.Core; +using Grpc.Shared.TestAssets; + +namespace Grpc.Testing +{ + // Implementation copied from https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs + public class TestServiceImpl : TestService.TestServiceBase + { + public override Task EmptyCall(Empty request, ServerCallContext context) + { + return Task.FromResult(new Empty()); + } + + public override async Task UnaryCall(SimpleRequest request, ServerCallContext context) + { + await EnsureEchoMetadataAsync(context, request.ResponseCompressed?.Value ?? false); + EnsureEchoStatus(request.ResponseStatus, context); + EnsureCompression(request.ExpectCompressed, context); + + var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) }; + return response; + } + + public override async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter responseStream, ServerCallContext context) + { + await EnsureEchoMetadataAsync(context, request.ResponseParameters.Any(rp => rp.Compressed?.Value ?? false)); + EnsureEchoStatus(request.ResponseStatus, context); + + foreach (var responseParam in request.ResponseParameters) + { + responseStream.WriteOptions = !(responseParam.Compressed?.Value ?? false) + ? new WriteOptions(WriteFlags.NoCompress) + : null; + + var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) }; + await responseStream.WriteAsync(response); + } + } + + public override async Task StreamingInputCall(IAsyncStreamReader requestStream, ServerCallContext context) + { + await EnsureEchoMetadataAsync(context); + + int sum = 0; + await requestStream.ForEachAsync(request => + { + EnsureCompression(request.ExpectCompressed, context); + + sum += request.Payload.Body.Length; + return Task.CompletedTask; + }); + + return new StreamingInputCallResponse { AggregatedPayloadSize = sum }; + } + + public override async Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) + { + await EnsureEchoMetadataAsync(context); + + await requestStream.ForEachAsync(async request => + { + EnsureEchoStatus(request.ResponseStatus, context); + foreach (var responseParam in request.ResponseParameters) + { + var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) }; + await responseStream.WriteAsync(response); + } + }); + } + + public override Task HalfDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) + { + throw new NotImplementedException(); + } + + private static Payload CreateZerosPayload(int size) + { + return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; + } + + private static async Task EnsureEchoMetadataAsync(ServerCallContext context, bool enableCompression = false) + { + var echoInitialList = context.RequestHeaders.Where((entry) => entry.Key == "x-grpc-test-echo-initial").ToList(); + + // Append grpc internal compression header if compression is requested by the client + if (enableCompression) + { + echoInitialList.Add(new Metadata.Entry("grpc-internal-encoding-request", "gzip")); + } + + if (echoInitialList.Any()) + { + var entry = echoInitialList.Single(); + await context.WriteResponseHeadersAsync(new Metadata { entry }); + } + + var echoTrailingList = context.RequestHeaders.Where((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ToList(); + if (echoTrailingList.Any()) + { + context.ResponseTrailers.Add(echoTrailingList.Single()); + } + } + + private static void EnsureEchoStatus(EchoStatus responseStatus, ServerCallContext context) + { + if (responseStatus != null) + { + var statusCode = (StatusCode)responseStatus.Code; + context.Status = new Status(statusCode, responseStatus.Message); + } + } + + private static void EnsureCompression(BoolValue? expectCompressed, ServerCallContext context) + { + if (expectCompressed != null) + { + // ServerCallContext.RequestHeaders filters out grpc-* headers + // Get grpc-encoding from HttpContext instead + var encoding = context.GetHttpContext().Request.Headers.SingleOrDefault(h => string.Equals(h.Key, "grpc-encoding", StringComparison.OrdinalIgnoreCase)).Value.SingleOrDefault(); + if (expectCompressed.Value) + { + if (encoding == null || encoding == "identity") + { + throw new RpcException(new Status(StatusCode.InvalidArgument, string.Empty)); + } + } + } + } + } +} From 85eb8548c36c6f55cd3995a48d992def24ee3126 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 29 Jul 2022 13:05:19 +0200 Subject: [PATCH 10/31] Remove WinHttpHandler --- .../Android.Device_Emulator.gRPC.Test.csproj | 1 - .../Android/Device_Emulator/gRPC/Program.cs | 3 +-- .../testassets/Shared/InteropClient.cs | 22 +------------------ 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index 2edfe952e7231..72c132a8677ef 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -55,6 +55,5 @@ - diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index 4621ece91858e..1f3c090ab0b3a 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -20,7 +20,7 @@ new ClientOptions { ServerHost = "localhost", - ServerPort = 50052, + ServerPort = 3000, UseTls = true, }, }; @@ -42,7 +42,6 @@ OAuthScope: {options.OAuthScope} ServiceAccountKeyFile: {options.ServiceAccountKeyFile} GrpcWebMode: {options.GrpcWebMode} - UseWinHttp: {options.UseWinHttp} UseHttp3: {options.UseHttp3} --- """); diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs index 02b37a3491e16..88b9332bf7b0d 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs @@ -41,7 +41,6 @@ public class ClientOptions public string? OAuthScope { get; set; } public string? ServiceAccountKeyFile { get; set; } public string? GrpcWebMode { get; set; } - public bool UseWinHttp { get; set; } public bool UseHttp3 { get; set; } } @@ -97,16 +96,7 @@ private IChannelWrapper HttpClientCreateChannel() scheme = "https"; } - HttpMessageHandler httpMessageHandler; - if (!options.UseWinHttp) - { - httpMessageHandler = CreateHttpClientHandler(); - } - else - { - httpMessageHandler = CreateWinHttpHandler(); - } - + HttpMessageHandler httpMessageHandler = CreateHttpClientHandler(); if (!string.IsNullOrEmpty(options.GrpcWebMode) && !string.Equals(options.GrpcWebMode, "None", StringComparison.OrdinalIgnoreCase)) { var mode = (GrpcWebMode)Enum.Parse(typeof(GrpcWebMode), options.GrpcWebMode); @@ -153,16 +143,6 @@ protected override Task SendAsync(HttpRequestMessage reques } #endif - private static WinHttpHandler CreateWinHttpHandler() - { -#pragma warning disable CA1416 // Validate platform compatibility - var handler = new WinHttpHandler(); - handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; - handler.ServerCertificateValidationCallback = (message, cert, chain, errors) => true; - return handler; -#pragma warning restore CA1416 // Validate platform compatibility - } - private HttpClientHandler CreateHttpClientHandler() { return new HttpClientHandler From b4b2d09e10e33d7633eb1fb01ad6b3188e6d80de Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 29 Jul 2022 13:10:03 +0200 Subject: [PATCH 11/31] Fix problem with SSL --- .../Device_Emulator/gRPC/res/raw/server1.pem | 22 +++++++++++++++++++ .../gRPC/res/xml/network_security_config.xml | 1 + 2 files changed, 23 insertions(+) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/server1.pem diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/server1.pem b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/server1.pem new file mode 100644 index 0000000000000..88244f856c622 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/raw/server1.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIUbJfTREJ6k6/+oInWhV1O1j3ZT0IwDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw +MDMxODAzMTA0MloXDTMwMDMxNjAzMTA0MlowZTELMAkGA1UEBhMCVVMxETAPBgNV +BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRUwEwYDVQQKDAxFeGFtcGxl +LCBDby4xGjAYBgNVBAMMESoudGVzdC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5xOONxJJ8b8Qauvob5/7dPYZfIcd+uhAWL2ZlTPz +Qvu4oF0QI4iYgP5iGgry9zEtCM+YQS8UhiAlPlqa6ANxgiBSEyMHH/xE8lo/+caY +GeACqy640Jpl/JocFGo3xd1L8DCawjlaj6eu7T7T/tpAV2qq13b5710eNRbCAfFe +8yALiGQemx0IYhlZXNbIGWLBNhBhvVjJh7UvOqpADk4xtl8o5j0xgMIRg6WJGK6c +6ffSIg4eP1XmovNYZ9LLEJG68tF0Q/yIN43B4dt1oq4jzSdCbG4F1EiykT2TmwPV +YDi8tml6DfOCDGnit8svnMEmBv/fcPd31GSbXjF8M+KGGQIDAQABo2swaTAJBgNV +HRMEAjAAMAsGA1UdDwQEAwIF4DBPBgNVHREESDBGghAqLnRlc3QuZ29vZ2xlLmZy +ghh3YXRlcnpvb2kudGVzdC5nb29nbGUuYmWCEioudGVzdC55b3V0dWJlLmNvbYcE +wKgBAzANBgkqhkiG9w0BAQsFAAOCAQEAS8hDQA8PSgipgAml7Q3/djwQ644ghWQv +C2Kb+r30RCY1EyKNhnQnIIh/OUbBZvh0M0iYsy6xqXgfDhCB93AA6j0i5cS8fkhH +Jl4RK0tSkGQ3YNY4NzXwQP/vmUgfkw8VBAZ4Y4GKxppdATjffIW+srbAmdDruIRM +wPeikgOoRrXf0LA1fi4TqxARzeRwenQpayNfGHTvVF9aJkl8HoaMunTAdG5pIVcr +9GKi/gEMpXUJbbVv3U5frX1Wo4CFo+rZWJ/LyCMeb0jciNLxSdMwj/E/ZuExlyeZ +gc9ctPjSMvgSyXEKv6Vwobleeg88V2ZgzenziORoWj4KszG/lbQZvg== +-----END CERTIFICATE----- diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml index 4abc812459235..6ae87169b9e1e 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/res/xml/network_security_config.xml @@ -2,6 +2,7 @@ + From 9dac1c4154ac34423ce6ad0ade50ddde4a9996d4 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 29 Jul 2022 13:41:53 +0200 Subject: [PATCH 12/31] Change server host --- .../FunctionalTests/Android/Device_Emulator/gRPC/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index 1f3c090ab0b3a..5fe5c57476186 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -19,8 +19,8 @@ { new ClientOptions { - ServerHost = "localhost", - ServerPort = 3000, + ServerHost = "10.0.2.2", + ServerPort = 50052, UseTls = true, }, }; From 3a8908fb8789da8cabd3641fba070f9b9ea74bcb Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Fri, 29 Jul 2022 07:47:23 -0400 Subject: [PATCH 13/31] Setup CI (#1) * Get Docker container building & exported via test build * Changes * Add missing pfx certificate * changes * cleanup Co-authored-by: Simon Rozsival --- eng/liveBuilds.targets | 1 + eng/pipelines/android-grpc-client-tests.yml | 33 +++++------------- src/libraries/sendtohelixhelp.proj | 9 +++++ src/libraries/tests.proj | 17 +++++---- .../Android.Device_Emulator.gRPC.Test.csproj | 18 ++++++---- .../Android/Device_Emulator/gRPC/Program.cs | 2 +- .../testassets/Certs/InteropTests/.gitignore | 2 ++ .../testassets/Certs/InteropTests/server1.pfx | Bin 0 -> 3461 bytes .../{InteropTestsWebsite => }/Dockerfile | 9 ++--- .../InteropTestsWebsite/TestServiceImpl.cs | 2 +- 10 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pfx rename src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/{InteropTestsWebsite => }/Dockerfile (55%) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index be20c6f295177..05adb6305ba0a 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -30,6 +30,7 @@ $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'build')) $([MSBuild]::NormalizeDirectory('$(MonoArtifactsPath)', 'cross', $(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant()))) + $([MSBuild]::NormalizeDirectory('$(LibrariesArtifactsPath)', 'obj', 'grpcserver', 'docker')) $([MSBuild]::NormalizeDirectory('$(LibrariesArtifactsPath)', 'packages', '$(LibrariesConfiguration)')) $([MSBuild]::NormalizeDirectory('$(LibrariesPackagesDir)', 'Shipping')) diff --git a/eng/pipelines/android-grpc-client-tests.yml b/eng/pipelines/android-grpc-client-tests.yml index 7a0625d2cf191..f93d9cb683a3c 100644 --- a/eng/pipelines/android-grpc-client-tests.yml +++ b/eng/pipelines/android-grpc-client-tests.yml @@ -17,50 +17,33 @@ schedules: branches: include: - main - always: true # the test is independent of the changes to the main branch since the client code is in another repo + always: true -# TODO do we need those variables? -# variables: -# - template: /eng/pipelines/common/variables.yml +variables: + - template: /eng/pipelines/common/variables.yml jobs: -# TODO we basically need to: -# -# 1) cd src/tests/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet -# 2) docker build -t grpc-server -f testassets/InteropTestsWebsite . -# 3) docker run --name grpc-server -d -p 50052:50052 -p 80:80 grpc-server -# 4) adb reverse tcp:50052 tcp:50052; adb reverse tcp:80 tcp:80 -# 5) dotnet build -t:Run -p:Configuration=Release ../Android.Device_Emulator.gRPC.Test.csproj -# 6) ... expect the result to be 42 -# 7) docker stop grpc-server (if we care) -# -# so... 1-4) are helix pre-scripts, 5) is the main command, 7) is helix post-script? - # # Android devices # Build the whole product using Mono and run libraries tests # - template: /eng/pipelines/common/platform-matrix.yml parameters: - # TODO which job template? - # jobTemplate: /eng/pipelines/common/global-build-job.yml + jobTemplate: /eng/pipelines/common/global-build-job.yml helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml buildConfig: Release runtimeFlavor: mono platforms: - # - Android_arm TODO do we need/want it? - - Android_arm64 + - Android_x64 jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono # TODO ??? - # we don't want to build the whole .net - # buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAdditionalTimezoneChecks=true + nameSuffix: AllSubsets_Mono_gRPC + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunGrpcTestsOnly=true /p:BuildGrpcServerDockerImage=true timeoutInMinutes: 180 # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot + extraHelixArguments: /p:RunGrpcTestsOnly=true /p:BuildGrpcServerDockerImage=true testRunNamePrefixSuffix: Mono_$(_BuildConfig) - -# TODO Android_x64, Android_x86 - do those queues have docker? \ No newline at end of file diff --git a/src/libraries/sendtohelixhelp.proj b/src/libraries/sendtohelixhelp.proj index 59cd95650c13e..f7fadf8a6323f 100644 --- a/src/libraries/sendtohelixhelp.proj +++ b/src/libraries/sendtohelixhelp.proj @@ -155,6 +155,14 @@ + + + + + + + + @@ -165,6 +173,7 @@ @(HelixPreCommand) + @(HelixPostCommand) $(HelixCommandPrefix) @(HelixCommandPrefixItem -> 'set "%(Identity)"', ' & ') $(HelixCommandPrefix) @(HelixCommandPrefixItem, ' ') true diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index c1ea341e687c2..c9f177e95839e 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -569,7 +569,8 @@ - + + @@ -590,9 +591,11 @@ + - + @@ -628,7 +631,7 @@ BuildInParallel="false" /> - + @@ -637,13 +640,13 @@ BuildInParallel="false" /> - + - + @@ -652,13 +655,13 @@ BuildInParallel="false" /> - + - + - - - + + + - - + + - + + + + + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index 5fe5c57476186..a0bcaef7c3df2 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -21,7 +21,7 @@ { ServerHost = "10.0.2.2", ServerPort = 50052, - UseTls = true, + UseTls = false, }, }; diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore new file mode 100644 index 0000000000000..1789eacae4805 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore @@ -0,0 +1,2 @@ +# we need the server1.pfx file +!*.pfx diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pfx b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pfx new file mode 100644 index 0000000000000000000000000000000000000000..86036690a7a41a32a37fc6043339a8b69e0ce28f GIT binary patch literal 3461 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 Date: Fri, 29 Jul 2022 13:48:56 +0200 Subject: [PATCH 14/31] Use tls --- .../FunctionalTests/Android/Device_Emulator/gRPC/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index a0bcaef7c3df2..5fe5c57476186 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -21,7 +21,7 @@ { ServerHost = "10.0.2.2", ServerPort = 50052, - UseTls = false, + UseTls = true, }, }; From b7b40e772f0ad4b3b80145d34d305fe7441e2e08 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 29 Jul 2022 13:52:59 +0200 Subject: [PATCH 15/31] Update yml --- eng/pipelines/android-grpc-client-tests.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/eng/pipelines/android-grpc-client-tests.yml b/eng/pipelines/android-grpc-client-tests.yml index f93d9cb683a3c..5322771f3a963 100644 --- a/eng/pipelines/android-grpc-client-tests.yml +++ b/eng/pipelines/android-grpc-client-tests.yml @@ -1,7 +1,3 @@ -# TODO file name == pipeline name (/azp run android-grpc-client-tests ?) -# -# TODO description + instructions -# # We run this pipeline on a schedule and also developers can run it # via /azp run command on PRs. # @@ -25,7 +21,7 @@ variables: jobs: # -# Android devices +# Android emulators # Build the whole product using Mono and run libraries tests # - template: /eng/pipelines/common/platform-matrix.yml From 44bd21ca6d8e903883b70652778f8a1c9474afc0 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 29 Jul 2022 13:56:47 +0200 Subject: [PATCH 16/31] Revert changes to the mono Android sample app --- .../sample/Android/AndroidSampleApp.csproj | 1 - src/mono/sample/Android/Makefile | 2 +- src/mono/sample/Android/Program.cs | 40 +++---------------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/src/mono/sample/Android/AndroidSampleApp.csproj b/src/mono/sample/Android/AndroidSampleApp.csproj index 80c25fed3ef12..dabf1700dce5f 100644 --- a/src/mono/sample/Android/AndroidSampleApp.csproj +++ b/src/mono/sample/Android/AndroidSampleApp.csproj @@ -86,7 +86,6 @@ MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackDir)runtimes\android-$(TargetArchitecture)\native\include\mono-2.0" Assemblies="@(BundleAssemblies)" MainLibraryFileName="$(AssemblyName).dll" - IncludeNetworkSecurityConfig="$(IncludeNetworkSecurityConfig)" StripDebugSymbols="$(StripDebugSymbols)" RuntimeComponents="$(RuntimeComponents)" DiagnosticPorts="$(DiagnosticPorts)" diff --git a/src/mono/sample/Android/Makefile b/src/mono/sample/Android/Makefile index f656fc15bf45c..cbcf63db861f6 100644 --- a/src/mono/sample/Android/Makefile +++ b/src/mono/sample/Android/Makefile @@ -1,5 +1,5 @@ MONO_CONFIG=Release -MONO_ARCH?=arm64 +MONO_ARCH?=x64 DOTNET := ../../../../dotnet.sh USE_LLVM=true AOT=false diff --git a/src/mono/sample/Android/Program.cs b/src/mono/sample/Android/Program.cs index 89b7d2794f338..7dcc0f375db87 100644 --- a/src/mono/sample/Android/Program.cs +++ b/src/mono/sample/Android/Program.cs @@ -1,41 +1,13 @@ -#nullable enable +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Net; -using System.Net.Sockets; -using System.Net.Security; -using System.Security; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -TestAuthenticateAsClient(hostname: "microsoft.com"); -TestAuthenticateAsClient(hostname: "self-signed.badssl.com"); -TestAuthenticateAsClient(hostname: "expired.badssl.com"); - -void TestAuthenticateAsClient(string hostname, int port = 443) +public static class Program { - using var tcpClient = new TcpClient(); - IAsyncResult result = tcpClient.BeginConnect(hostname, port, null, null); - var connected = result.AsyncWaitHandle.WaitOne(2000, true); - if (connected) + public static int Main(string[] args) { - tcpClient.EndConnect(result); - var stream = new SslStream(tcpClient.GetStream(), false, ValidateServerCertificate, null); - try - { - stream.AuthenticateAsClient(hostname); - - Console.WriteLine($"OK - {hostname}:{port}"); - } - catch (Exception ex) - { - Console.WriteLine($"!! - {hostname}:{port} ({ex.Message})"); - Console.WriteLine(ex); - } + Console.WriteLine("Hello, Android!"); // logcat + return 42; } } - -bool ValidateServerCertificate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) -{ - return true; -} From 6e7f96e4501b425ed673e590ebcfe9cfc3c4dc69 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 9 Aug 2022 19:31:08 +0200 Subject: [PATCH 17/31] Bump android image version --- eng/pipelines/common/platform-matrix.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 4ae4b32db8a9f..3a28ef2052ce0 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -207,7 +207,7 @@ jobs: platform: Linux_bionic_arm64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220628174908-5789942 + image: ubuntu-18.04-android-20220803135138-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -236,7 +236,7 @@ jobs: platform: Linux_bionic_x64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220628174908-5789942 + image: ubuntu-18.04-android-20220803135138-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -494,7 +494,7 @@ jobs: platform: Android_x64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220628174908-5789942 + image: ubuntu-18.04-android-20220803135138-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -519,7 +519,7 @@ jobs: platform: Android_x86 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220628174908-5789942 + image: ubuntu-18.04-android-20220803135138-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -544,7 +544,7 @@ jobs: platform: Android_arm shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220628174908-5789942 + image: ubuntu-18.04-android-20220803135138-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -569,7 +569,7 @@ jobs: platform: Android_arm64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220628174908-5789942 + image: ubuntu-18.04-android-20220803135138-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono From 41d80a21bb20f45a0a039bb73afd0093534cec6a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 10 Aug 2022 14:24:22 +0200 Subject: [PATCH 18/31] Bump image version --- eng/pipelines/common/platform-matrix.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 3a28ef2052ce0..9262b5d36a165 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -207,7 +207,7 @@ jobs: platform: Linux_bionic_arm64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220803135138-8fcaabc + image: ubuntu-18.04-android-20220808192756-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -236,7 +236,7 @@ jobs: platform: Linux_bionic_x64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220803135138-8fcaabc + image: ubuntu-18.04-android-20220808192756-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -494,7 +494,7 @@ jobs: platform: Android_x64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220803135138-8fcaabc + image: ubuntu-18.04-android-20220808192756-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -519,7 +519,7 @@ jobs: platform: Android_x86 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220803135138-8fcaabc + image: ubuntu-18.04-android-20220808192756-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -544,7 +544,7 @@ jobs: platform: Android_arm shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220803135138-8fcaabc + image: ubuntu-18.04-android-20220808192756-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono @@ -569,7 +569,7 @@ jobs: platform: Android_arm64 shouldContinueOnError: ${{ parameters.shouldContinueOnError }} container: - image: ubuntu-18.04-android-20220803135138-8fcaabc + image: ubuntu-18.04-android-20220808192756-8fcaabc registry: mcr jobParameters: runtimeFlavor: mono From 124ed66e60285d369174e94c6cbe34dbdb02b408 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 10 Aug 2022 15:15:40 +0200 Subject: [PATCH 19/31] Enable TLS --- .../Device_Emulator/gRPC/grpc-dotnet/testassets/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Dockerfile b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Dockerfile index 0f502fea7af4b..a3e5798c601ce 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Dockerfile +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Dockerfile @@ -12,4 +12,4 @@ RUN dotnet publish --framework net6.0 -c Release -o out -p:LatestFramework=true FROM mcr.microsoft.com/dotnet/aspnet:6.0 WORKDIR /app COPY --from=build-env /app/InteropTestsWebsite/out . -ENTRYPOINT ["dotnet", "InteropTestsWebsite.dll", "--port_http1", "80"] +ENTRYPOINT ["dotnet", "InteropTestsWebsite.dll", "--use_tls", "true"] From 39f4009f8011f9640f9c746f1aaf32782785a379 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 12 Aug 2022 17:11:58 +0200 Subject: [PATCH 20/31] Remove hardcoded package versions --- eng/Versions.props | 5 +++++ .../Android.Device_Emulator.gRPC.Test.csproj | 16 ++++++++-------- .../Android/Device_Emulator/gRPC/NuGet.config | 6 ------ .../Android/Device_Emulator/gRPC/README.md | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) delete mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config diff --git a/eng/Versions.props b/eng/Versions.props index 8a0379bc1992a..1ac657953ad79 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -163,6 +163,11 @@ 2.0.4 4.12.0 2.14.3 + + 2.47.0 + 2.46.3 + 3.19.4 + 3.0.3 1.1.2-beta1.22403.2 diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index e31569990f27c..e72d726967c08 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -46,15 +46,15 @@ ProtoRoot="$(MSBuildProjectDirectory)\grpc-dotnet\testassets\Proto\grpc\testing\" GrpcServices="Client" /> - - - + + + - - - - - + + + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config deleted file mode 100644 index 95e879eff2bbb..0000000000000 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/NuGet.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md index 32bf183798b84..6ac6505242024 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/README.md @@ -1,2 +1,2 @@ -res - Android resource folder +res - Android resource folder containing self-signed certificates and Android network configuration dotnet-grpc - copied from https://github.com/grpc/grpc-dotnet From a11e4a878e4e916235387a2ddd9d31c72fbc7c7e Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 12 Aug 2022 17:52:07 +0200 Subject: [PATCH 21/31] Update package versions --- eng/Versions.props | 6 ++++-- .../gRPC/Android.Device_Emulator.gRPC.Test.csproj | 7 +++---- .../Android/Device_Emulator/gRPC/Program.cs | 1 - .../grpc-dotnet/testassets/Shared/InteropClient.cs | 14 -------------- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 1ac657953ad79..2de013283c901 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -164,9 +164,11 @@ 4.12.0 2.14.3 - 2.47.0 - 2.46.3 3.19.4 + 2.46.3 + 2.46.3 + 2.46.0 + 2.45.0 3.0.3 diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index e72d726967c08..ff57f19ab16eb 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -46,13 +46,12 @@ ProtoRoot="$(MSBuildProjectDirectory)\grpc-dotnet\testassets\Proto\grpc\testing\" GrpcServices="Client" /> - - - + - + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index 5fe5c57476186..66df44876f920 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -41,7 +41,6 @@ DefaultServiceAccount: {options.DefaultServiceAccount} OAuthScope: {options.OAuthScope} ServiceAccountKeyFile: {options.ServiceAccountKeyFile} - GrpcWebMode: {options.GrpcWebMode} UseHttp3: {options.UseHttp3} --- """); diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs index 88b9332bf7b0d..af6caf29b6439 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs @@ -20,7 +20,6 @@ using Google.Protobuf; using Grpc.Core; using Grpc.Net.Client; -using Grpc.Net.Client.Web; using Grpc.Testing; using Microsoft.Extensions.Logging; using Empty = Grpc.Testing.Empty; @@ -40,7 +39,6 @@ public class ClientOptions public string? DefaultServiceAccount { get; set; } public string? OAuthScope { get; set; } public string? ServiceAccountKeyFile { get; set; } - public string? GrpcWebMode { get; set; } public bool UseHttp3 { get; set; } } @@ -66,10 +64,6 @@ public async Task Run() try { var message = "Running " + options.TestCase; - if (options.GrpcWebMode != null) - { - message += $" ({options.GrpcWebMode})"; - } logger.LogInformation(message); await RunTestCaseAsync(channel, options); logger.LogInformation("Passed!"); @@ -97,14 +91,6 @@ private IChannelWrapper HttpClientCreateChannel() } HttpMessageHandler httpMessageHandler = CreateHttpClientHandler(); - if (!string.IsNullOrEmpty(options.GrpcWebMode) && !string.Equals(options.GrpcWebMode, "None", StringComparison.OrdinalIgnoreCase)) - { - var mode = (GrpcWebMode)Enum.Parse(typeof(GrpcWebMode), options.GrpcWebMode); - httpMessageHandler = new GrpcWebHandler(mode, httpMessageHandler) - { - HttpVersion = new Version(1, 1) - }; - } if (options.UseHttp3) { #if NET6_0_OR_GREATER From 764f74596841dd4cc93bd130a617ef8e0993c65d Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 12 Aug 2022 18:21:27 +0200 Subject: [PATCH 22/31] Update package versions --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 2de013283c901..a73f1804d6fe8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -167,7 +167,7 @@ 3.19.4 2.46.3 2.46.3 - 2.46.0 + 2.45.0 2.45.0 3.0.3 From e996d02e73e1400629acbaef13cc3f75da36a662 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 10:07:25 +0200 Subject: [PATCH 23/31] Rename pipeline --- ...rpc-client-tests.yml => runtime-android-grpc-client-tests.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename eng/pipelines/{android-grpc-client-tests.yml => runtime-android-grpc-client-tests.yml} (100%) diff --git a/eng/pipelines/android-grpc-client-tests.yml b/eng/pipelines/runtime-android-grpc-client-tests.yml similarity index 100% rename from eng/pipelines/android-grpc-client-tests.yml rename to eng/pipelines/runtime-android-grpc-client-tests.yml From 09c67c3e0d53cb1e2586dfc8ef443602b35305a9 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 10:11:41 +0200 Subject: [PATCH 24/31] Move interop tests website dependencies versions to Versions.props --- eng/Versions.props | 2 ++ .../InteropTestsWebsite/InteropTestsWebsite.csproj | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index a73f1804d6fe8..f9f3115e89bb6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -165,6 +165,8 @@ 2.14.3 3.19.4 + 2.46.0 + 2.46.0 2.46.3 2.46.3 2.45.0 diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj index ec382ae658f4c..88fff62b97aa6 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj @@ -21,9 +21,13 @@ PreserveNewest + + + - - + + + From c1bb0dd918cef07760023fb628cfe16b9acc4edf Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 10:14:10 +0200 Subject: [PATCH 25/31] Add cred scan supression for the interop test server private key --- .config/CredScanSuppressions.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.config/CredScanSuppressions.json b/.config/CredScanSuppressions.json index 2f274268f63fe..8235ef42fd7cc 100644 --- a/.config/CredScanSuppressions.json +++ b/.config/CredScanSuppressions.json @@ -7,7 +7,8 @@ "src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyPemTests.cs", "src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyPemTests.cs", "src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs", - "src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs" + "src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs", + "src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.key" ], "placeholder": [ "-----BEGIN PRIVATE KEY-----", From b9a02d8ca883a27c1525347b32c6e06face9be38 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 10:44:18 +0200 Subject: [PATCH 26/31] Fix licenses --- .../Android/Device_Emulator/gRPC/Program.cs | 3 +++ .../Device_Emulator/gRPC/THIRD-PARTY-NOTICES | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/THIRD-PARTY-NOTICES diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index 66df44876f920..d1e6772f999e2 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/THIRD-PARTY-NOTICES b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/THIRD-PARTY-NOTICES new file mode 100644 index 0000000000000..e0c2c13933e21 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/THIRD-PARTY-NOTICES @@ -0,0 +1,26 @@ +.NET Runtime uses third-party libraries or other resources that may be +distributed under licenses different than the .NET Runtime software. + +In the event that we accidentally failed to list a required notice, please +bring it to our attention. Post an issue or email us: + + dotnet@microsoft.com + +The attached notices are provided for information only. + +License notice for Grpc.Net.Client +------------------------------- + +Copyright 2019 The gRPC Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. From 6691bc04eeefe99fe52f6b6db12fa5c4a7ef2239 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 10:50:11 +0200 Subject: [PATCH 27/31] Remove dependencies --- .../Android.Device_Emulator.gRPC.Test.csproj | 2 -- .../Android/Device_Emulator/gRPC/Program.cs | 11 +++------ .../testassets/Shared/InteropClient.cs | 23 ++++--------------- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index ff57f19ab16eb..0550094d5cae8 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -52,8 +52,6 @@ - - diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs index d1e6772f999e2..21fda1ab72206 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs @@ -3,8 +3,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; // The code of the tests is cloned from https://github.com/grpc/grpc-dotnet using Grpc.Shared.TestAssets; @@ -79,18 +77,15 @@ void Log(string testName, string status) sealed class InteropClientWrapper { - private readonly InteropClient interopClient; + private readonly InteropClient _interopClient; [DynamicDependency(DynamicallyAccessedMemberTypes.All, "Grpc.Testing.TestService.TestServiceClient", "Android.Device_Emulator.gRPC.Test")] [DynamicDependency(DynamicallyAccessedMemberTypes.All, "Grpc.Testing.UnimplementedService.UnimplementedServiceClient", "Android.Device_Emulator.gRPC.Test")] public InteropClientWrapper(ClientOptions options) { - interopClient = new InteropClient( - options, - Microsoft.Extensions.Logging.Abstractions.NullLoggerFactory.Instance - ); + _interopClient = new InteropClient(options); } public Task Run() - => interopClient.Run(); + => _interopClient.Run(); } diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs index af6caf29b6439..12549f8515bdf 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs @@ -21,7 +21,6 @@ using Grpc.Core; using Grpc.Net.Client; using Grpc.Testing; -using Microsoft.Extensions.Logging; using Empty = Grpc.Testing.Empty; using System.Security.Authentication; @@ -47,32 +46,19 @@ public class InteropClient internal const string CompressionRequestAlgorithmMetadataKey = "grpc-internal-encoding-request"; private readonly ClientOptions options; - private readonly ILoggerFactory loggerFactory; - private readonly ILogger logger; - public InteropClient(ClientOptions options, ILoggerFactory loggerFactory) + public InteropClient(ClientOptions options) { this.options = options; - this.loggerFactory = loggerFactory; - this.logger = loggerFactory.CreateLogger(); } public async Task Run() { var channel = HttpClientCreateChannel(); - try - { - var message = "Running " + options.TestCase; - logger.LogInformation(message); - await RunTestCaseAsync(channel, options); - logger.LogInformation("Passed!"); - } - catch (Exception ex) - { - logger.LogInformation(ex, "Failed!"); - throw; - } + var message = "Running " + options.TestCase; + await RunTestCaseAsync(channel, options); + await channel.ShutdownAsync(); } @@ -104,7 +90,6 @@ private IChannelWrapper HttpClientCreateChannel() { Credentials = credentials, HttpHandler = httpMessageHandler, - LoggerFactory = loggerFactory }); return new GrpcChannelWrapper(channel); From 32034ad221afafb61b2ca04de584ce63c585710c Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 11:41:13 +0200 Subject: [PATCH 28/31] Fix path to Versions.props --- .../gRPC/Android.Device_Emulator.gRPC.Test.csproj | 1 - .../testassets/InteropTestsWebsite/InteropTestsWebsite.csproj | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index 0550094d5cae8..7b33e5eb5be04 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -46,7 +46,6 @@ ProtoRoot="$(MSBuildProjectDirectory)\grpc-dotnet\testassets\Proto\grpc\testing\" GrpcServices="Client" /> - diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj index 88fff62b97aa6..180d44a6f9dfc 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj @@ -22,8 +22,8 @@ PreserveNewest - - + + From d2ac3d8eaf3d70db928fb420fd82c62ee8f07067 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 13:54:55 +0200 Subject: [PATCH 29/31] Remove unnecessary dependency version --- eng/Versions.props | 1 - 1 file changed, 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index b4055111866a8..64fe0a45d60a4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -173,7 +173,6 @@ 2.46.3 2.45.0 2.45.0 - 3.0.3 1.1.2-beta1.22403.2 From 3bb36bfe658b03b25e7ede0c5d070a3fb327bcbb Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 13:56:24 +0200 Subject: [PATCH 30/31] Fix building docker image --- .../gRPC/Android.Device_Emulator.gRPC.Test.csproj | 1 + .../Device_Emulator/gRPC/grpc-dotnet/testassets/.gitignore | 5 +++++ .../grpc-dotnet/testassets/Certs/InteropTests/.gitignore | 2 -- .../InteropTestsWebsite/InteropTestsWebsite.csproj | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/.gitignore delete mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj index 7b33e5eb5be04..93f5817bc2aad 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Android.Device_Emulator.gRPC.Test.csproj @@ -54,6 +54,7 @@ + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/.gitignore b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/.gitignore new file mode 100644 index 0000000000000..434635979192b --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/.gitignore @@ -0,0 +1,5 @@ +# we need the server1.pfx file +!Certs/InteropTests/server1.pfx + +# we copy eng/Versions.props during the build process +InteropTestsWebsite/Versions.props diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore deleted file mode 100644 index 1789eacae4805..0000000000000 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# we need the server1.pfx file -!*.pfx diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj index 180d44a6f9dfc..0c763a85c8c88 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/InteropTestsWebsite/InteropTestsWebsite.csproj @@ -23,7 +23,7 @@ - + From 2cf9df95d3f6bd8bd82f64895f57b146c0caa597 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 24 Aug 2022 15:02:53 +0200 Subject: [PATCH 31/31] Change pfx password --- .../testassets/Certs/InteropTests/README.md | 2 +- .../testassets/Certs/InteropTests/server1.pfx | Bin 3461 -> 3461 bytes .../testassets/InteropTestsWebsite/Program.cs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md index 79206a4863a5d..18efda8276bb6 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/README.md @@ -2,7 +2,7 @@ Keys taken from https://github.com/grpc/grpc/tree/master/src/core/tsi/test_creds so that interop server in this project is compatible with interop clients implemented in other gRPC languages. -The server1.pem and server1.key were combined into server1.pfx. The password is 1111. These certs are not secure, do not use in production. +The server1.pem and server1.key were combined into server1.pfx. The password is PLACEHOLDER. These certs are not secure, do not use in production. ``` openssl pkcs12 -export -out server1.pfx -inkey server1.key -in server1.pem -certfile ca.pem ``` diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pfx b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.pfx index 86036690a7a41a32a37fc6043339a8b69e0ce28f..182e5ecfe7d1c7cd2ea247d3aea2903f9c2c73b6 100644 GIT binary patch delta 3283 zcmV;^3@r178-*K?U4LD`y>4JBkDCGl2mpYB2cVWg(-Zi`vOOh=7Sg5t&H*uD*X%BD zGzHZ(r^uHM?E!t+6GfAr@ZJ`@&K6(pamJQ5^j9`yl^FN^w=5G76)ze^(Jp;gQ*rgV z7F@pD^Fv`E#;XIToW9W{6pd_TgOW6{XEhWGjqg#747hl0$$tx4i`0Fx`gk$4exVyoEDXoJz{03a+Mf-@zO!dZ7+yu)8T(o>%iq})KYgwzxirYS*1DH0a6-XMAahHP9A?&?=QZEXe% z-pc1UY%^4OQh$b@ITov8iorTC-qrnDZhK>1EZ)hn>oo$*OjV6-%w zxcfzo1q(v^rCa1QNQ9jtOft1=6M2;u?-R-)OZ$xx-G8#oyF>7QMn~>sx8|~z=w5!u zsG+y$PTFlV7|nQ2PF91?8yqBDtys|6lyzpV@kr*^O$;_>xmA~wpuG<%g|DHZ)$jvk zMqoSPJtsRldj0L%8N+j1HbB29MiYpTfu6&L&RDA8z$l}@4(b$}Z_Pb{LCKBZjG%HJ z5#tt5sDHy_)UNwcuTn4;ND;S`2XDU#Bv-*I8g`3v5*@OI*|#aH8jn6Cu#L;vnn*^U z8r=IDYmN4nzhRaj{2700sVX(9la*go*lt?3Yre|%C}6?eXt1$sej}PSNNz*ib@&yG zSL?22NpR7sfM>0)TnffOx{RvUW)&69p1@A=1AoM&Dmj8)7yA;!N5w&;PQ$V7yh94U z*wX6EhMy&ZrnbL&RJGv zB0u#_9lCbpma&K=8YkJM>eCsMt=-Z-unpi=)ML(lox{!z0B|Bd!noQGothuv|M)hD z*%{b{B@z@-{=6KbMa5Hv@t~!DFD`pavVW*gvhF5=x(qVFqUF11`HRpe>Stg2hA?6g zs+C)GddQg{eP|Eip`80g-F-h33+frMuMTGSXMj+n7KfH`a7%wv6*_LP@^}llEJ?ZJ zX^okgjAxu^3!Ua2#yFG(!#v%W)z~K=+A7>~>PHFGas9<@Ap*5vE5%3k79XEj^?&Dj zmO{=I*uTI=Fg8E;DltdUY?9$Uh;Kzul+hNo4Kx1t-zM&ZTi>CZg%h?9hBnuOD-!;0 zKP<+(x|>-{W(#aL1+K8>u;YJ)(-6Mm(4mMj!-Iyb>3La137hQtFYrhI0i(Ptw=TU9 zf7u^LbOewfQ|oc}s83}9drZE^MFd#rI<(!_(`KrB8QYOB$tC&aQw9)Up<_{-S zc)>wR;J(kTT{I3AA|<9@^X5yxANxq!7YGb_i4xb3v2hcG3@I2&ZmU*n1g|}FZZzrp zm=XeB3h`|eX^eP&hi~WxV4es{3EZ0mBUq33bF?P@jf+O-D@u@CR)4b-t6?Q=%c?Bc zaAxi0V7P888ToAY3Z(8KMQ3qHmj{1p%2;!|PKRAKl%DMx-jZ_{eJzJK#ZfzPL#a)(O%m9EC`Nd>6~0nZAaqmkAw51|&C(q!Fp`8dOJ zBlkL}rt42t!B<>84Z0%o&)4Wz(K&2vhr!ex6t0TA4{gi(e1KeZVv7ufU%%*gXV)NU z+WWczxOEj3Rav7Hd;RV;T#xeL-F5xdaNvAubVd0EQJCxIm4Al@*Y(&&NW=$nh%jDW zv$`@2a867*z+sC6{=$hf4D9${lQ#C0KbMk(d6iE>=V-{=1D0ZLpKr$sNwbbCW!Sp@ zH`J24{31UztD;bsTigV0?=y7j-`lT71;sfzVLaci%P;m*v)w#Ywx|jeTr!PZ7iz}s ztefix>l*cM!#{jGf3bxs)0V#C>Hfu>t$<^Zn=%||8+6Z+*M2ml0v1jrNdPWF9(a4yu{ z`p^k?pKJH`%HmcUC5r$NUJ-pKY3fbryi6PE9q*lRa9FmUM<#|` zIPr|G;7-eKGh?dAsecNwe$M-ZxhN|lI1X+q)^In>F(;eW4e7phK^kUBoWlKx;D07n zEL2b1%KiLb>7-W6H|EE@L?aQemPAOfHcn|DBFI-te5k4eF~S}#NMzh`G!2CqQz;k2 z2g=Y9_94bN&UP3ca9X0`H!}p`Resg&RYJVj4g(}SU?Gy(o=w3d{Od%$vQ^gx`+;eY zZ(aWrn*q!RXr$F36BsZYA2dCuqkpMm+PU&hw4pAx+J*DtMt%8D<{!U&Vb#zSII z&Sk}o0>dXD;Y<)$Xg#e?a)q*QzVdn~oMA-jYzmG!NH{Ah9%LU0SscCBD-=`sNmG)w ze3Wh=gOsxQI>`p#tmN}s>$gitBXMAfl}LyEC{Hap`O6|efwNG8co-3)* zs+bKzQ_yU{JIMI-<9^h)UP>X-vC}gYi^jb*JETuF@m~IFjv*T77oMZwne=_{%%2&5 z`7vz9a`NDBe<)2bTA0fOV!&z#mwLC-O=@ zE`v}N-0|;+5s6AWSrlb+`~+}s6HAwDf3yyNl)hUdyXFwas%;mMu791Pg=0lx656~~ zy8i;uUM6Y-1+-i&KqP6;<|VdLi5kFuTh9dvg&Gu`SBoD~>c~qL)YLM);eF!oCPqNZ zv0t`$Cs+KV1pwHQfeo~fj3_IX&O%7PQi4Bn|NAb1`MW%Xh7%R21qT})=OkK z1P@^7JZ~}h`Vlp!<9`S%U0#m#-0OuW%Jp)4l#?--+CgU$fAd(V_)Iv8SQKgl>S42* zP7yU`BoHHP=(2;8i^-ZMtb>%r5YE7)=FC&`URdhYKu_uj6@w=L?3dgBOw{Q16t;@U@$~B;wkILwLCA^_#7YJ zr0TY0o>Z3LPGbRn$AXt=<9IT@O0?Df^mz6Bw=77^oEV?i?tRqnxY*tRfRx@agtM$E?Mviu*?OZIAz z!j=aKU~|Ks5r2K&*cOjjq^a>Zwe(hXyM;C%6sAi{gPVg>zDQekillSU6llpdO`~5_ z4M{p>Uim1K3r&OB)A`QN&ddn{z*WLSP!HC1U;|q^2p^{1?css&7aG7oi+6(M z8U9#WxSy1!JSnmb0OFaFQwoo=rw58UXjJ-sQa-9QH zRrd%TD1YU);Em&G%va)&=m}V*PCr_Zh^L@mxGAwEo5HBETC_pb=;2?9yTqvb!v8&|;KZNyc!My-GK=wH z64CsN0xEL}gjH(;QKw09t(hSy=k9T6VeM^b*UhLuOLx0_yc@OrMM*oQr^9Xjp*LkDIL7XgzQB=hH z4f>m`S=E=}?BI!1d>!LBWWLV?LVty%sU7>GK0KjO{D0%cVlV#+X4kLN-sS zt;Z}habyQuv;&+V(0ifa+;Zb+7;aO#t_+o-;k$Z#9N(WV16wWeL{G2v{j0gllYfqD zX8n+**y#vkB9z*viiB=gtt{RCI%aZdH*@Z%Nc$szd4#owieI>Pw)Go9U0d0J@Vw~j zNQ>m&Ny>x=v6kw`FE^i+wz}4BKzSx`(O9j9p?P`tEFKPT$!F2vGy{la6eYNU(Km3x zQm^W&%naY|8)IYwK#&XS!Q-30Z4G`yj23taIy`-!phnI z?+G{7T+V^;%B`RT+|y~8BnY&N(s#8wNKPf%ELHD49x1Gt2(iEQA>nRoq9E$|AHnf( zqh~1;bM~QrQdfB)Oo&_EBUxw%l8)l*#CT){qM9IJ|E}VCO^V(2wV7@{dVd<~C=wx3 z2w}4ox|AZZZQZb3gM2YlgCH%PDspF)^lc%BSf$9C{x0@%d~dK-76<{?Pc=OTlzf)Xo3SZoy!NgWs*UN@=abPh zdmON~Qg(c9Czh1~waZ#k+p(SM3B~$Piiw3(gXOQMKA<8tlGKO|FcX-Uucl231Nz6I8k zhcVjgOB3$LA*#314Q|!2H!?jKGj$4IMjL*emfk}*PK4Oe=E#?Y;aV7C``~kiSMvWq zK=w&Yh7EBljVjtF0olo?YW&B4#T)U_I#O`8p=ELhsA#`BPJh}X9dVR>LSbwS7B_mE z$XdSWm6D9vn#Hi0^61=!*?4E_=io#V*9BCpByh%uT~hg(+LWwdj4~8aZ9BKFxnyH% zIj4pCEg^aVn3~4;V`BR4aTMPUm8yy;pjw8hUOr|SnEHknRggEf#yA|Z#%5srDfdsD zRwC1{o}YyGsR{WnNRd_G6{Zl7ox&59fp1;E`Iq0TV(K?|Cf;$TIC|= zX|$A{4dUmS^E?=)q{0Ss9KL3H-;)gpMt}Kopu8bqVe0|{2ml0v1jxm)PiSp4bxSwl zQVegl=k(g>#&};cJwu#Wz)rta!N-}ei*uuOG~HdNKPXJ1KnrXlic+>dsR0qzRd6#wQjZ6CvgHLNlIjCQA8GK@?Rf+9LykVJTN}7mw-a=hTn=6JVbu2l!hCTbn zKHK^|Q@c4|V1)u!I*4N#GOjnq_J2_+q01XGP2LksT`~f>^z0mdP4Dyo?;Bv}{K3bG z#>m-N?X9v>7bB2E{tqZLqNpy4ESk{5AQFQl8sDujQh)9fXtAf%9*pQLv*HwM2|doF z)0Pmx#1vqkJBiq#XP)&14+XfY_;i^ker%FZ24RyviLN?d0UZsSVp~w>PJcOu^1>U0 z0)o7)i5#(*)_1t%N+%4vbDVVF!m>0O-5s|(oTMYS6QAs4-_0Lx2<~L}C^Q3y$G1l= zl4R`*E?oHyzz1Q#b&P{)bS}q^o(wW!jqH+e1CmE7V>b)JJ)@ttq;GqB!)PSSSM1M)pkAO!cu^KORMW1 zygzb~Mt_>2&OqA#2(Zrpg2;C(E{gUnq33vd4!V&^5hu-`A7HKY-Y~W{{XW=Qzz}9|sd_-3Bt`!heM~q0SWJU5AJ3 zj#Z*O_BT|X&|__??w#2kPJJ{VfGSpeD#t%hR*8RaXaWO zW=oR^r2}_WYXdG+@qgRm=~ zDfEY1ZeYI{*?(F2nlwNV*riT4_m=OeJ@OQj z3cPiBNxeGeOX-LZyUO5zA5C7unQ6;BU7CJo5!ewFJdr62^N8v;+u}Z&ocmk+gr-l_ z?c4txz>xx*`l^cY4V^+KNP{@z)v(BE)ZPC?CVlnKFkz<3FoW#1Su(!ldoL6Yt5)2~ z`m=@)^k;GA#vFOYxaGv&LKqoFwS`{{1v9z*GE{r}wh*B$>To$OnznLk#}N