Skip to content

Commit 2d57ed3

Browse files
committed
feat: standing up the GRPC service and running conformance tests with kokoro and Github actions
1 parent 31ce6ee commit 2d57ed3

File tree

11 files changed

+197
-7124
lines changed

11 files changed

+197
-7124
lines changed
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# Github action job to test core java library features on
15+
# downstream client libraries before they are released.
16+
on:
17+
push:
18+
branches:
19+
- main
20+
pull_request:
21+
name: bigtable-conformance
22+
jobs:
23+
conformance:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- uses: actions/checkout@v4
27+
with:
28+
submodules: true
29+
- uses: actions/checkout@v4
30+
with:
31+
repository: googleapis/cloud-bigtable-clients-test
32+
ref: main
33+
path: cloud-bigtable-clients-test
34+
- uses: actions/setup-dotnet@v4
35+
with:
36+
dotnet-version: 6.0.x
37+
- uses: actions/setup-go@v5
38+
with:
39+
go-version: '>=1.20.2'
40+
- run: dotnet --version
41+
- run: go version
42+
- run: .kokoro/bigtable-conformance.sh

.kokoro/bigtable-conformance.sh

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/bin/bash
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
set -eo pipefail
17+
18+
## Get the directory of the build script
19+
scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}"))
20+
## cd to the parent directory, i.e. the root of the git repo
21+
cd ${scriptDir}/..
22+
23+
set +e
24+
25+
# Build the proxy
26+
pushd .
27+
cd apis/Google.Cloud.Bigtable.V2/Google.Cloud.Bigtable.V2ConformanceTest
28+
dotnet build
29+
popd
30+
31+
declare -a configs=("default" "enable_all")
32+
for config in "${configs[@]}"
33+
do
34+
# Start the proxy in a separate process
35+
dotnet run
36+
37+
# Run the conformance test
38+
if [[ ${config} = "enable_all" ]]
39+
then
40+
echo "Testing the client with all optional features enabled..."
41+
configFlag="--enable_features_all"
42+
else
43+
echo "Testing the client with default settings for optional features..."
44+
# skipping routing cookie and retry info tests. When the feature is disabled, these
45+
# tests are expected to fail
46+
configFlag="-skip _Retry_WithRoutingCookie\|_Retry_WithRetryInfo"
47+
fi
48+
49+
pushd .
50+
cd cloud-bigtable-clients-test/tests
51+
eval "go test -v -proxy_addr=:7238 ${configFlag} -skip '`cat ../../apis/Google.Cloud.Bigtable.V2/Google.Cloud.Bigtable.V2ConformanceTest/known_failures.txt`'"
52+
returnCode=$?
53+
popd
54+
55+
# Stop the proxy
56+
kill ${proxyPID}
57+
58+
if [[ ${returnCode} -gt 0 ]]
59+
then
60+
echo "Conformance test failed for config: ${config}"
61+
RETURN_CODE=${returnCode}
62+
else
63+
echo "Conformance test passed for config: ${config}"
64+
fi
65+
done
66+
67+
exit ${RETURN_CODE}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
<?xml version="1.0" encoding="utf-8"?>
2-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
33
<PropertyGroup>
4-
<TargetFrameworks>net6.0;net462</TargetFrameworks>
5-
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net6.0</TargetFrameworks>
6-
<IsPackable>false</IsPackable>
7-
<NoWarn>1701;1702;1705;xUnit2004;xUnit2013</NoWarn>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
87
</PropertyGroup>
8+
99
<ItemGroup>
1010
<ProjectReference Include="..\Google.Cloud.Bigtable.V2\Google.Cloud.Bigtable.V2.csproj" />
1111
</ItemGroup>
12+
13+
<ItemGroup>
14+
<Protobuf Include="Protos\test_proxy.proto" GrpcServices="Server" AdditionalImportDirs="..\..\..\googleapis;.\googleapis" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="Grpc.AspNetCore" VersionOverride="2.40.0" />
19+
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" VersionOverride="2.3.0" />
20+
</ItemGroup>
21+
1222
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Google.Cloud.Bigtable.V2.ConformanceTests.Services;
2+
using Microsoft.AspNetCore.Server.Kestrel.Core;
3+
4+
var builder = WebApplication.CreateBuilder(args);
5+
6+
builder.WebHost.ConfigureKestrel(options =>
7+
{
8+
// Setup a HTTP/2 endpoint without TLS.
9+
options.ListenLocalhost(7238, o => o.Protocols =
10+
HttpProtocols.Http2);
11+
});
12+
// Additional configuration is required to successfully run gRPC on macOS.
13+
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
14+
15+
// Add services to the container.
16+
builder.Services.AddGrpc();
17+
18+
var app = builder.Build();
19+
20+
// Configure the HTTP request pipeline.
21+
app.MapGrpcService<CloudBigtableV2TestProxyImpl>();
22+
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
23+
24+
app.Run();

apis/Google.Cloud.Bigtable.V2/Google.Cloud.Bigtable.V2.ConformanceTests/Protos/test_proxy.proto

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
syntax = "proto3";
1616

17-
package google.cloud.bigtable.v2.conformanceTests;
17+
package google.cloud.bigtable.v2.ConformanceTests;
1818

1919
import "google/api/client.proto";
2020
import "google/bigtable/v2/bigtable.proto";

apis/Google.Cloud.Bigtable.V2/Google.Cloud.Bigtable.V2.ConformanceTests/CloudBigtableV2TestProxyImpl.cs renamed to apis/Google.Cloud.Bigtable.V2/Google.Cloud.Bigtable.V2.ConformanceTests/Services/CloudBigtableV2TestProxyImpl.cs

+24-18
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,23 @@
1818
using Google.Cloud.Bigtable.Common.V2;
1919
using Grpc.Auth;
2020
using Grpc.Core;
21-
using System;
22-
using System.Collections.Generic;
23-
using System.Linq;
24-
using System.Threading.Tasks;
2521

26-
namespace Google.Cloud.Bigtable.V2.ConformanceTests;
22+
namespace Google.Cloud.Bigtable.V2.ConformanceTests.Services;
2723

2824
public sealed class CloudBigtableV2TestProxyImpl : CloudBigtableV2TestProxy.CloudBigtableV2TestProxyBase
2925
{
3026
private class CbtClient
3127
{
32-
public BigtableClient Client { get; set; }
33-
public ChannelBase LastCreatedChannel { get; set; }
34-
public InstanceName InstanceName { get; set; }
28+
public BigtableClient Client { get; private set; }
29+
public ChannelBase LastCreatedChannel { get; private set; }
30+
public InstanceName InstanceName { get; private set; }
31+
32+
public CbtClient(BigtableClient bigtableClient, ChannelBase channelBase, InstanceName instanceName)
33+
{
34+
Client = bigtableClient;
35+
LastCreatedChannel = channelBase;
36+
InstanceName = instanceName;
37+
}
3538
}
3639

3740
private readonly Dictionary<string, CbtClient> _idClientMap;
@@ -52,11 +55,13 @@ public override async Task<CreateClientResponse> CreateClient(CreateClientReques
5255
|| (securityOptions.SslRootCertsPem is not ("" or null)), "SecurityOptions",
5356
"security_options.ssl_root_certs_pem must be provided if security_options.use_ssl is true");
5457

58+
#pragma warning disable CS8604 // Possible null reference argument.
5559
if (_idClientMap.ContainsKey(clientId))
5660
{
5761
context.Status = new Status(StatusCode.AlreadyExists, $"Client {clientId} already exists");
5862
throw new RpcException(context.Status);
5963
}
64+
#pragma warning restore CS8604 // Possible null reference argument.
6065

6166
try
6267
{
@@ -77,7 +82,9 @@ public override async Task<CreateClientResponse> CreateClient(CreateClientReques
7782
if (dataTarget != "emulator")
7883
{
7984
builder.Endpoint = dataTarget;
85+
#pragma warning disable CS8604 // Possible null reference argument.
8086
builder.ChannelCredentials = GetChannelCredentials(securityOptions.UseSsl, securityOptions.SslRootCertsPem, securityOptions.AccessToken);
87+
#pragma warning restore CS8604 // Possible null reference argument.
8188
builder.GrpcChannelOptions = (securityOptions.UseSsl && securityOptions.SslEndpointOverride is not null)
8289
? GrpcChannelOptions.Empty.WithCustomOption("grpc.ssl_target_name_override", securityOptions.SslEndpointOverride)
8390
: GrpcChannelOptions.Empty;
@@ -89,12 +96,7 @@ public override async Task<CreateClientResponse> CreateClient(CreateClientReques
8996
InstanceName instanceName = new InstanceName(projectId, instanceId);
9097
BigtableServiceApiClient apiClient = await builder.BuildAsync();
9198

92-
CbtClient cbtClient = new CbtClient
93-
{
94-
Client = BigtableClient.Create(apiClient),
95-
LastCreatedChannel = builder.LastCreatedChannel,
96-
InstanceName = instanceName
97-
};
99+
CbtClient cbtClient = new CbtClient(BigtableClient.Create(apiClient), builder.LastCreatedChannel, instanceName);
98100
_idClientMap[clientId] = cbtClient;
99101
}
100102
catch (Exception e)
@@ -126,7 +128,9 @@ public override Task<RemoveClientResponse> RemoveClient(RemoveClientRequest requ
126128
{
127129
string clientId = request.ClientId;
128130
GaxPreconditions.CheckArgument(clientId is not ("" or null), "ClientId", "client id must be provided", context);
131+
#pragma warning disable CS8604 // Possible null reference argument.
129132
bool removed = _idClientMap.Remove(clientId);
133+
#pragma warning restore CS8604 // Possible null reference argument.
130134
if (!removed)
131135
{
132136
context.Status = new Status(StatusCode.NotFound, $"Client {clientId} not found.");
@@ -147,7 +151,7 @@ public override async Task<RowResult> ReadRow(ReadRowRequest request, ServerCall
147151
{
148152
Status = new Rpc.Status()
149153
{
150-
Code = (int) Rpc.Code.InvalidArgument,
154+
Code = (int)Rpc.Code.InvalidArgument,
151155
Message = "Invalid TableName"
152156
}
153157
};
@@ -355,17 +359,19 @@ public override async Task<ExecuteQueryResult> ExecuteQuery(ExecuteQueryRequest
355359

356360
public static CloudBigtableV2TestProxyImpl Create() => new();
357361

358-
private CloudBigtableV2TestProxyImpl() => _idClientMap = new();
362+
public CloudBigtableV2TestProxyImpl() => _idClientMap = new();
359363

360364
private CbtClient GetClient(string clientId, ServerCallContext context)
361365
{
362366
GaxPreconditions.CheckArgument(clientId is not ("" or null), "ClientId", "client id must be provided", context);
363367

368+
#pragma warning disable CS8604 // Possible null reference argument.
364369
if (!_idClientMap.ContainsKey(clientId))
365370
{
366371
context.Status = new Status(StatusCode.NotFound, $"Client {clientId} not found.");
367372
throw new RpcException(context.Status);
368373
}
374+
#pragma warning restore CS8604 // Possible null reference argument.
369375
return _idClientMap[clientId];
370376
}
371377

@@ -399,7 +405,7 @@ private static Rpc.Status SetExceptionStatus(Exception e, ServerCallContext cont
399405
context.Status = new Status(StatusCode.Internal, e.Message, e);
400406
return new Rpc.Status()
401407
{
402-
Code = (int) Rpc.Code.Internal,
408+
Code = (int)Rpc.Code.Internal,
403409
Message = e.Message
404410
};
405411
}
@@ -409,7 +415,7 @@ private static Rpc.Status SetSuccessStatus(string message, ServerCallContext con
409415
context.Status = new Status(StatusCode.OK, message);
410416
return new Rpc.Status()
411417
{
412-
Code = (int) Rpc.Code.Ok,
418+
Code = (int)Rpc.Code.Ok,
413419
Message = message
414420
};
415421
}

0 commit comments

Comments
 (0)