Skip to content

Commit

Permalink
[Android] gRPC client tests (dotnet#73060)
Browse files Browse the repository at this point in the history
* WIP: add gRPC tests

* Fix AOT and trimming

* WIP

* Implement IncludeNetworkSecurityConfig

* Use IncludeNetworkSecurityConfig

* Fix gRPC test

* Avoid git checkout

* Remove unnecessary code

* WIP: start working on CI configuration

* Remove WinHttpHandler

* Fix problem with SSL

* Change server host

* Setup CI (#1)

* Get Docker container building & exported via test build

* Changes

* Add missing pfx certificate

* changes

* cleanup

Co-authored-by: Simon Rozsival <simon@rozsival.com>

* Use tls

* Update yml

* Revert changes to the mono Android sample app

* Bump android image version

* Bump image version

* Enable TLS

* Remove hardcoded package versions

* Update package versions

* Update package versions

* Rename pipeline

* Move interop tests website dependencies versions to Versions.props

* Add cred scan supression for the interop test server private key

* Fix licenses

* Remove dependencies

* Fix path to Versions.props

* Remove unnecessary dependency version

* Fix building docker image

* Change pfx password

Co-authored-by: Jo Shields <directhex@apebox.org>
  • Loading branch information
simonrozsival and directhex committed Aug 25, 2022
1 parent 79e3cd0 commit 7a4b0af
Show file tree
Hide file tree
Showing 36 changed files with 2,185 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .config/CredScanSuppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -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/tests/X509Certificates/TestData.cs"
"src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs",
"src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Certs/InteropTests/server1.key"
],
"placeholder": [
"-----BEGIN PRIVATE KEY-----",
Expand Down
8 changes: 8 additions & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@
<SQLitePCLRawbundle_greenVersion>2.0.4</SQLitePCLRawbundle_greenVersion>
<MoqVersion>4.12.0</MoqVersion>
<FsCheckVersion>2.14.3</FsCheckVersion>
<!-- Android gRPC client tests -->
<GoogleProtobufVersion>3.19.4</GoogleProtobufVersion>
<GrpcAspNetCoreVersion>2.46.0</GrpcAspNetCoreVersion>
<GrpcAspNetCoreWebVersion>2.46.0</GrpcAspNetCoreWebVersion>
<GrpcAuthVersion>2.46.3</GrpcAuthVersion>
<GrpcCoreVersion>2.46.3</GrpcCoreVersion>
<GrpcDotnetClientVersion>2.45.0</GrpcDotnetClientVersion>
<GrpcToolsVersion>2.45.0</GrpcToolsVersion>
<!-- Uncomment to set a fixed version, else the latest is used -->
<!--<SdkVersionForWorkloadTesting>7.0.100-rc.1.22402.35</SdkVersionForWorkloadTesting>-->
<CompilerPlatformTestingVersion>1.1.2-beta1.22403.2</CompilerPlatformTestingVersion>
Expand Down
1 change: 1 addition & 0 deletions eng/liveBuilds.targets
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<CoreCLRBuildIntegrationDir>$([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'build'))</CoreCLRBuildIntegrationDir>

<MonoAotCrossDir>$([MSBuild]::NormalizeDirectory('$(MonoArtifactsPath)', 'cross', $(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant())))</MonoAotCrossDir>
<GrpcServerDockerImageDir>$([MSBuild]::NormalizeDirectory('$(LibrariesArtifactsPath)', 'obj', 'grpcserver', 'docker'))</GrpcServerDockerImageDir>

<LibrariesPackagesDir>$([MSBuild]::NormalizeDirectory('$(LibrariesArtifactsPath)', 'packages', '$(LibrariesConfiguration)'))</LibrariesPackagesDir>
<LibrariesShippingPackagesDir>$([MSBuild]::NormalizeDirectory('$(LibrariesPackagesDir)', 'Shipping'))</LibrariesShippingPackagesDir>
Expand Down
12 changes: 6 additions & 6 deletions eng/pipelines/common/platform-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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-20220808192756-8fcaabc
registry: mcr
jobParameters:
runtimeFlavor: mono
Expand Down Expand Up @@ -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-20220808192756-8fcaabc
registry: mcr
jobParameters:
runtimeFlavor: mono
Expand Down Expand Up @@ -494,7 +494,7 @@ jobs:
platform: Android_x64
shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
container:
image: ubuntu-18.04-android-20220628174908-5789942
image: ubuntu-18.04-android-20220808192756-8fcaabc
registry: mcr
jobParameters:
runtimeFlavor: mono
Expand All @@ -519,7 +519,7 @@ jobs:
platform: Android_x86
shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
container:
image: ubuntu-18.04-android-20220628174908-5789942
image: ubuntu-18.04-android-20220808192756-8fcaabc
registry: mcr
jobParameters:
runtimeFlavor: mono
Expand All @@ -544,7 +544,7 @@ jobs:
platform: Android_arm
shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
container:
image: ubuntu-18.04-android-20220628174908-5789942
image: ubuntu-18.04-android-20220808192756-8fcaabc
registry: mcr
jobParameters:
runtimeFlavor: mono
Expand All @@ -569,7 +569,7 @@ jobs:
platform: Android_arm64
shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
container:
image: ubuntu-18.04-android-20220628174908-5789942
image: ubuntu-18.04-android-20220808192756-8fcaabc
registry: mcr
jobParameters:
runtimeFlavor: mono
Expand Down
45 changes: 45 additions & 0 deletions eng/pipelines/runtime-android-grpc-client-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 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

variables:
- template: /eng/pipelines/common/variables.yml

jobs:

#
# Android emulators
# Build the whole product using Mono and run libraries tests
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
buildConfig: Release
runtimeFlavor: mono
platforms:
- Android_x64
jobParameters:
testGroup: innerloop
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)
9 changes: 9 additions & 0 deletions src/libraries/sendtohelixhelp.proj
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@
<HelixProperties Condition="'$(Scenario)' != ''" Include="scenario" Value="$(Scenario)" />
</ItemGroup>

<ItemGroup Condition="'$(RunGrpcTestsOnly)' == 'true' and '$(BuildGrpcServerDockerImage)' == 'true'">
<HelixCorrelationPayload Include="$(GrpcServerDockerImageDir)" Destination="grpcserver" />
<HelixPreCommand Include="docker load -i $HELIX_CORRELATION_PAYLOAD/grpcserver/grpcserver.tar" />
<HelixPreCommand Include="docker run --name grpc-server -d -p 50052:50052 -p 80:80 grpc-server:latest" />
<HelixPostCommand Include="docker stop grpc-server" />
<HelixPostCommand Include="docker rmi -f grpc-server:latest" />
</ItemGroup>

<!-- Ensure that all HelixPreCommand items are ready before this -->
<Target Name="BuildHelixCommand">
<!-- setting DotNetCliVersion here to ensure that it is set to the intended value -->
Expand All @@ -165,6 +173,7 @@

<PropertyGroup>
<HelixPreCommands>@(HelixPreCommand)</HelixPreCommands>
<HelixPostCommands>@(HelixPostCommand)</HelixPostCommands>
<HelixCommandPrefix Condition="'$(WindowsShell)' == 'true' and @(HelixCommandPrefixItem->Count()) > 0" >$(HelixCommandPrefix) @(HelixCommandPrefixItem -> 'set &quot;%(Identity)&quot;', ' &amp; ')</HelixCommandPrefix>
<HelixCommandPrefix Condition="'$(WindowsShell)' != 'true' and @(HelixCommandPrefixItem->Count()) > 0 ">$(HelixCommandPrefix) @(HelixCommandPrefixItem, ' ')</HelixCommandPrefix>
<IncludeHelixCorrelationPayload Condition="'$(IncludeHelixCorrelationPayload)' == '' and '$(HelixCorrelationPayload)' != ''">true</IncludeHelixCorrelationPayload>
Expand Down
20 changes: 13 additions & 7 deletions src/libraries/tests.proj
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@
<!-- Crashes on CI (possibly flakey) -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Private.Xml/tests/Misc/System.Xml.Misc.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Dynamic.Runtime/tests/System.Dynamic.Runtime.Tests.csproj"/>

<!-- gRPC tests should be run only manually -->
<ProjectExclusions Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\gRPC\Android.Device_Emulator.gRPC.Test.csproj" />
</ItemGroup>

<ItemGroup Condition="('$(TargetOS)' == 'Android' or '$(TargetsLinuxBionic)' == 'true') and '$(TargetArchitecture)' == 'arm64' and '$(RunDisabledAndroidTests)' != 'true'">
Expand Down Expand Up @@ -540,7 +543,8 @@
</ItemGroup>

<ItemGroup>
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Runtime.Tests.csproj" />
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Runtime.Tests.csproj" />
<GrpcTestProject Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\gRPC\Android.Device_Emulator.gRPC.Test.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TestNativeAot)' == 'true'">
Expand All @@ -560,9 +564,11 @@
<ProjectReference Condition="'$(RunHighAOTResourceRequiringTestsOnly)' == 'true'"
Include="@(HighAOTResourceRequiringProject)"
BuildInParallel="false" />
<ProjectReference Condition="'$(RunGrpcTestsOnly)' == 'true'"
Include="@(GrpcTestProject)" />
</ItemGroup>

<ItemGroup Condition="'$(RunSmokeTestsOnly)' != 'true' and '$(RunHighAOTResourceRequiringTestsOnly)' != 'true'">
<ItemGroup Condition="'$(RunSmokeTestsOnly)' != 'true' and '$(RunGrpcTestsOnly)' != 'true' and '$(RunHighAOTResourceRequiringTestsOnly)' != 'true'">
<ProjectReference Include="$(MSBuildThisFileDirectory)*\tests\**\*.Tests.csproj"
Exclude="@(ProjectExclusions)"
Condition="'$(TestAssemblies)' == 'true'" />
Expand Down Expand Up @@ -606,7 +612,7 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)System.Formats.Cbor\tests\System.Formats.Cbor.Tests.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(TargetOS)' == 'iOSSimulator'">
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(RunGrpcTestsOnly)' != 'true' and '$(TargetOS)' == 'iOSSimulator'">
<!-- https://github.com/dotnet/runtime/issues/57666 -->
<!-- <ProjectReference Include="$(MonoProjectRoot)sample\iOS\Program.csproj"
BuildInParallel="false" /> -->
Expand All @@ -615,13 +621,13 @@
BuildInParallel="false" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(TargetOS)' == 'tvOS'">
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(RunGrpcTestsOnly)' != 'true' and '$(TargetOS)' == 'tvOS'">
<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\tvOS\Device\**\*.Test.csproj"
Exclude="@(ProjectExclusions)"
BuildInParallel="false" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(TargetOS)' == 'MacCatalyst'">
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(RunGrpcTestsOnly)' != 'true' and '$(TargetOS)' == 'MacCatalyst'">
<!-- https://github.com/dotnet/runtime/issues/57666 -->
<!-- <ProjectReference Include="$(MonoProjectRoot)sample\iOS\Program.csproj"
BuildInParallel="false" /> -->
Expand All @@ -630,13 +636,13 @@
BuildInParallel="false" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(TargetOS)' == 'tvOSSimulator'">
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(RunGrpcTestsOnly)' != 'true' and '$(TargetOS)' == 'tvOSSimulator'">
<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\tvOS\Simulator\**\*.Test.csproj"
Exclude="@(ProjectExclusions)"
BuildInParallel="false" />
</ItemGroup>

<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(TargetOS)' == 'Android'">
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(RunSmokeTestsOnly)' != 'true' and '$(RunGrpcTestsOnly)' != 'true' and '$(TargetOS)' == 'Android'">
<ProjectReference Include="$(MonoProjectRoot)sample\Android\AndroidSampleApp.csproj"
BuildInParallel="false" />
<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\Android\**\*.Test.csproj"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TestRuntime>true</TestRuntime>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<MainLibraryFileName>Android.Device_Emulator.gRPC.Test.dll</MainLibraryFileName>
<ExpectedExitCode>42</ExpectedExitCode>

<MonoForceInterpreter>false</MonoForceInterpreter>
<RunAOTCompilation>true</RunAOTCompilation>
<ForceAOT>true</ForceAOT>
<AOTWithLibraryFiles>true</AOTWithLibraryFiles>

<PublishTrimmed>true</PublishTrimmed>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>

<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Disable CS8981 because the generated code from the protobuf files contains classes with lowercase names -->
<!-- Disable SYSLIB0039 because the tests intentionally use TLS 1.0 and 1.1 -->
<NoWarn>CS8981;SYSLIB0039</NoWarn>
</PropertyGroup>

<PropertyGroup>
<IncludeNetworkSecurityConfig>true</IncludeNetworkSecurityConfig>
</PropertyGroup>

<ItemGroup>
<Compile Include="Program.cs" />

<None Include="$(MSBuildProjectDirectory)\res\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<!-- Based on grpc-dotnet's testassets/InteropTestsClient/InteropTestsClient.csproj -->
<ItemGroup>
<!-- Required for QUIC & HTTP/3 in .NET 6 - https://github.com/dotnet/runtime/pull/55332 -->
<RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />

<Compile Include="$(MSBuildProjectDirectory)\grpc-dotnet\testassets\Shared\*.cs" />
<Compile Include="$(MSBuildProjectDirectory)\grpc-dotnet\test\Shared\HttpEventSourceListener.cs" />

<Protobuf
Include="$(MSBuildProjectDirectory)\grpc-dotnet\testassets\Proto\grpc\testing\*.proto"
ProtoRoot="$(MSBuildProjectDirectory)\grpc-dotnet\testassets\Proto\grpc\testing\"
GrpcServices="Client" />

<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
<PackageReference Include="Grpc.Auth" Version="$(GrpcAuthVersion)" />
<PackageReference Include="Grpc.Core" Version="$(GrpcCoreVersion)" PrivateAssets="All" />
<PackageReference Include="Grpc.Net.Client" Version="$(GrpcDotnetClientVersion)" />
<PackageReference Include="Grpc.Tools" Version="$(GrpcToolsVersion)" PrivateAssets="All" />
</ItemGroup>

<Target Name="BuildServerDockerImage" AfterTargets="Build" Condition="'$(BuildGrpcServerDockerImage)' == 'true'">
<Exec Command="cp $(RepoRoot)eng/Versions.props grpc-dotnet/testassets/InteropTestsWebsite/" />
<Exec Command="docker build -t grpc-server:latest grpc-dotnet/testassets/" />
<Exec Command="mkdir -p $(ArtifactsObjDir)/grpcserver/docker/" />
<Exec Command="docker save -o $(ArtifactsObjDir)/grpcserver/docker/grpcserver.tar grpc-server:latest" />
</Target>
</Project>
91 changes: 91 additions & 0 deletions src/tests/FunctionalTests/Android/Device_Emulator/gRPC/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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;

// The code of the tests is cloned from https://github.com/grpc/grpc-dotnet
using Grpc.Shared.TestAssets;

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 = "10.0.2.2",
ServerPort = 50052,
UseTls = true,
},
};

int failedTests = 0;

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}
UseHttp3: {options.UseHttp3}
---
""");

foreach (var testName in InteropClient.TestNames)
{
if (skippedTests.Contains(testName))
{
Log(testName, "SKIPPED");
continue;
}

options.TestCase = testName;
var client = new InteropClientWrapper(options);

try
{
Log(testName, "STARTED");
await client.Run();
Log(testName, "PASSED");
} catch (Exception e) {
Log(testName, "FAILED");
Console.Error.WriteLine(e);
failedTests++;
}
}
}

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);
}

public Task Run()
=> _interopClient.Run();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
res - Android resource folder containing self-signed certificates and Android network configuration
dotnet-grpc - copied from https://github.com/grpc/grpc-dotnet
Loading

0 comments on commit 7a4b0af

Please sign in to comment.