commit
3ff9727a37
135 changed files with 12094 additions and 599 deletions
@ -0,0 +1,141 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head><title>Interop Test Result</title></head> |
||||
<body> |
||||
|
||||
<%def name="fill_one_test_result(shortname, resultset)"> |
||||
% if shortname in resultset: |
||||
## Because interop tests does not have runs_per_test flag, each test is |
||||
## run once. So there should only be one element for each result. |
||||
<% result = resultset[shortname][0] %> |
||||
% if result.state == 'PASSED': |
||||
<td bgcolor="green">PASS</td> |
||||
% else: |
||||
<% |
||||
tooltip = '' |
||||
if result.returncode > 0 or result.message: |
||||
if result.returncode > 0: |
||||
tooltip = 'returncode: %d ' % result.returncode |
||||
if result.message: |
||||
tooltip = '%smessage: %s' % (tooltip, result.message) |
||||
%> |
||||
% if result.state == 'FAILED': |
||||
<td bgcolor="red"> |
||||
% if tooltip: |
||||
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">FAIL</a></td> |
||||
% else: |
||||
FAIL</td> |
||||
% endif |
||||
% elif result.state == 'TIMEOUT': |
||||
<td bgcolor="yellow"> |
||||
% if tooltip: |
||||
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">TIMEOUT</a></td> |
||||
% else: |
||||
TIMEOUT</td> |
||||
% endif |
||||
% endif |
||||
% endif |
||||
% else: |
||||
<td bgcolor="magenta">Not implemented</td> |
||||
% endif |
||||
</%def> |
||||
|
||||
% if num_failures > 1: |
||||
<p><h2><font color="red">${num_failures} tests failed!</font></h2></p> |
||||
% elif num_failures: |
||||
<p><h2><font color="red">${num_failures} test failed!</font></h2></p> |
||||
% else: |
||||
<p><h2><font color="green">All tests passed!</font></h2></p> |
||||
% endif |
||||
|
||||
% if cloud_to_prod: |
||||
## Each column header is the client language. |
||||
<h2>Cloud to Prod</h2> |
||||
<table style="width:100%" border="1"> |
||||
<tr bgcolor="#00BFFF"> |
||||
<th>Client languages ►<br/>Test Cases ▼</th> |
||||
% for client_lang in client_langs: |
||||
<th>${client_lang}</th> |
||||
% endfor |
||||
</tr> |
||||
% for test_case in test_cases + auth_test_cases: |
||||
<tr><td><b>${test_case}</b></td> |
||||
% for client_lang in client_langs: |
||||
<% |
||||
if test_case in auth_test_cases: |
||||
shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case) |
||||
else: |
||||
shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case) |
||||
%> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endfor |
||||
</tr> |
||||
% endfor |
||||
</table> |
||||
% endif |
||||
|
||||
% if http2_interop: |
||||
## Each column header is the server language. |
||||
<h2>HTTP/2 Interop</h2> |
||||
<table style="width:100%" border="1"> |
||||
<tr bgcolor="#00BFFF"> |
||||
<th>Servers ►<br/>Test Cases ▼</th> |
||||
% for server_lang in server_langs: |
||||
<th>${server_lang}</th> |
||||
% endfor |
||||
% if cloud_to_prod: |
||||
<th>prod</th> |
||||
% endif |
||||
</tr> |
||||
% for test_case in http2_cases: |
||||
<tr><td><b>${test_case}</b></td> |
||||
## Fill up the cells with test result. |
||||
% for server_lang in server_langs: |
||||
<% |
||||
shortname = 'cloud_to_cloud:http2:%s_server:%s' % ( |
||||
server_lang, test_case) |
||||
%> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endfor |
||||
% if cloud_to_prod: |
||||
<% shortname = 'cloud_to_prod:http2:%s' % test_case %> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endif |
||||
</tr> |
||||
% endfor |
||||
</table> |
||||
% endif |
||||
|
||||
% if server_langs: |
||||
% for test_case in test_cases: |
||||
## Each column header is the client language. |
||||
<h2>${test_case}</h2> |
||||
<table style="width:100%" border="1"> |
||||
<tr bgcolor="#00BFFF"> |
||||
<th>Client languages ►<br/>Server languages ▼</th> |
||||
% for client_lang in client_langs: |
||||
<th>${client_lang}</th> |
||||
% endfor |
||||
</tr> |
||||
## Each row head is the server language. |
||||
% for server_lang in server_langs: |
||||
<tr> |
||||
<td><b>${server_lang}</b></td> |
||||
% for client_lang in client_langs: |
||||
<% |
||||
shortname = 'cloud_to_cloud:%s:%s_server:%s' % ( |
||||
client_lang, server_lang, test_case) |
||||
%> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endfor |
||||
</tr> |
||||
% endfor |
||||
</table> |
||||
% endfor |
||||
% endif |
||||
|
||||
<script> |
||||
$(document).ready(function(){$('[data-toggle="tooltip"]').tooltip();}); |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,3 @@ |
||||
bin |
||||
obj |
||||
|
@ -0,0 +1,60 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid> |
||||
<OutputType>Exe</OutputType> |
||||
<RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace> |
||||
<AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Debug</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<PlatformTarget>AnyCPU</PlatformTarget> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
<DebugType>pdbonly</DebugType> |
||||
<Optimize>true</Optimize> |
||||
<OutputPath>bin\Release</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<PlatformTarget>AnyCPU</PlatformTarget> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> |
||||
<DebugType>pdbonly</DebugType> |
||||
<Optimize>true</Optimize> |
||||
<OutputPath>bin\ReleaseSigned</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<SignAssembly>True</SignAssembly> |
||||
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="System" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="..\Grpc.Core\Version.cs"> |
||||
<Link>Version.cs</Link> |
||||
</Compile> |
||||
<Compile Include="Program.cs" /> |
||||
<Compile Include="Properties\AssemblyInfo.cs" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj"> |
||||
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project> |
||||
<Name>Grpc.Core</Name> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj"> |
||||
<Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project> |
||||
<Name>Grpc.IntegrationTesting</Name> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,76 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
|
||||
namespace Grpc.Testing |
||||
{ |
||||
/// <summary> |
||||
/// Implementation of BenchmarkService server |
||||
/// </summary> |
||||
public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService |
||||
{ |
||||
private readonly int responseSize; |
||||
|
||||
public BenchmarkServiceImpl(int responseSize) |
||||
{ |
||||
this.responseSize = responseSize; |
||||
} |
||||
|
||||
public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context) |
||||
{ |
||||
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) }; |
||||
return Task.FromResult(response); |
||||
} |
||||
|
||||
public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context) |
||||
{ |
||||
await requestStream.ForEachAsync(async request => |
||||
{ |
||||
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) }; |
||||
await responseStream.WriteAsync(response); |
||||
}); |
||||
} |
||||
|
||||
private static Payload CreateZerosPayload(int size) |
||||
{ |
||||
return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,153 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using Grpc.Testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Helper methods to start client runners for performance testing. |
||||
/// </summary> |
||||
public static class ClientRunners |
||||
{ |
||||
/// <summary> |
||||
/// Creates a started client runner. |
||||
/// </summary> |
||||
public static IClientRunner CreateStarted(ClientConfig config) |
||||
{ |
||||
string target = config.ServerTargets.Single(); |
||||
Grpc.Core.Utils.Preconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop); |
||||
|
||||
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure; |
||||
var channel = new Channel(target, credentials); |
||||
|
||||
switch (config.RpcType) |
||||
{ |
||||
case RpcType.UNARY: |
||||
return new SyncUnaryClientRunner(channel, |
||||
config.PayloadConfig.SimpleParams.ReqSize, |
||||
config.HistogramParams); |
||||
|
||||
case RpcType.STREAMING: |
||||
default: |
||||
throw new ArgumentException("Unsupported RpcType."); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Client that starts synchronous unary calls in a closed loop. |
||||
/// </summary> |
||||
public class SyncUnaryClientRunner : IClientRunner |
||||
{ |
||||
const double SecondsToNanos = 1e9; |
||||
|
||||
readonly Channel channel; |
||||
readonly int payloadSize; |
||||
readonly Histogram histogram; |
||||
|
||||
readonly BenchmarkService.IBenchmarkServiceClient client; |
||||
readonly Task runnerTask; |
||||
readonly CancellationTokenSource stoppedCts; |
||||
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); |
||||
|
||||
public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams) |
||||
{ |
||||
this.channel = Grpc.Core.Utils.Preconditions.CheckNotNull(channel); |
||||
this.payloadSize = payloadSize; |
||||
this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible); |
||||
|
||||
this.stoppedCts = new CancellationTokenSource(); |
||||
this.client = BenchmarkService.NewClient(channel); |
||||
this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning); |
||||
} |
||||
|
||||
public ClientStats GetStats(bool reset) |
||||
{ |
||||
var histogramData = histogram.GetSnapshot(reset); |
||||
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds; |
||||
|
||||
// TODO: populate user time and system time |
||||
return new ClientStats |
||||
{ |
||||
Latencies = histogramData, |
||||
TimeElapsed = secondsElapsed, |
||||
TimeUser = 0, |
||||
TimeSystem = 0 |
||||
}; |
||||
} |
||||
|
||||
public async Task StopAsync() |
||||
{ |
||||
stoppedCts.Cancel(); |
||||
await runnerTask; |
||||
await channel.ShutdownAsync(); |
||||
} |
||||
|
||||
private void Run() |
||||
{ |
||||
var request = new SimpleRequest |
||||
{ |
||||
Payload = CreateZerosPayload(payloadSize) |
||||
}; |
||||
var stopwatch = new Stopwatch(); |
||||
|
||||
while (!stoppedCts.Token.IsCancellationRequested) |
||||
{ |
||||
stopwatch.Restart(); |
||||
client.UnaryCall(request); |
||||
stopwatch.Stop(); |
||||
|
||||
// spec requires data point in nanoseconds. |
||||
histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos); |
||||
} |
||||
} |
||||
|
||||
private static Payload CreateZerosPayload(int size) |
||||
{ |
||||
return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,153 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using Grpc.Testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Basic implementation of histogram based on grpc/support/histogram.h. |
||||
/// </summary> |
||||
public class Histogram |
||||
{ |
||||
readonly object myLock = new object(); |
||||
readonly double multiplier; |
||||
readonly double oneOnLogMultiplier; |
||||
readonly double maxPossible; |
||||
readonly uint[] buckets; |
||||
|
||||
int count; |
||||
double sum; |
||||
double sumOfSquares; |
||||
double min; |
||||
double max; |
||||
|
||||
public Histogram(double resolution, double maxPossible) |
||||
{ |
||||
Grpc.Core.Utils.Preconditions.CheckArgument(resolution > 0); |
||||
Grpc.Core.Utils.Preconditions.CheckArgument(maxPossible > 0); |
||||
this.maxPossible = maxPossible; |
||||
this.multiplier = 1.0 + resolution; |
||||
this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution); |
||||
this.buckets = new uint[FindBucket(maxPossible) + 1]; |
||||
|
||||
ResetUnsafe(); |
||||
} |
||||
|
||||
public void AddObservation(double value) |
||||
{ |
||||
lock (myLock) |
||||
{ |
||||
AddObservationUnsafe(value); |
||||
} |
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// Gets snapshot of stats and reset |
||||
/// </summary> |
||||
public HistogramData GetSnapshot(bool reset = false) |
||||
{ |
||||
lock (myLock) |
||||
{ |
||||
return GetSnapshotUnsafe(reset); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Finds bucket index to which given observation should go. |
||||
/// </summary> |
||||
private int FindBucket(double value) |
||||
{ |
||||
value = Math.Max(value, 1.0); |
||||
value = Math.Min(value, this.maxPossible); |
||||
return (int)(Math.Log(value) * oneOnLogMultiplier); |
||||
} |
||||
|
||||
private void AddObservationUnsafe(double value) |
||||
{ |
||||
this.count++; |
||||
this.sum += value; |
||||
this.sumOfSquares += value * value; |
||||
this.min = Math.Min(this.min, value); |
||||
this.max = Math.Max(this.max, value); |
||||
|
||||
this.buckets[FindBucket(value)]++; |
||||
} |
||||
|
||||
private HistogramData GetSnapshotUnsafe(bool reset) |
||||
{ |
||||
var data = new HistogramData |
||||
{ |
||||
Count = count, |
||||
Sum = sum, |
||||
SumOfSquares = sumOfSquares, |
||||
MinSeen = min, |
||||
MaxSeen = max, |
||||
Bucket = { buckets } |
||||
}; |
||||
|
||||
if (reset) |
||||
{ |
||||
ResetUnsafe(); |
||||
} |
||||
|
||||
return data; |
||||
} |
||||
|
||||
private void ResetUnsafe() |
||||
{ |
||||
this.count = 0; |
||||
this.sum = 0; |
||||
this.sumOfSquares = 0; |
||||
this.min = double.PositiveInfinity; |
||||
this.max = double.NegativeInfinity; |
||||
for (int i = 0; i < this.buckets.Length; i++) |
||||
{ |
||||
this.buckets[i] = 0; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,104 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using Grpc.Testing; |
||||
using NUnit.Framework; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
public class HistogramTest |
||||
{ |
||||
[Test] |
||||
public void Simple() |
||||
{ |
||||
var hist = new Histogram(0.01, 60e9); |
||||
hist.AddObservation(10000); |
||||
hist.AddObservation(10000); |
||||
hist.AddObservation(11000); |
||||
hist.AddObservation(11000); |
||||
|
||||
var data = hist.GetSnapshot(); |
||||
|
||||
Assert.AreEqual(4, data.Count); |
||||
Assert.AreEqual(42000.0, data.Sum, 1e-6); |
||||
Assert.AreEqual(10000, data.MinSeen); |
||||
Assert.AreEqual(11000, data.MaxSeen); |
||||
Assert.AreEqual(2.0*10000*10000 + 2.0*11000*11000, data.SumOfSquares, 1e-6); |
||||
|
||||
// 1.01^925 < 10000 < 1.01^926 |
||||
Assert.AreEqual(2, data.Bucket[925]); |
||||
Assert.AreEqual(2, data.Bucket[935]); |
||||
} |
||||
|
||||
[Test] |
||||
public void ExtremeObservations() |
||||
{ |
||||
var hist = new Histogram(0.01, 60e9); |
||||
hist.AddObservation(-0.5); // should be in the first bucket |
||||
hist.AddObservation(1e12); // should be in the last bucket |
||||
|
||||
var data = hist.GetSnapshot(); |
||||
Assert.AreEqual(1, data.Bucket[0]); |
||||
Assert.AreEqual(1, data.Bucket[data.Bucket.Count - 1]); |
||||
} |
||||
|
||||
[Test] |
||||
public void Reset() |
||||
{ |
||||
var hist = new Histogram(0.01, 60e9); |
||||
hist.AddObservation(10000); |
||||
hist.AddObservation(11000); |
||||
|
||||
var data = hist.GetSnapshot(true); // snapshot contains data before reset |
||||
Assert.AreEqual(2, data.Count); |
||||
Assert.AreEqual(10000, data.MinSeen); |
||||
Assert.AreEqual(11000, data.MaxSeen); |
||||
|
||||
data = hist.GetSnapshot(); // snapshot contains state after reset |
||||
Assert.AreEqual(0, data.Count); |
||||
Assert.AreEqual(double.PositiveInfinity, data.MinSeen); |
||||
Assert.AreEqual(double.NegativeInfinity, data.MaxSeen); |
||||
Assert.AreEqual(0, data.Sum); |
||||
Assert.AreEqual(0, data.SumOfSquares); |
||||
CollectionAssert.AreEqual(new uint[data.Bucket.Count], data.Bucket); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,67 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using Grpc.Testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Abstract client runner. |
||||
/// </summary> |
||||
public interface IClientRunner |
||||
{ |
||||
/// <summary> |
||||
/// Gets stats snapshot. |
||||
/// </summary> |
||||
/// <returns>The stats.</returns> |
||||
ClientStats GetStats(bool reset); |
||||
|
||||
/// <summary> |
||||
/// Asynchronously stops the client. |
||||
/// </summary> |
||||
/// <returns>Task that finishes when client has come to a full stop.</returns> |
||||
Task StopAsync(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,72 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using Grpc.Testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Abstract server runner. |
||||
/// </summary> |
||||
public interface IServerRunner |
||||
{ |
||||
/// <summary> |
||||
/// Port on which the server is listening. |
||||
/// </summary> |
||||
int BoundPort { get; } |
||||
|
||||
/// <summary> |
||||
/// Gets server stats. |
||||
/// </summary> |
||||
/// <returns>The stats.</returns> |
||||
ServerStats GetStats(bool reset); |
||||
|
||||
/// <summary> |
||||
/// Asynchronously stops the server. |
||||
/// </summary> |
||||
/// <returns>Task that finishes when server has shutdown.</returns> |
||||
Task StopAsync(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,580 @@ |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: test/proto/benchmarks/payloads.proto |
||||
#pragma warning disable 1591, 0612, 3021 |
||||
#region Designer generated code |
||||
|
||||
using pb = global::Google.Protobuf; |
||||
using pbc = global::Google.Protobuf.Collections; |
||||
using pbr = global::Google.Protobuf.Reflection; |
||||
using scg = global::System.Collections.Generic; |
||||
namespace Grpc.Testing { |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public static partial class Payloads { |
||||
|
||||
#region Descriptor |
||||
public static pbr::FileDescriptor Descriptor { |
||||
get { return descriptor; } |
||||
} |
||||
private static pbr::FileDescriptor descriptor; |
||||
|
||||
static Payloads() { |
||||
byte[] descriptorData = global::System.Convert.FromBase64String( |
||||
string.Concat( |
||||
"CiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8SDGdycGMu", |
||||
"dGVzdGluZyI3ChBCeXRlQnVmZmVyUGFyYW1zEhAKCHJlcV9zaXplGAEgASgF", |
||||
"EhEKCXJlc3Bfc2l6ZRgCIAEoBSI4ChFTaW1wbGVQcm90b1BhcmFtcxIQCghy", |
||||
"ZXFfc2l6ZRgBIAEoBRIRCglyZXNwX3NpemUYAiABKAUiFAoSQ29tcGxleFBy", |
||||
"b3RvUGFyYW1zIsoBCg1QYXlsb2FkQ29uZmlnEjgKDmJ5dGVidWZfcGFyYW1z", |
||||
"GAEgASgLMh4uZ3JwYy50ZXN0aW5nLkJ5dGVCdWZmZXJQYXJhbXNIABI4Cg1z", |
||||
"aW1wbGVfcGFyYW1zGAIgASgLMh8uZ3JwYy50ZXN0aW5nLlNpbXBsZVByb3Rv", |
||||
"UGFyYW1zSAASOgoOY29tcGxleF9wYXJhbXMYAyABKAsyIC5ncnBjLnRlc3Rp", |
||||
"bmcuQ29tcGxleFByb3RvUGFyYW1zSABCCQoHcGF5bG9hZGIGcHJvdG8z")); |
||||
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, |
||||
new pbr::FileDescriptor[] { }, |
||||
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ByteBufferParams), new[]{ "ReqSize", "RespSize" }, null, null, null), |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), new[]{ "ReqSize", "RespSize" }, null, null, null), |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), null, null, null, null), |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PayloadConfig), new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null) |
||||
})); |
||||
} |
||||
#endregion |
||||
|
||||
} |
||||
#region Messages |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class ByteBufferParams : pb::IMessage<ByteBufferParams> { |
||||
private static readonly pb::MessageParser<ByteBufferParams> _parser = new pb::MessageParser<ByteBufferParams>(() => new ByteBufferParams()); |
||||
public static pb::MessageParser<ByteBufferParams> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[0]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public ByteBufferParams() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public ByteBufferParams(ByteBufferParams other) : this() { |
||||
reqSize_ = other.reqSize_; |
||||
respSize_ = other.respSize_; |
||||
} |
||||
|
||||
public ByteBufferParams Clone() { |
||||
return new ByteBufferParams(this); |
||||
} |
||||
|
||||
public const int ReqSizeFieldNumber = 1; |
||||
private int reqSize_; |
||||
public int ReqSize { |
||||
get { return reqSize_; } |
||||
set { |
||||
reqSize_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int RespSizeFieldNumber = 2; |
||||
private int respSize_; |
||||
public int RespSize { |
||||
get { return respSize_; } |
||||
set { |
||||
respSize_ = value; |
||||
} |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as ByteBufferParams); |
||||
} |
||||
|
||||
public bool Equals(ByteBufferParams other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (ReqSize != other.ReqSize) return false; |
||||
if (RespSize != other.RespSize) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (ReqSize != 0) hash ^= ReqSize.GetHashCode(); |
||||
if (RespSize != 0) hash ^= RespSize.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (ReqSize != 0) { |
||||
output.WriteRawTag(8); |
||||
output.WriteInt32(ReqSize); |
||||
} |
||||
if (RespSize != 0) { |
||||
output.WriteRawTag(16); |
||||
output.WriteInt32(RespSize); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (ReqSize != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize); |
||||
} |
||||
if (RespSize != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(ByteBufferParams other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.ReqSize != 0) { |
||||
ReqSize = other.ReqSize; |
||||
} |
||||
if (other.RespSize != 0) { |
||||
RespSize = other.RespSize; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 8: { |
||||
ReqSize = input.ReadInt32(); |
||||
break; |
||||
} |
||||
case 16: { |
||||
RespSize = input.ReadInt32(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class SimpleProtoParams : pb::IMessage<SimpleProtoParams> { |
||||
private static readonly pb::MessageParser<SimpleProtoParams> _parser = new pb::MessageParser<SimpleProtoParams>(() => new SimpleProtoParams()); |
||||
public static pb::MessageParser<SimpleProtoParams> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[1]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public SimpleProtoParams() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public SimpleProtoParams(SimpleProtoParams other) : this() { |
||||
reqSize_ = other.reqSize_; |
||||
respSize_ = other.respSize_; |
||||
} |
||||
|
||||
public SimpleProtoParams Clone() { |
||||
return new SimpleProtoParams(this); |
||||
} |
||||
|
||||
public const int ReqSizeFieldNumber = 1; |
||||
private int reqSize_; |
||||
public int ReqSize { |
||||
get { return reqSize_; } |
||||
set { |
||||
reqSize_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int RespSizeFieldNumber = 2; |
||||
private int respSize_; |
||||
public int RespSize { |
||||
get { return respSize_; } |
||||
set { |
||||
respSize_ = value; |
||||
} |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as SimpleProtoParams); |
||||
} |
||||
|
||||
public bool Equals(SimpleProtoParams other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (ReqSize != other.ReqSize) return false; |
||||
if (RespSize != other.RespSize) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (ReqSize != 0) hash ^= ReqSize.GetHashCode(); |
||||
if (RespSize != 0) hash ^= RespSize.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (ReqSize != 0) { |
||||
output.WriteRawTag(8); |
||||
output.WriteInt32(ReqSize); |
||||
} |
||||
if (RespSize != 0) { |
||||
output.WriteRawTag(16); |
||||
output.WriteInt32(RespSize); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (ReqSize != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize); |
||||
} |
||||
if (RespSize != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(SimpleProtoParams other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.ReqSize != 0) { |
||||
ReqSize = other.ReqSize; |
||||
} |
||||
if (other.RespSize != 0) { |
||||
RespSize = other.RespSize; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 8: { |
||||
ReqSize = input.ReadInt32(); |
||||
break; |
||||
} |
||||
case 16: { |
||||
RespSize = input.ReadInt32(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class ComplexProtoParams : pb::IMessage<ComplexProtoParams> { |
||||
private static readonly pb::MessageParser<ComplexProtoParams> _parser = new pb::MessageParser<ComplexProtoParams>(() => new ComplexProtoParams()); |
||||
public static pb::MessageParser<ComplexProtoParams> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[2]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public ComplexProtoParams() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public ComplexProtoParams(ComplexProtoParams other) : this() { |
||||
} |
||||
|
||||
public ComplexProtoParams Clone() { |
||||
return new ComplexProtoParams(this); |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as ComplexProtoParams); |
||||
} |
||||
|
||||
public bool Equals(ComplexProtoParams other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(ComplexProtoParams other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class PayloadConfig : pb::IMessage<PayloadConfig> { |
||||
private static readonly pb::MessageParser<PayloadConfig> _parser = new pb::MessageParser<PayloadConfig>(() => new PayloadConfig()); |
||||
public static pb::MessageParser<PayloadConfig> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[3]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public PayloadConfig() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public PayloadConfig(PayloadConfig other) : this() { |
||||
switch (other.PayloadCase) { |
||||
case PayloadOneofCase.BytebufParams: |
||||
BytebufParams = other.BytebufParams.Clone(); |
||||
break; |
||||
case PayloadOneofCase.SimpleParams: |
||||
SimpleParams = other.SimpleParams.Clone(); |
||||
break; |
||||
case PayloadOneofCase.ComplexParams: |
||||
ComplexParams = other.ComplexParams.Clone(); |
||||
break; |
||||
} |
||||
|
||||
} |
||||
|
||||
public PayloadConfig Clone() { |
||||
return new PayloadConfig(this); |
||||
} |
||||
|
||||
public const int BytebufParamsFieldNumber = 1; |
||||
public global::Grpc.Testing.ByteBufferParams BytebufParams { |
||||
get { return payloadCase_ == PayloadOneofCase.BytebufParams ? (global::Grpc.Testing.ByteBufferParams) payload_ : null; } |
||||
set { |
||||
payload_ = value; |
||||
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BytebufParams; |
||||
} |
||||
} |
||||
|
||||
public const int SimpleParamsFieldNumber = 2; |
||||
public global::Grpc.Testing.SimpleProtoParams SimpleParams { |
||||
get { return payloadCase_ == PayloadOneofCase.SimpleParams ? (global::Grpc.Testing.SimpleProtoParams) payload_ : null; } |
||||
set { |
||||
payload_ = value; |
||||
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SimpleParams; |
||||
} |
||||
} |
||||
|
||||
public const int ComplexParamsFieldNumber = 3; |
||||
public global::Grpc.Testing.ComplexProtoParams ComplexParams { |
||||
get { return payloadCase_ == PayloadOneofCase.ComplexParams ? (global::Grpc.Testing.ComplexProtoParams) payload_ : null; } |
||||
set { |
||||
payload_ = value; |
||||
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ComplexParams; |
||||
} |
||||
} |
||||
|
||||
private object payload_; |
||||
public enum PayloadOneofCase { |
||||
None = 0, |
||||
BytebufParams = 1, |
||||
SimpleParams = 2, |
||||
ComplexParams = 3, |
||||
} |
||||
private PayloadOneofCase payloadCase_ = PayloadOneofCase.None; |
||||
public PayloadOneofCase PayloadCase { |
||||
get { return payloadCase_; } |
||||
} |
||||
|
||||
public void ClearPayload() { |
||||
payloadCase_ = PayloadOneofCase.None; |
||||
payload_ = null; |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as PayloadConfig); |
||||
} |
||||
|
||||
public bool Equals(PayloadConfig other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (!object.Equals(BytebufParams, other.BytebufParams)) return false; |
||||
if (!object.Equals(SimpleParams, other.SimpleParams)) return false; |
||||
if (!object.Equals(ComplexParams, other.ComplexParams)) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) hash ^= BytebufParams.GetHashCode(); |
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) hash ^= SimpleParams.GetHashCode(); |
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) hash ^= ComplexParams.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) { |
||||
output.WriteRawTag(10); |
||||
output.WriteMessage(BytebufParams); |
||||
} |
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) { |
||||
output.WriteRawTag(18); |
||||
output.WriteMessage(SimpleParams); |
||||
} |
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) { |
||||
output.WriteRawTag(26); |
||||
output.WriteMessage(ComplexParams); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) { |
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(BytebufParams); |
||||
} |
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) { |
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(SimpleParams); |
||||
} |
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) { |
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ComplexParams); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(PayloadConfig other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
switch (other.PayloadCase) { |
||||
case PayloadOneofCase.BytebufParams: |
||||
BytebufParams = other.BytebufParams; |
||||
break; |
||||
case PayloadOneofCase.SimpleParams: |
||||
SimpleParams = other.SimpleParams; |
||||
break; |
||||
case PayloadOneofCase.ComplexParams: |
||||
ComplexParams = other.ComplexParams; |
||||
break; |
||||
} |
||||
|
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 10: { |
||||
global::Grpc.Testing.ByteBufferParams subBuilder = new global::Grpc.Testing.ByteBufferParams(); |
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) { |
||||
subBuilder.MergeFrom(BytebufParams); |
||||
} |
||||
input.ReadMessage(subBuilder); |
||||
BytebufParams = subBuilder; |
||||
break; |
||||
} |
||||
case 18: { |
||||
global::Grpc.Testing.SimpleProtoParams subBuilder = new global::Grpc.Testing.SimpleProtoParams(); |
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) { |
||||
subBuilder.MergeFrom(SimpleParams); |
||||
} |
||||
input.ReadMessage(subBuilder); |
||||
SimpleParams = subBuilder; |
||||
break; |
||||
} |
||||
case 26: { |
||||
global::Grpc.Testing.ComplexProtoParams subBuilder = new global::Grpc.Testing.ComplexProtoParams(); |
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) { |
||||
subBuilder.MergeFrom(ComplexParams); |
||||
} |
||||
input.ReadMessage(subBuilder); |
||||
ComplexParams = subBuilder; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
|
||||
#endregion Designer generated code |
@ -0,0 +1,108 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading.Tasks; |
||||
|
||||
using CommandLine; |
||||
using CommandLine.Text; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using Grpc.Testing; |
||||
using NUnit.Framework; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
public class QpsWorker |
||||
{ |
||||
private class ServerOptions |
||||
{ |
||||
[Option("driver_port", DefaultValue = 0)] |
||||
public int DriverPort { get; set; } |
||||
|
||||
[HelpOption] |
||||
public string GetUsage() |
||||
{ |
||||
var help = new HelpText |
||||
{ |
||||
Heading = "gRPC C# performance testing worker", |
||||
AddDashesToOption = true |
||||
}; |
||||
help.AddPreOptionsLine("Usage:"); |
||||
help.AddOptions(this); |
||||
return help; |
||||
} |
||||
} |
||||
|
||||
ServerOptions options; |
||||
|
||||
private QpsWorker(ServerOptions options) |
||||
{ |
||||
this.options = options; |
||||
} |
||||
|
||||
public static void Run(string[] args) |
||||
{ |
||||
var options = new ServerOptions(); |
||||
if (!Parser.Default.ParseArguments(args, options)) |
||||
{ |
||||
Environment.Exit(1); |
||||
} |
||||
|
||||
var workerServer = new QpsWorker(options); |
||||
workerServer.Run(); |
||||
} |
||||
|
||||
private void Run() |
||||
{ |
||||
string host = "0.0.0.0"; |
||||
int port = options.DriverPort; |
||||
|
||||
var server = new Server |
||||
{ |
||||
Services = { WorkerService.BindService(new WorkerServiceImpl()) }, |
||||
Ports = { new ServerPort(host, options.DriverPort, ServerCredentials.Insecure )} |
||||
}; |
||||
int boundPort = server.Ports.Single().BoundPort; |
||||
Console.WriteLine("Running qps worker server on " + string.Format("{0}:{1}", host, boundPort)); |
||||
server.Start(); |
||||
|
||||
server.ShutdownTask.Wait(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,117 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using Grpc.Testing; |
||||
using NUnit.Framework; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Runs performance tests in-process. |
||||
/// </summary> |
||||
public class RunnerClientServerTest |
||||
{ |
||||
const string Host = "localhost"; |
||||
IServerRunner serverRunner; |
||||
|
||||
[TestFixtureSetUp] |
||||
public void Init() |
||||
{ |
||||
var serverConfig = new ServerConfig |
||||
{ |
||||
ServerType = ServerType.ASYNC_SERVER, |
||||
Host = Host, |
||||
PayloadConfig = new PayloadConfig |
||||
{ |
||||
SimpleParams = new SimpleProtoParams |
||||
{ |
||||
RespSize = 100 |
||||
} |
||||
} |
||||
}; |
||||
serverRunner = ServerRunners.CreateStarted(serverConfig); |
||||
} |
||||
|
||||
[TestFixtureTearDown] |
||||
public void Cleanup() |
||||
{ |
||||
serverRunner.StopAsync().Wait(); |
||||
} |
||||
|
||||
// Test attribute commented out to prevent running as part of the default test suite. |
||||
//[Test] |
||||
//[Category("Performance")] |
||||
public async Task ClientServerRunner() |
||||
{ |
||||
var config = new ClientConfig |
||||
{ |
||||
ServerTargets = { string.Format("{0}:{1}", Host, serverRunner.BoundPort) }, |
||||
RpcType = RpcType.UNARY, |
||||
LoadParams = new LoadParams { ClosedLoop = new ClosedLoopParams() }, |
||||
PayloadConfig = new PayloadConfig |
||||
{ |
||||
SimpleParams = new SimpleProtoParams |
||||
{ |
||||
ReqSize = 100 |
||||
} |
||||
}, |
||||
HistogramParams = new HistogramParams |
||||
{ |
||||
Resolution = 0.01, |
||||
MaxPossible = 60e9 |
||||
} |
||||
}; |
||||
|
||||
var runner = ClientRunners.CreateStarted(config); |
||||
|
||||
System.Console.WriteLine("Warming up"); |
||||
await Task.Delay(3000); |
||||
runner.GetStats(true); // throw away warm-up data |
||||
|
||||
System.Console.WriteLine("Benchmarking"); |
||||
await Task.Delay(3000); |
||||
var stats = runner.GetStats(true); |
||||
await runner.StopAsync(); |
||||
|
||||
System.Console.WriteLine(stats); |
||||
System.Console.WriteLine("avg micros/call " + (long) (stats.Latencies.Sum / stats.Latencies.Count / 1000.0)); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,124 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using Grpc.Testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Helper methods to start server runners for performance testing. |
||||
/// </summary> |
||||
public static class ServerRunners |
||||
{ |
||||
/// <summary> |
||||
/// Creates a started server runner. |
||||
/// </summary> |
||||
public static IServerRunner CreateStarted(ServerConfig config) |
||||
{ |
||||
Grpc.Core.Utils.Preconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER); |
||||
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure; |
||||
|
||||
// TODO: qps_driver needs to setup payload properly... |
||||
int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0; |
||||
var server = new Server |
||||
{ |
||||
Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) }, |
||||
Ports = { new ServerPort(config.Host, config.Port, credentials) } |
||||
}; |
||||
|
||||
server.Start(); |
||||
return new ServerRunnerImpl(server); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Server runner. |
||||
/// </summary> |
||||
public class ServerRunnerImpl : IServerRunner |
||||
{ |
||||
readonly Server server; |
||||
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); |
||||
|
||||
public ServerRunnerImpl(Server server) |
||||
{ |
||||
this.server = Grpc.Core.Utils.Preconditions.CheckNotNull(server); |
||||
} |
||||
|
||||
public int BoundPort |
||||
{ |
||||
get |
||||
{ |
||||
return server.Ports.Single().BoundPort; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets server stats. |
||||
/// </summary> |
||||
/// <returns>The stats.</returns> |
||||
public ServerStats GetStats(bool reset) |
||||
{ |
||||
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds; |
||||
|
||||
// TODO: populate user time and system time |
||||
return new ServerStats |
||||
{ |
||||
TimeElapsed = secondsElapsed, |
||||
TimeUser = 0, |
||||
TimeSystem = 0 |
||||
}; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Asynchronously stops the server. |
||||
/// </summary> |
||||
/// <returns>Task that finishes when server has shutdown.</returns> |
||||
public Task StopAsync() |
||||
{ |
||||
return server.ShutdownAsync(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,44 @@ |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: test/proto/benchmarks/services.proto |
||||
#pragma warning disable 1591, 0612, 3021 |
||||
#region Designer generated code |
||||
|
||||
using pb = global::Google.Protobuf; |
||||
using pbc = global::Google.Protobuf.Collections; |
||||
using pbr = global::Google.Protobuf.Reflection; |
||||
using scg = global::System.Collections.Generic; |
||||
namespace Grpc.Testing { |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public static partial class Services { |
||||
|
||||
#region Descriptor |
||||
public static pbr::FileDescriptor Descriptor { |
||||
get { return descriptor; } |
||||
} |
||||
private static pbr::FileDescriptor descriptor; |
||||
|
||||
static Services() { |
||||
byte[] descriptorData = global::System.Convert.FromBase64String( |
||||
string.Concat( |
||||
"CiR0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc2VydmljZXMucHJvdG8SDGdycGMu", |
||||
"dGVzdGluZxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bxojdGVzdC9wcm90", |
||||
"by9iZW5jaG1hcmtzL2NvbnRyb2wucHJvdG8yqgEKEEJlbmNobWFya1NlcnZp", |
||||
"Y2USRgoJVW5hcnlDYWxsEhsuZ3JwYy50ZXN0aW5nLlNpbXBsZVJlcXVlc3Qa", |
||||
"HC5ncnBjLnRlc3RpbmcuU2ltcGxlUmVzcG9uc2USTgoNU3RyZWFtaW5nQ2Fs", |
||||
"bBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5n", |
||||
"LlNpbXBsZVJlc3BvbnNlKAEwATKdAQoNV29ya2VyU2VydmljZRJFCglSdW5T", |
||||
"ZXJ2ZXISGC5ncnBjLnRlc3RpbmcuU2VydmVyQXJncxoaLmdycGMudGVzdGlu", |
||||
"Zy5TZXJ2ZXJTdGF0dXMoATABEkUKCVJ1bkNsaWVudBIYLmdycGMudGVzdGlu", |
||||
"Zy5DbGllbnRBcmdzGhouZ3JwYy50ZXN0aW5nLkNsaWVudFN0YXR1cygBMAFi", |
||||
"BnByb3RvMw==")); |
||||
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, |
||||
new pbr::FileDescriptor[] { global::Grpc.Testing.Messages.Descriptor, global::Grpc.Testing.Control.Descriptor, }, |
||||
new pbr::GeneratedCodeInfo(null, null)); |
||||
} |
||||
#endregion |
||||
|
||||
} |
||||
} |
||||
|
||||
#endregion Designer generated code |
@ -0,0 +1,198 @@ |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: test/proto/benchmarks/services.proto |
||||
#region Designer generated code |
||||
|
||||
using System; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Grpc.Core; |
||||
|
||||
namespace Grpc.Testing { |
||||
public static class BenchmarkService |
||||
{ |
||||
static readonly string __ServiceName = "grpc.testing.BenchmarkService"; |
||||
|
||||
static readonly Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom); |
||||
static readonly Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom); |
||||
|
||||
static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>( |
||||
MethodType.Unary, |
||||
__ServiceName, |
||||
"UnaryCall", |
||||
__Marshaller_SimpleRequest, |
||||
__Marshaller_SimpleResponse); |
||||
|
||||
static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>( |
||||
MethodType.DuplexStreaming, |
||||
__ServiceName, |
||||
"StreamingCall", |
||||
__Marshaller_SimpleRequest, |
||||
__Marshaller_SimpleResponse); |
||||
|
||||
// service descriptor |
||||
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor |
||||
{ |
||||
get { return global::Grpc.Testing.Services.Descriptor.Services[0]; } |
||||
} |
||||
|
||||
// client interface |
||||
public interface IBenchmarkServiceClient |
||||
{ |
||||
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); |
||||
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options); |
||||
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); |
||||
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options); |
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); |
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options); |
||||
} |
||||
|
||||
// server-side interface |
||||
public interface IBenchmarkService |
||||
{ |
||||
Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context); |
||||
Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context); |
||||
} |
||||
|
||||
// client stub |
||||
public class BenchmarkServiceClient : ClientBase, IBenchmarkServiceClient |
||||
{ |
||||
public BenchmarkServiceClient(Channel channel) : base(channel) |
||||
{ |
||||
} |
||||
public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) |
||||
{ |
||||
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); |
||||
return Calls.BlockingUnaryCall(call, request); |
||||
} |
||||
public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options) |
||||
{ |
||||
var call = CreateCall(__Method_UnaryCall, options); |
||||
return Calls.BlockingUnaryCall(call, request); |
||||
} |
||||
public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) |
||||
{ |
||||
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); |
||||
return Calls.AsyncUnaryCall(call, request); |
||||
} |
||||
public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options) |
||||
{ |
||||
var call = CreateCall(__Method_UnaryCall, options); |
||||
return Calls.AsyncUnaryCall(call, request); |
||||
} |
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) |
||||
{ |
||||
var call = CreateCall(__Method_StreamingCall, new CallOptions(headers, deadline, cancellationToken)); |
||||
return Calls.AsyncDuplexStreamingCall(call); |
||||
} |
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options) |
||||
{ |
||||
var call = CreateCall(__Method_StreamingCall, options); |
||||
return Calls.AsyncDuplexStreamingCall(call); |
||||
} |
||||
} |
||||
|
||||
// creates service definition that can be registered with a server |
||||
public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl) |
||||
{ |
||||
return ServerServiceDefinition.CreateBuilder(__ServiceName) |
||||
.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall) |
||||
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build(); |
||||
} |
||||
|
||||
// creates a new client |
||||
public static BenchmarkServiceClient NewClient(Channel channel) |
||||
{ |
||||
return new BenchmarkServiceClient(channel); |
||||
} |
||||
|
||||
} |
||||
public static class WorkerService |
||||
{ |
||||
static readonly string __ServiceName = "grpc.testing.WorkerService"; |
||||
|
||||
static readonly Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_ServerArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom); |
||||
static readonly Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_ServerStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom); |
||||
static readonly Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_ClientArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom); |
||||
static readonly Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_ClientStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom); |
||||
|
||||
static readonly Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>( |
||||
MethodType.DuplexStreaming, |
||||
__ServiceName, |
||||
"RunServer", |
||||
__Marshaller_ServerArgs, |
||||
__Marshaller_ServerStatus); |
||||
|
||||
static readonly Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>( |
||||
MethodType.DuplexStreaming, |
||||
__ServiceName, |
||||
"RunClient", |
||||
__Marshaller_ClientArgs, |
||||
__Marshaller_ClientStatus); |
||||
|
||||
// service descriptor |
||||
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor |
||||
{ |
||||
get { return global::Grpc.Testing.Services.Descriptor.Services[1]; } |
||||
} |
||||
|
||||
// client interface |
||||
public interface IWorkerServiceClient |
||||
{ |
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); |
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options); |
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); |
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options); |
||||
} |
||||
|
||||
// server-side interface |
||||
public interface IWorkerService |
||||
{ |
||||
Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context); |
||||
Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context); |
||||
} |
||||
|
||||
// client stub |
||||
public class WorkerServiceClient : ClientBase, IWorkerServiceClient |
||||
{ |
||||
public WorkerServiceClient(Channel channel) : base(channel) |
||||
{ |
||||
} |
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) |
||||
{ |
||||
var call = CreateCall(__Method_RunServer, new CallOptions(headers, deadline, cancellationToken)); |
||||
return Calls.AsyncDuplexStreamingCall(call); |
||||
} |
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options) |
||||
{ |
||||
var call = CreateCall(__Method_RunServer, options); |
||||
return Calls.AsyncDuplexStreamingCall(call); |
||||
} |
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) |
||||
{ |
||||
var call = CreateCall(__Method_RunClient, new CallOptions(headers, deadline, cancellationToken)); |
||||
return Calls.AsyncDuplexStreamingCall(call); |
||||
} |
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options) |
||||
{ |
||||
var call = CreateCall(__Method_RunClient, options); |
||||
return Calls.AsyncDuplexStreamingCall(call); |
||||
} |
||||
} |
||||
|
||||
// creates service definition that can be registered with a server |
||||
public static ServerServiceDefinition BindService(IWorkerService serviceImpl) |
||||
{ |
||||
return ServerServiceDefinition.CreateBuilder(__ServiceName) |
||||
.AddMethod(__Method_RunServer, serviceImpl.RunServer) |
||||
.AddMethod(__Method_RunClient, serviceImpl.RunClient).Build(); |
||||
} |
||||
|
||||
// creates a new client |
||||
public static WorkerServiceClient NewClient(Channel channel) |
||||
{ |
||||
return new WorkerServiceClient(channel); |
||||
} |
||||
|
||||
} |
||||
} |
||||
#endregion |
@ -0,0 +1,744 @@ |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: test/proto/benchmarks/stats.proto |
||||
#pragma warning disable 1591, 0612, 3021 |
||||
#region Designer generated code |
||||
|
||||
using pb = global::Google.Protobuf; |
||||
using pbc = global::Google.Protobuf.Collections; |
||||
using pbr = global::Google.Protobuf.Reflection; |
||||
using scg = global::System.Collections.Generic; |
||||
namespace Grpc.Testing { |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public static partial class Stats { |
||||
|
||||
#region Descriptor |
||||
public static pbr::FileDescriptor Descriptor { |
||||
get { return descriptor; } |
||||
} |
||||
private static pbr::FileDescriptor descriptor; |
||||
|
||||
static Stats() { |
||||
byte[] descriptorData = global::System.Convert.FromBase64String( |
||||
string.Concat( |
||||
"CiF0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc3RhdHMucHJvdG8SDGdycGMudGVz", |
||||
"dGluZyJLCgtTZXJ2ZXJTdGF0cxIUCgx0aW1lX2VsYXBzZWQYASABKAESEQoJ", |
||||
"dGltZV91c2VyGAIgASgBEhMKC3RpbWVfc3lzdGVtGAMgASgBIjsKD0hpc3Rv", |
||||
"Z3JhbVBhcmFtcxISCgpyZXNvbHV0aW9uGAEgASgBEhQKDG1heF9wb3NzaWJs", |
||||
"ZRgCIAEoASJ3Cg1IaXN0b2dyYW1EYXRhEg4KBmJ1Y2tldBgBIAMoDRIQCght", |
||||
"aW5fc2VlbhgCIAEoARIQCghtYXhfc2VlbhgDIAEoARILCgNzdW0YBCABKAES", |
||||
"FgoOc3VtX29mX3NxdWFyZXMYBSABKAESDQoFY291bnQYBiABKAEiewoLQ2xp", |
||||
"ZW50U3RhdHMSLgoJbGF0ZW5jaWVzGAEgASgLMhsuZ3JwYy50ZXN0aW5nLkhp", |
||||
"c3RvZ3JhbURhdGESFAoMdGltZV9lbGFwc2VkGAIgASgBEhEKCXRpbWVfdXNl", |
||||
"chgDIAEoARITCgt0aW1lX3N5c3RlbRgEIAEoAWIGcHJvdG8z")); |
||||
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, |
||||
new pbr::FileDescriptor[] { }, |
||||
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStats), new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null), |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramParams), new[]{ "Resolution", "MaxPossible" }, null, null, null), |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramData), new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null), |
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStats), new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null) |
||||
})); |
||||
} |
||||
#endregion |
||||
|
||||
} |
||||
#region Messages |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class ServerStats : pb::IMessage<ServerStats> { |
||||
private static readonly pb::MessageParser<ServerStats> _parser = new pb::MessageParser<ServerStats>(() => new ServerStats()); |
||||
public static pb::MessageParser<ServerStats> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[0]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public ServerStats() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public ServerStats(ServerStats other) : this() { |
||||
timeElapsed_ = other.timeElapsed_; |
||||
timeUser_ = other.timeUser_; |
||||
timeSystem_ = other.timeSystem_; |
||||
} |
||||
|
||||
public ServerStats Clone() { |
||||
return new ServerStats(this); |
||||
} |
||||
|
||||
public const int TimeElapsedFieldNumber = 1; |
||||
private double timeElapsed_; |
||||
public double TimeElapsed { |
||||
get { return timeElapsed_; } |
||||
set { |
||||
timeElapsed_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int TimeUserFieldNumber = 2; |
||||
private double timeUser_; |
||||
public double TimeUser { |
||||
get { return timeUser_; } |
||||
set { |
||||
timeUser_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int TimeSystemFieldNumber = 3; |
||||
private double timeSystem_; |
||||
public double TimeSystem { |
||||
get { return timeSystem_; } |
||||
set { |
||||
timeSystem_ = value; |
||||
} |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as ServerStats); |
||||
} |
||||
|
||||
public bool Equals(ServerStats other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (TimeElapsed != other.TimeElapsed) return false; |
||||
if (TimeUser != other.TimeUser) return false; |
||||
if (TimeSystem != other.TimeSystem) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode(); |
||||
if (TimeUser != 0D) hash ^= TimeUser.GetHashCode(); |
||||
if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (TimeElapsed != 0D) { |
||||
output.WriteRawTag(9); |
||||
output.WriteDouble(TimeElapsed); |
||||
} |
||||
if (TimeUser != 0D) { |
||||
output.WriteRawTag(17); |
||||
output.WriteDouble(TimeUser); |
||||
} |
||||
if (TimeSystem != 0D) { |
||||
output.WriteRawTag(25); |
||||
output.WriteDouble(TimeSystem); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (TimeElapsed != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (TimeUser != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (TimeSystem != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(ServerStats other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.TimeElapsed != 0D) { |
||||
TimeElapsed = other.TimeElapsed; |
||||
} |
||||
if (other.TimeUser != 0D) { |
||||
TimeUser = other.TimeUser; |
||||
} |
||||
if (other.TimeSystem != 0D) { |
||||
TimeSystem = other.TimeSystem; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 9: { |
||||
TimeElapsed = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 17: { |
||||
TimeUser = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 25: { |
||||
TimeSystem = input.ReadDouble(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class HistogramParams : pb::IMessage<HistogramParams> { |
||||
private static readonly pb::MessageParser<HistogramParams> _parser = new pb::MessageParser<HistogramParams>(() => new HistogramParams()); |
||||
public static pb::MessageParser<HistogramParams> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[1]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public HistogramParams() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public HistogramParams(HistogramParams other) : this() { |
||||
resolution_ = other.resolution_; |
||||
maxPossible_ = other.maxPossible_; |
||||
} |
||||
|
||||
public HistogramParams Clone() { |
||||
return new HistogramParams(this); |
||||
} |
||||
|
||||
public const int ResolutionFieldNumber = 1; |
||||
private double resolution_; |
||||
public double Resolution { |
||||
get { return resolution_; } |
||||
set { |
||||
resolution_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int MaxPossibleFieldNumber = 2; |
||||
private double maxPossible_; |
||||
public double MaxPossible { |
||||
get { return maxPossible_; } |
||||
set { |
||||
maxPossible_ = value; |
||||
} |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as HistogramParams); |
||||
} |
||||
|
||||
public bool Equals(HistogramParams other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (Resolution != other.Resolution) return false; |
||||
if (MaxPossible != other.MaxPossible) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (Resolution != 0D) hash ^= Resolution.GetHashCode(); |
||||
if (MaxPossible != 0D) hash ^= MaxPossible.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (Resolution != 0D) { |
||||
output.WriteRawTag(9); |
||||
output.WriteDouble(Resolution); |
||||
} |
||||
if (MaxPossible != 0D) { |
||||
output.WriteRawTag(17); |
||||
output.WriteDouble(MaxPossible); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (Resolution != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (MaxPossible != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(HistogramParams other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.Resolution != 0D) { |
||||
Resolution = other.Resolution; |
||||
} |
||||
if (other.MaxPossible != 0D) { |
||||
MaxPossible = other.MaxPossible; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 9: { |
||||
Resolution = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 17: { |
||||
MaxPossible = input.ReadDouble(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class HistogramData : pb::IMessage<HistogramData> { |
||||
private static readonly pb::MessageParser<HistogramData> _parser = new pb::MessageParser<HistogramData>(() => new HistogramData()); |
||||
public static pb::MessageParser<HistogramData> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[2]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public HistogramData() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public HistogramData(HistogramData other) : this() { |
||||
bucket_ = other.bucket_.Clone(); |
||||
minSeen_ = other.minSeen_; |
||||
maxSeen_ = other.maxSeen_; |
||||
sum_ = other.sum_; |
||||
sumOfSquares_ = other.sumOfSquares_; |
||||
count_ = other.count_; |
||||
} |
||||
|
||||
public HistogramData Clone() { |
||||
return new HistogramData(this); |
||||
} |
||||
|
||||
public const int BucketFieldNumber = 1; |
||||
private static readonly pb::FieldCodec<uint> _repeated_bucket_codec |
||||
= pb::FieldCodec.ForUInt32(10); |
||||
private readonly pbc::RepeatedField<uint> bucket_ = new pbc::RepeatedField<uint>(); |
||||
public pbc::RepeatedField<uint> Bucket { |
||||
get { return bucket_; } |
||||
} |
||||
|
||||
public const int MinSeenFieldNumber = 2; |
||||
private double minSeen_; |
||||
public double MinSeen { |
||||
get { return minSeen_; } |
||||
set { |
||||
minSeen_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int MaxSeenFieldNumber = 3; |
||||
private double maxSeen_; |
||||
public double MaxSeen { |
||||
get { return maxSeen_; } |
||||
set { |
||||
maxSeen_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int SumFieldNumber = 4; |
||||
private double sum_; |
||||
public double Sum { |
||||
get { return sum_; } |
||||
set { |
||||
sum_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int SumOfSquaresFieldNumber = 5; |
||||
private double sumOfSquares_; |
||||
public double SumOfSquares { |
||||
get { return sumOfSquares_; } |
||||
set { |
||||
sumOfSquares_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int CountFieldNumber = 6; |
||||
private double count_; |
||||
public double Count { |
||||
get { return count_; } |
||||
set { |
||||
count_ = value; |
||||
} |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as HistogramData); |
||||
} |
||||
|
||||
public bool Equals(HistogramData other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if(!bucket_.Equals(other.bucket_)) return false; |
||||
if (MinSeen != other.MinSeen) return false; |
||||
if (MaxSeen != other.MaxSeen) return false; |
||||
if (Sum != other.Sum) return false; |
||||
if (SumOfSquares != other.SumOfSquares) return false; |
||||
if (Count != other.Count) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
hash ^= bucket_.GetHashCode(); |
||||
if (MinSeen != 0D) hash ^= MinSeen.GetHashCode(); |
||||
if (MaxSeen != 0D) hash ^= MaxSeen.GetHashCode(); |
||||
if (Sum != 0D) hash ^= Sum.GetHashCode(); |
||||
if (SumOfSquares != 0D) hash ^= SumOfSquares.GetHashCode(); |
||||
if (Count != 0D) hash ^= Count.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
bucket_.WriteTo(output, _repeated_bucket_codec); |
||||
if (MinSeen != 0D) { |
||||
output.WriteRawTag(17); |
||||
output.WriteDouble(MinSeen); |
||||
} |
||||
if (MaxSeen != 0D) { |
||||
output.WriteRawTag(25); |
||||
output.WriteDouble(MaxSeen); |
||||
} |
||||
if (Sum != 0D) { |
||||
output.WriteRawTag(33); |
||||
output.WriteDouble(Sum); |
||||
} |
||||
if (SumOfSquares != 0D) { |
||||
output.WriteRawTag(41); |
||||
output.WriteDouble(SumOfSquares); |
||||
} |
||||
if (Count != 0D) { |
||||
output.WriteRawTag(49); |
||||
output.WriteDouble(Count); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
size += bucket_.CalculateSize(_repeated_bucket_codec); |
||||
if (MinSeen != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (MaxSeen != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (Sum != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (SumOfSquares != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (Count != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(HistogramData other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
bucket_.Add(other.bucket_); |
||||
if (other.MinSeen != 0D) { |
||||
MinSeen = other.MinSeen; |
||||
} |
||||
if (other.MaxSeen != 0D) { |
||||
MaxSeen = other.MaxSeen; |
||||
} |
||||
if (other.Sum != 0D) { |
||||
Sum = other.Sum; |
||||
} |
||||
if (other.SumOfSquares != 0D) { |
||||
SumOfSquares = other.SumOfSquares; |
||||
} |
||||
if (other.Count != 0D) { |
||||
Count = other.Count; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 10: |
||||
case 8: { |
||||
bucket_.AddEntriesFrom(input, _repeated_bucket_codec); |
||||
break; |
||||
} |
||||
case 17: { |
||||
MinSeen = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 25: { |
||||
MaxSeen = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 33: { |
||||
Sum = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 41: { |
||||
SumOfSquares = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 49: { |
||||
Count = input.ReadDouble(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class ClientStats : pb::IMessage<ClientStats> { |
||||
private static readonly pb::MessageParser<ClientStats> _parser = new pb::MessageParser<ClientStats>(() => new ClientStats()); |
||||
public static pb::MessageParser<ClientStats> Parser { get { return _parser; } } |
||||
|
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[3]; } |
||||
} |
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
public ClientStats() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
public ClientStats(ClientStats other) : this() { |
||||
Latencies = other.latencies_ != null ? other.Latencies.Clone() : null; |
||||
timeElapsed_ = other.timeElapsed_; |
||||
timeUser_ = other.timeUser_; |
||||
timeSystem_ = other.timeSystem_; |
||||
} |
||||
|
||||
public ClientStats Clone() { |
||||
return new ClientStats(this); |
||||
} |
||||
|
||||
public const int LatenciesFieldNumber = 1; |
||||
private global::Grpc.Testing.HistogramData latencies_; |
||||
public global::Grpc.Testing.HistogramData Latencies { |
||||
get { return latencies_; } |
||||
set { |
||||
latencies_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int TimeElapsedFieldNumber = 2; |
||||
private double timeElapsed_; |
||||
public double TimeElapsed { |
||||
get { return timeElapsed_; } |
||||
set { |
||||
timeElapsed_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int TimeUserFieldNumber = 3; |
||||
private double timeUser_; |
||||
public double TimeUser { |
||||
get { return timeUser_; } |
||||
set { |
||||
timeUser_ = value; |
||||
} |
||||
} |
||||
|
||||
public const int TimeSystemFieldNumber = 4; |
||||
private double timeSystem_; |
||||
public double TimeSystem { |
||||
get { return timeSystem_; } |
||||
set { |
||||
timeSystem_ = value; |
||||
} |
||||
} |
||||
|
||||
public override bool Equals(object other) { |
||||
return Equals(other as ClientStats); |
||||
} |
||||
|
||||
public bool Equals(ClientStats other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (!object.Equals(Latencies, other.Latencies)) return false; |
||||
if (TimeElapsed != other.TimeElapsed) return false; |
||||
if (TimeUser != other.TimeUser) return false; |
||||
if (TimeSystem != other.TimeSystem) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (latencies_ != null) hash ^= Latencies.GetHashCode(); |
||||
if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode(); |
||||
if (TimeUser != 0D) hash ^= TimeUser.GetHashCode(); |
||||
if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
return pb::JsonFormatter.Default.Format(this); |
||||
} |
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (latencies_ != null) { |
||||
output.WriteRawTag(10); |
||||
output.WriteMessage(Latencies); |
||||
} |
||||
if (TimeElapsed != 0D) { |
||||
output.WriteRawTag(17); |
||||
output.WriteDouble(TimeElapsed); |
||||
} |
||||
if (TimeUser != 0D) { |
||||
output.WriteRawTag(25); |
||||
output.WriteDouble(TimeUser); |
||||
} |
||||
if (TimeSystem != 0D) { |
||||
output.WriteRawTag(33); |
||||
output.WriteDouble(TimeSystem); |
||||
} |
||||
} |
||||
|
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (latencies_ != null) { |
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Latencies); |
||||
} |
||||
if (TimeElapsed != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (TimeUser != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
if (TimeSystem != 0D) { |
||||
size += 1 + 8; |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
public void MergeFrom(ClientStats other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.latencies_ != null) { |
||||
if (latencies_ == null) { |
||||
latencies_ = new global::Grpc.Testing.HistogramData(); |
||||
} |
||||
Latencies.MergeFrom(other.Latencies); |
||||
} |
||||
if (other.TimeElapsed != 0D) { |
||||
TimeElapsed = other.TimeElapsed; |
||||
} |
||||
if (other.TimeUser != 0D) { |
||||
TimeUser = other.TimeUser; |
||||
} |
||||
if (other.TimeSystem != 0D) { |
||||
TimeSystem = other.TimeSystem; |
||||
} |
||||
} |
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
input.SkipLastField(); |
||||
break; |
||||
case 10: { |
||||
if (latencies_ == null) { |
||||
latencies_ = new global::Grpc.Testing.HistogramData(); |
||||
} |
||||
input.ReadMessage(latencies_); |
||||
break; |
||||
} |
||||
case 17: { |
||||
TimeElapsed = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 25: { |
||||
TimeUser = input.ReadDouble(); |
||||
break; |
||||
} |
||||
case 33: { |
||||
TimeSystem = input.ReadDouble(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
|
||||
#endregion Designer generated code |
@ -0,0 +1,78 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using Grpc.Testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Snapshottable wall clock stopwatch. |
||||
/// </summary> |
||||
public class WallClockStopwatch |
||||
{ |
||||
long startTicks; |
||||
|
||||
public WallClockStopwatch() |
||||
{ |
||||
this.startTicks = DateTime.UtcNow.Ticks; |
||||
} |
||||
|
||||
public TimeSpan GetElapsedSnapshot(bool reset) |
||||
{ |
||||
var utcNow = DateTime.UtcNow; |
||||
|
||||
long oldStartTicks; |
||||
if (reset) |
||||
{ |
||||
oldStartTicks = Interlocked.Exchange(ref this.startTicks, utcNow.Ticks); |
||||
} |
||||
else |
||||
{ |
||||
oldStartTicks = this.startTicks; |
||||
} |
||||
return utcNow - new DateTime(oldStartTicks, DateTimeKind.Utc); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,96 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.Protobuf; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using Grpc.IntegrationTesting; |
||||
|
||||
namespace Grpc.Testing |
||||
{ |
||||
/// <summary> |
||||
/// Implementation of WorkerService server |
||||
/// </summary> |
||||
public class WorkerServiceImpl : WorkerService.IWorkerService |
||||
{ |
||||
public async Task RunServer(IAsyncStreamReader<ServerArgs> requestStream, IServerStreamWriter<ServerStatus> responseStream, ServerCallContext context) |
||||
{ |
||||
Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext()); |
||||
var serverConfig = requestStream.Current.Setup; |
||||
var runner = ServerRunners.CreateStarted(serverConfig); |
||||
|
||||
await responseStream.WriteAsync(new ServerStatus |
||||
{ |
||||
Stats = runner.GetStats(false), |
||||
Port = runner.BoundPort, |
||||
Cores = 0, // TODO: set number of cores |
||||
}); |
||||
|
||||
while (await requestStream.MoveNext()) |
||||
{ |
||||
var reset = requestStream.Current.Mark.Reset; |
||||
await responseStream.WriteAsync(new ServerStatus |
||||
{ |
||||
Stats = runner.GetStats(reset) |
||||
}); |
||||
} |
||||
await runner.StopAsync(); |
||||
} |
||||
|
||||
public async Task RunClient(IAsyncStreamReader<ClientArgs> requestStream, IServerStreamWriter<ClientStatus> responseStream, ServerCallContext context) |
||||
{ |
||||
Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext()); |
||||
var clientConfig = requestStream.Current.Setup; |
||||
var runner = ClientRunners.CreateStarted(clientConfig); |
||||
|
||||
await responseStream.WriteAsync(new ClientStatus |
||||
{ |
||||
Stats = runner.GetStats(false) |
||||
}); |
||||
|
||||
while (await requestStream.MoveNext()) |
||||
{ |
||||
var reset = requestStream.Current.Mark.Reset; |
||||
await responseStream.WriteAsync(new ClientStatus |
||||
{ |
||||
Stats = runner.GetStats(reset) |
||||
}); |
||||
} |
||||
await runner.StopAsync(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,446 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "test/core/end2end/end2end_tests.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/byte_buffer.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/time.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
#include "src/core/support/string.h" |
||||
#include "test/core/end2end/cq_verifier.h" |
||||
|
||||
static void *tag(gpr_intptr t) { return (void *)t; } |
||||
|
||||
const char *hobbits[][2] = {{"Adaldrida", "Brandybuck"}, |
||||
{"Adamanta", "Took"}, |
||||
{"Adalgrim", "Took"}, |
||||
{"Adelard", "Took"}, |
||||
{"Amaranth", "Brandybuck"}, |
||||
{"Andwise", "Roper"}, |
||||
{"Angelica", "Baggins"}, |
||||
{"Asphodel", "Burrows"}, |
||||
{"Balbo", "Baggins"}, |
||||
{"Bandobras", "Took"}, |
||||
{"Belba", "Bolger"}, |
||||
{"Bell", "Gamgee"}, |
||||
{"Belladonna", "Baggins"}, |
||||
{"Berylla", "Baggins"}, |
||||
{"Bilbo", "Baggins"}, |
||||
{"Bilbo", "Gardner"}, |
||||
{"Bill", "Butcher"}, |
||||
{"Bingo", "Baggins"}, |
||||
{"Bodo", "Proudfoot"}, |
||||
{"Bowman", "Cotton"}, |
||||
{"Bungo", "Baggins"}, |
||||
{"Camellia", "Sackville"}, |
||||
{"Carl", "Cotton"}, |
||||
{"Celandine", "Brandybuck"}, |
||||
{"Chica", "Baggins"}, |
||||
{"Daddy", "Twofoot"}, |
||||
{"Daisy", "Boffin"}, |
||||
{"Diamond", "Took"}, |
||||
{"Dinodas", "Brandybuck"}, |
||||
{"Doderic", "Brandybuck"}, |
||||
{"Dodinas", "Brandybuck"}, |
||||
{"Donnamira", "Boffin"}, |
||||
{"Dora", "Baggins"}, |
||||
{"Drogo", "Baggins"}, |
||||
{"Dudo", "Baggins"}, |
||||
{"Eglantine", "Took"}, |
||||
{"Elanor", "Fairbairn"}, |
||||
{"Elfstan", "Fairbairn"}, |
||||
{"Esmeralda", "Brandybuck"}, |
||||
{"Estella", "Brandybuck"}, |
||||
{"Everard", "Took"}, |
||||
{"Falco", "Chubb-Baggins"}, |
||||
{"Faramir", "Took"}, |
||||
{"Farmer", "Maggot"}, |
||||
{"Fastolph", "Bolger"}, |
||||
{"Ferdibrand", "Took"}, |
||||
{"Ferdinand", "Took"}, |
||||
{"Ferumbras", "Took"}, |
||||
{"Ferumbras", "Took"}, |
||||
{"Filibert", "Bolger"}, |
||||
{"Firiel", "Fairbairn"}, |
||||
{"Flambard", "Took"}, |
||||
{"Folco", "Boffin"}, |
||||
{"Fortinbras", "Took"}, |
||||
{"Fortinbras", "Took"}, |
||||
{"Fosco", "Baggins"}, |
||||
{"Fredegar", "Bolger"}, |
||||
{"Frodo", "Baggins"}, |
||||
{"Frodo", "Gardner"}, |
||||
{"Gerontius", "Took"}, |
||||
{"Gilly", "Baggins"}, |
||||
{"Goldilocks", "Took"}, |
||||
{"Gorbadoc", "Brandybuck"}, |
||||
{"Gorbulas", "Brandybuck"}, |
||||
{"Gorhendad", "Brandybuck"}, |
||||
{"Gormadoc", "Brandybuck"}, |
||||
{"Griffo", "Boffin"}, |
||||
{"Halfast", "Gamgee"}, |
||||
{"Halfred", "Gamgee"}, |
||||
{"Halfred", "Greenhand"}, |
||||
{"Hanna", "Brandybuck"}, |
||||
{"Hamfast", "Gamgee"}, |
||||
{"Hamfast", "Gardner"}, |
||||
{"Hamson", "Gamgee"}, |
||||
{"Harding", "Gardner"}, |
||||
{"Hilda", "Brandybuck"}, |
||||
{"Hildibrand", "Took"}, |
||||
{"Hildifons", "Took"}, |
||||
{"Hildigard", "Took"}, |
||||
{"Hildigrim", "Took"}, |
||||
{"Hob", "Gammidge"}, |
||||
{"Hob", "Hayward"}, |
||||
{"Hobson", "Gamgee"}, |
||||
{"Holfast", "Gardner"}, |
||||
{"Holman", "Cotton"}, |
||||
{"Holman", "Greenhand"}, |
||||
{"Hugo", "Boffin"}, |
||||
{"Hugo", "Bracegirdle"}, |
||||
{"Ilberic", "Brandybuck"}, |
||||
{"Isembard", "Took"}, |
||||
{"Isembold", "Took"}, |
||||
{"Isengar", "Took"}, |
||||
{"Isengrim", "Took"}, |
||||
{"Isengrim", "Took"}, |
||||
{"Isumbras", "Took"}, |
||||
{"Isumbras", "Took"}, |
||||
{"Jolly", "Cotton"}, |
||||
{"Lalia", "Took"}, |
||||
{"Largo", "Baggins"}, |
||||
{"Laura", "Baggins"}, |
||||
{"Lily", "Goodbody"}, |
||||
{"Lily", "Cotton"}, |
||||
{"Linda", "Proudfoot"}, |
||||
{"Lobelia", "Sackville-Baggins"}, |
||||
{"Longo", "Baggins"}, |
||||
{"Lotho", "Sackville-Baggins"}, |
||||
{"Madoc", "Brandybuck"}, |
||||
{"Malva", "Brandybuck"}, |
||||
{"Marigold", "Cotton"}, |
||||
{"Marmadas", "Brandybuck"}, |
||||
{"Marmadoc", "Brandybuck"}, |
||||
{"Marroc", "Brandybuck"}, |
||||
{"May", "Gamgee"}, |
||||
{"Melilot", "Brandybuck"}, |
||||
{"Menegilda", "Brandybuck"}, |
||||
{"Mentha", "Brandybuck"}, |
||||
{"Meriadoc", "Brandybuck"}, |
||||
{"Merimac", "Brandybuck"}, |
||||
{"Merimas", "Brandybuck"}, |
||||
{"Merry", "Gardner"}, |
||||
{"Milo", "Burrows"}, |
||||
{"Mimosa", "Baggins"}, |
||||
{"Minto", "Burrows"}, |
||||
{"Mirabella", "Brandybuck"}, |
||||
{"Moro", "Burrows"}, |
||||
{"Mosco", "Burrows"}, |
||||
{"Mungo", "Baggins"}, |
||||
{"Myrtle", "Burrows"}, |
||||
{"Odo", "Proudfoot"}, |
||||
{"Odovacar", "Bolger"}, |
||||
{"Olo", "Proudfoot"}, |
||||
{"Orgulas", "Brandybuck"}, |
||||
{"Otho", "Sackville-Baggins"}, |
||||
{"Paladin", "Took"}, |
||||
{"Pansy", "Bolger"}, |
||||
{"Pearl", "Took"}, |
||||
{"Peony", "Burrows"}, |
||||
{"Peregrin", "Took"}, |
||||
{"Pervinca", "Took"}, |
||||
{"Pimpernel", "Took"}, |
||||
{"Pippin", "Gardner"}, |
||||
{"Polo", "Baggins"}, |
||||
{"Ponto", "Baggins"}, |
||||
{"Porto", "Baggins"}, |
||||
{"Posco", "Baggins"}, |
||||
{"Poppy", "Bolger"}, |
||||
{"Primrose", "Gardner"}, |
||||
{"Primula", "Baggins"}, |
||||
{"Prisca", "Bolger"}, |
||||
{"Reginard", "Took"}, |
||||
{"Robin", "Smallburrow"}, |
||||
{"Robin", "Gardner"}, |
||||
{"Rorimac", "Brandybuck"}, |
||||
{"Rosa", "Took"}, |
||||
{"Rosamunda", "Bolger"}, |
||||
{"Rose", "Gardner"}, |
||||
{"Ruby", "Baggins"}, |
||||
{"Ruby", "Gardner"}, |
||||
{"Rudigar", "Bolger"}, |
||||
{"Rufus", "Burrows"}, |
||||
{"Sadoc", "Brandybuck"}, |
||||
{"Salvia", "Bolger"}, |
||||
{"Samwise", "Gamgee"}, |
||||
{"Sancho", "Proudfoot"}, |
||||
{"Saradas", "Brandybuck"}, |
||||
{"Saradoc", "Brandybuck"}, |
||||
{"Seredic", "Brandybuck"}, |
||||
{"Sigismond", "Took"}, |
||||
{"Smeagol", "Gollum"}, |
||||
{"Tanta", "Baggins"}, |
||||
{"Ted", "Sandyman"}, |
||||
{"Tobold", "Hornblower"}, |
||||
{"Togo", "Goodbody"}, |
||||
{"Tolman", "Cotton"}, |
||||
{"Tolman", "Gardner"}, |
||||
{"Widow", "Rumble"}, |
||||
{"Wilcome", "Cotton"}, |
||||
{"Wilcome", "Cotton"}, |
||||
{"Wilibald", "Bolger"}, |
||||
{"Will", "Whitfoot"}, |
||||
{"Wiseman", "Gamwich"}}; |
||||
|
||||
const char *dragons[] = {"Ancalagon", "Glaurung", "Scatha", |
||||
"Smaug the Magnificent"}; |
||||
|
||||
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, |
||||
const char *test_name, |
||||
grpc_channel_args *client_args, |
||||
grpc_channel_args *server_args) { |
||||
grpc_end2end_test_fixture f; |
||||
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); |
||||
f = config.create_fixture(client_args, server_args); |
||||
config.init_client(&f, client_args); |
||||
config.init_server(&f, server_args); |
||||
return f; |
||||
} |
||||
|
||||
static gpr_timespec n_seconds_time(int n) { |
||||
return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n); |
||||
} |
||||
|
||||
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); } |
||||
|
||||
static void drain_cq(grpc_completion_queue *cq) { |
||||
grpc_event ev; |
||||
do { |
||||
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL); |
||||
} while (ev.type != GRPC_QUEUE_SHUTDOWN); |
||||
} |
||||
|
||||
static void shutdown_server(grpc_end2end_test_fixture *f) { |
||||
if (!f->server) return; |
||||
grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000)); |
||||
GPR_ASSERT(grpc_completion_queue_pluck( |
||||
f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL) |
||||
.type == GRPC_OP_COMPLETE); |
||||
grpc_server_destroy(f->server); |
||||
f->server = NULL; |
||||
} |
||||
|
||||
static void shutdown_client(grpc_end2end_test_fixture *f) { |
||||
if (!f->client) return; |
||||
grpc_channel_destroy(f->client); |
||||
f->client = NULL; |
||||
} |
||||
|
||||
static void end_test(grpc_end2end_test_fixture *f) { |
||||
shutdown_server(f); |
||||
shutdown_client(f); |
||||
|
||||
grpc_completion_queue_shutdown(f->cq); |
||||
drain_cq(f->cq); |
||||
grpc_completion_queue_destroy(f->cq); |
||||
} |
||||
|
||||
static void simple_request_body(grpc_end2end_test_fixture f, size_t index) { |
||||
grpc_call *c; |
||||
grpc_call *s; |
||||
gpr_timespec deadline = five_seconds_time(); |
||||
cq_verifier *cqv = cq_verifier_create(f.cq); |
||||
grpc_op ops[6]; |
||||
grpc_op *op; |
||||
grpc_metadata_array initial_metadata_recv; |
||||
grpc_metadata_array trailing_metadata_recv; |
||||
grpc_metadata_array request_metadata_recv; |
||||
grpc_call_details call_details; |
||||
grpc_status_code status; |
||||
grpc_call_error error; |
||||
grpc_metadata extra_metadata[3]; |
||||
char *details = NULL; |
||||
size_t details_capacity = 0; |
||||
int was_cancelled = 2; |
||||
|
||||
memset(extra_metadata, 0, sizeof(extra_metadata)); |
||||
extra_metadata[0].key = "hobbit-first-name"; |
||||
extra_metadata[0].value = hobbits[index % GPR_ARRAY_SIZE(hobbits)][0]; |
||||
extra_metadata[0].value_length = strlen(extra_metadata[0].value); |
||||
extra_metadata[1].key = "hobbit-second-name"; |
||||
extra_metadata[1].value = hobbits[index % GPR_ARRAY_SIZE(hobbits)][1]; |
||||
extra_metadata[1].value_length = strlen(extra_metadata[1].value); |
||||
extra_metadata[2].key = "dragon"; |
||||
extra_metadata[2].value = dragons[index % GPR_ARRAY_SIZE(dragons)]; |
||||
extra_metadata[2].value_length = strlen(extra_metadata[2].value); |
||||
|
||||
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, |
||||
"/foo", "foo.test.google.fr:1234", deadline, |
||||
NULL); |
||||
GPR_ASSERT(c); |
||||
|
||||
grpc_metadata_array_init(&initial_metadata_recv); |
||||
grpc_metadata_array_init(&trailing_metadata_recv); |
||||
grpc_metadata_array_init(&request_metadata_recv); |
||||
grpc_call_details_init(&call_details); |
||||
|
||||
op = ops; |
||||
op->op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
op->data.send_initial_metadata.count = GPR_ARRAY_SIZE(extra_metadata); |
||||
op->data.send_initial_metadata.metadata = extra_metadata; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_RECV_INITIAL_METADATA; |
||||
op->data.recv_initial_metadata = &initial_metadata_recv; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
||||
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; |
||||
op->data.recv_status_on_client.status = &status; |
||||
op->data.recv_status_on_client.status_details = &details; |
||||
op->data.recv_status_on_client.status_details_capacity = &details_capacity; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); |
||||
GPR_ASSERT(GRPC_CALL_OK == error); |
||||
|
||||
error = |
||||
grpc_server_request_call(f.server, &s, &call_details, |
||||
&request_metadata_recv, f.cq, f.cq, tag(101)); |
||||
GPR_ASSERT(GRPC_CALL_OK == error); |
||||
cq_expect_completion(cqv, tag(101), 1); |
||||
cq_verify(cqv); |
||||
|
||||
op = ops; |
||||
op->op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
op->data.send_initial_metadata.count = 0; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; |
||||
op->data.send_status_from_server.trailing_metadata_count = 0; |
||||
op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED; |
||||
op->data.send_status_from_server.status_details = "xyz"; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; |
||||
op->data.recv_close_on_server.cancelled = &was_cancelled; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL); |
||||
GPR_ASSERT(GRPC_CALL_OK == error); |
||||
|
||||
cq_expect_completion(cqv, tag(102), 1); |
||||
cq_expect_completion(cqv, tag(1), 1); |
||||
cq_verify(cqv); |
||||
|
||||
GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); |
||||
GPR_ASSERT(0 == strcmp(details, "xyz")); |
||||
GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); |
||||
GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234")); |
||||
GPR_ASSERT(was_cancelled == 1); |
||||
|
||||
gpr_free(details); |
||||
grpc_metadata_array_destroy(&initial_metadata_recv); |
||||
grpc_metadata_array_destroy(&trailing_metadata_recv); |
||||
grpc_metadata_array_destroy(&request_metadata_recv); |
||||
grpc_call_details_destroy(&call_details); |
||||
|
||||
grpc_call_destroy(c); |
||||
grpc_call_destroy(s); |
||||
|
||||
cq_verifier_destroy(cqv); |
||||
} |
||||
|
||||
static void test_size(grpc_end2end_test_config config, int encode_size, |
||||
int decode_size) { |
||||
size_t i; |
||||
grpc_end2end_test_fixture f; |
||||
grpc_arg server_arg; |
||||
grpc_channel_args server_args; |
||||
grpc_arg client_arg; |
||||
grpc_channel_args client_args; |
||||
char *name; |
||||
|
||||
server_arg.type = GRPC_ARG_INTEGER; |
||||
server_arg.key = GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER; |
||||
server_arg.value.integer = decode_size; |
||||
server_args.num_args = 1; |
||||
server_args.args = &server_arg; |
||||
|
||||
client_arg.type = GRPC_ARG_INTEGER; |
||||
client_arg.key = GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER; |
||||
client_arg.value.integer = encode_size; |
||||
client_args.num_args = 1; |
||||
client_args.args = &client_arg; |
||||
|
||||
gpr_asprintf(&name, "test_size:e=%d:d=%d", encode_size, decode_size); |
||||
f = begin_test(config, name, encode_size != 4096 ? &client_args : NULL, |
||||
decode_size != 4096 ? &server_args : NULL); |
||||
for (i = 0; i < 4 * GPR_ARRAY_SIZE(hobbits); i++) { |
||||
simple_request_body(f, i); |
||||
} |
||||
end_test(&f); |
||||
config.tear_down_data(&f); |
||||
gpr_free(name); |
||||
} |
||||
|
||||
void grpc_end2end_tests(grpc_end2end_test_config config) { |
||||
static const int interesting_sizes[] = {4096, 0, 100, |
||||
1000, 32768, 4 * 1024 * 1024}; |
||||
size_t i, j; |
||||
|
||||
for (i = 0; i < GPR_ARRAY_SIZE(interesting_sizes); i++) { |
||||
for (j = 0; j < GPR_ARRAY_SIZE(interesting_sizes); j++) { |
||||
test_size(config, interesting_sizes[i], interesting_sizes[j]); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,103 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*is % allowed in string |
||||
*/ |
||||
|
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <gflags/gflags.h> |
||||
#include <grpc++/grpc++.h> |
||||
|
||||
#include "test/cpp/util/metrics_server.h" |
||||
#include "test/cpp/util/test_config.h" |
||||
#include "test/proto/metrics.grpc.pb.h" |
||||
#include "test/proto/metrics.pb.h" |
||||
|
||||
DEFINE_string(metrics_server_address, "", |
||||
"The metrics server addresses in the fomrat <hostname>:<port>"); |
||||
|
||||
using grpc::testing::EmptyMessage; |
||||
using grpc::testing::GaugeResponse; |
||||
using grpc::testing::MetricsService; |
||||
using grpc::testing::MetricsServiceImpl; |
||||
|
||||
void PrintMetrics(grpc::string& server_address) { |
||||
gpr_log(GPR_INFO, "creating a channel to %s", server_address.c_str()); |
||||
std::shared_ptr<grpc::Channel> channel( |
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials())); |
||||
|
||||
std::unique_ptr<MetricsService::Stub> stub(MetricsService::NewStub(channel)); |
||||
|
||||
grpc::ClientContext context; |
||||
EmptyMessage message; |
||||
|
||||
std::unique_ptr<grpc::ClientReader<GaugeResponse>> reader( |
||||
stub->GetAllGauges(&context, message)); |
||||
|
||||
GaugeResponse gauge_response; |
||||
long overall_qps = 0; |
||||
int idx = 0; |
||||
while (reader->Read(&gauge_response)) { |
||||
if (gauge_response.value_case() == GaugeResponse::kLongValue) { |
||||
gpr_log(GPR_INFO, "Gauge: %d (%s: %ld)", ++idx, |
||||
gauge_response.name().c_str(), gauge_response.long_value()); |
||||
overall_qps += gauge_response.long_value(); |
||||
} else { |
||||
gpr_log(GPR_INFO, "Gauge %s is not a long value", |
||||
gauge_response.name().c_str()); |
||||
} |
||||
} |
||||
|
||||
gpr_log(GPR_INFO, "OVERALL: %ld", overall_qps); |
||||
|
||||
const grpc::Status status = reader->Finish(); |
||||
if (!status.ok()) { |
||||
gpr_log(GPR_ERROR, "Error in getting metrics from the client"); |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc::testing::InitTest(&argc, &argv, true); |
||||
|
||||
// Make sure server_addresses flag is not empty
|
||||
if (FLAGS_metrics_server_address.empty()) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Cannot connect to the Metrics server. Please pass the address of the" |
||||
"metrics server to connect to via the 'metrics_server_address' flag"); |
||||
return 1; |
||||
} |
||||
|
||||
PrintMetrics(FLAGS_metrics_server_address); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,119 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*is % allowed in string |
||||
*/ |
||||
|
||||
#include "test/cpp/util/metrics_server.h" |
||||
|
||||
#include <grpc++/server_builder.h> |
||||
|
||||
#include "test/proto/metrics.grpc.pb.h" |
||||
#include "test/proto/metrics.pb.h" |
||||
|
||||
namespace grpc { |
||||
namespace testing { |
||||
|
||||
Gauge::Gauge(long initial_val) : val_(initial_val) {} |
||||
|
||||
void Gauge::Set(long new_val) { |
||||
std::lock_guard<std::mutex> lock(val_mu_); |
||||
val_ = new_val; |
||||
} |
||||
|
||||
long Gauge::Get() { |
||||
std::lock_guard<std::mutex> lock(val_mu_); |
||||
return val_; |
||||
} |
||||
|
||||
grpc::Status MetricsServiceImpl::GetAllGauges( |
||||
ServerContext* context, const EmptyMessage* request, |
||||
ServerWriter<GaugeResponse>* writer) { |
||||
gpr_log(GPR_INFO, "GetAllGauges called"); |
||||
|
||||
std::lock_guard<std::mutex> lock(mu_); |
||||
for (auto it = gauges_.begin(); it != gauges_.end(); it++) { |
||||
GaugeResponse resp; |
||||
resp.set_name(it->first); // Gauge name
|
||||
resp.set_long_value(it->second->Get()); // Gauge value
|
||||
writer->Write(resp); |
||||
} |
||||
|
||||
return Status::OK; |
||||
} |
||||
|
||||
grpc::Status MetricsServiceImpl::GetGauge(ServerContext* context, |
||||
const GaugeRequest* request, |
||||
GaugeResponse* response) { |
||||
std::lock_guard<std::mutex> lock(mu_); |
||||
|
||||
const auto it = gauges_.find(request->name()); |
||||
if (it != gauges_.end()) { |
||||
response->set_name(it->first); |
||||
response->set_long_value(it->second->Get()); |
||||
} |
||||
|
||||
return Status::OK; |
||||
} |
||||
|
||||
std::shared_ptr<Gauge> MetricsServiceImpl::CreateGauge(const grpc::string& name, |
||||
bool* already_present) { |
||||
std::lock_guard<std::mutex> lock(mu_); |
||||
|
||||
std::shared_ptr<Gauge> gauge(new Gauge(0)); |
||||
const auto p = gauges_.emplace(name, gauge); |
||||
|
||||
// p.first is an iterator pointing to <name, shared_ptr<Gauge>> pair. p.second
|
||||
// is a boolean which is set to 'true' if the Gauge is inserted in the guages_
|
||||
// map and 'false' if it is already present in the map
|
||||
*already_present = !p.second; |
||||
return p.first->second; |
||||
} |
||||
|
||||
// Starts the metrics server and returns the grpc::Server instance. Call Wait()
|
||||
// on the returned server instance.
|
||||
std::unique_ptr<grpc::Server> MetricsServiceImpl::StartServer(int port) { |
||||
gpr_log(GPR_INFO, "Building metrics server.."); |
||||
|
||||
const grpc::string address = "0.0.0.0:" + std::to_string(port); |
||||
|
||||
ServerBuilder builder; |
||||
builder.AddListeningPort(address, grpc::InsecureServerCredentials()); |
||||
builder.RegisterService(this); |
||||
|
||||
std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); |
||||
gpr_log(GPR_INFO, "Metrics server %s started. Ready to receive requests..", |
||||
address.c_str()); |
||||
|
||||
return server; |
||||
} |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
@ -0,0 +1,100 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*is % allowed in string |
||||
*/ |
||||
#ifndef GRPC_TEST_CPP_METRICS_SERVER_H |
||||
#define GRPC_TEST_CPP_METRICS_SERVER_H |
||||
|
||||
#include <map> |
||||
#include <mutex> |
||||
|
||||
#include "test/proto/metrics.grpc.pb.h" |
||||
#include "test/proto/metrics.pb.h" |
||||
|
||||
/*
|
||||
* This implements a Metrics server defined in test/proto/metrics.proto. Any |
||||
* test service can use this to export Metrics (TODO (sreek): Only Gauges for |
||||
* now). |
||||
* |
||||
* Example: |
||||
* MetricsServiceImpl metricsImpl; |
||||
* .. |
||||
* // Create Gauge(s). Note: Gauges can be created even after calling
|
||||
* // 'StartServer'.
|
||||
* Gauge gauge1 = metricsImpl.CreateGauge("foo",is_present); |
||||
* // gauge1 can now be used anywhere in the program to set values.
|
||||
* ... |
||||
* // Create the metrics server
|
||||
* std::unique_ptr<grpc::Server> server = metricsImpl.StartServer(port); |
||||
* server->Wait(); // Note: This is blocking.
|
||||
*/ |
||||
namespace grpc { |
||||
namespace testing { |
||||
|
||||
// TODO(sreek): Add support for other types of Gauges like Double, String in
|
||||
// future
|
||||
class Gauge { |
||||
public: |
||||
Gauge(long initial_val); |
||||
void Set(long new_val); |
||||
long Get(); |
||||
|
||||
private: |
||||
long val_; |
||||
std::mutex val_mu_; |
||||
}; |
||||
|
||||
class MetricsServiceImpl GRPC_FINAL : public MetricsService::Service { |
||||
public: |
||||
grpc::Status GetAllGauges(ServerContext* context, const EmptyMessage* request, |
||||
ServerWriter<GaugeResponse>* writer) GRPC_OVERRIDE; |
||||
|
||||
grpc::Status GetGauge(ServerContext* context, const GaugeRequest* request, |
||||
GaugeResponse* response) GRPC_OVERRIDE; |
||||
|
||||
// Create a Gauge with name 'name'. is_present is set to true if the Gauge
|
||||
// is already present in the map.
|
||||
// NOTE: CreateGauge can be called anytime (i.e before or after calling
|
||||
// StartServer).
|
||||
std::shared_ptr<Gauge> CreateGauge(const grpc::string& name, |
||||
bool* already_present); |
||||
|
||||
std::unique_ptr<grpc::Server> StartServer(int port); |
||||
|
||||
private: |
||||
std::map<string, std::shared_ptr<Gauge>> gauges_; |
||||
std::mutex mu_; |
||||
}; |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_TEST_CPP_METRICS_SERVER_H
|
@ -0,0 +1,56 @@ |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
// An integration test service that covers all the method signature permutations |
||||
// of unary/streaming requests/responses. |
||||
syntax = "proto3"; |
||||
|
||||
package grpc.testing; |
||||
|
||||
message GaugeResponse { |
||||
string name = 1; |
||||
oneof value { |
||||
int64 long_value = 2; |
||||
double double_vale = 3; |
||||
string string_value = 4; |
||||
} |
||||
} |
||||
|
||||
message GaugeRequest { |
||||
string name = 1; |
||||
} |
||||
|
||||
message EmptyMessage { |
||||
} |
||||
|
||||
service MetricsService { |
||||
rpc GetAllGauges(EmptyMessage) returns (stream GaugeResponse); |
||||
rpc GetGauge(GaugeRequest) returns (GaugeResponse); |
||||
} |
@ -0,0 +1,216 @@ |
||||
#!/usr/bin/env python2.7 |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import requests |
||||
import json |
||||
|
||||
_REQUEST_TIMEOUT_SECS = 10 |
||||
|
||||
def _make_pod_config(pod_name, image_name, container_port_list, cmd_list, |
||||
arg_list): |
||||
"""Creates a string containing the Pod defintion as required by the Kubernetes API""" |
||||
body = { |
||||
'kind': 'Pod', |
||||
'apiVersion': 'v1', |
||||
'metadata': { |
||||
'name': pod_name, |
||||
'labels': {'name': pod_name} |
||||
}, |
||||
'spec': { |
||||
'containers': [ |
||||
{ |
||||
'name': pod_name, |
||||
'image': image_name, |
||||
'ports': [] |
||||
} |
||||
] |
||||
} |
||||
} |
||||
# Populate the 'ports' list |
||||
for port in container_port_list: |
||||
port_entry = {'containerPort': port, 'protocol': 'TCP'} |
||||
body['spec']['containers'][0]['ports'].append(port_entry) |
||||
|
||||
# Add the 'Command' and 'Args' attributes if they are passed. |
||||
# Note: |
||||
# - 'Command' overrides the ENTRYPOINT in the Docker Image |
||||
# - 'Args' override the COMMAND in Docker image (yes, it is confusing!) |
||||
if len(cmd_list) > 0: |
||||
body['spec']['containers'][0]['command'] = cmd_list |
||||
if len(arg_list) > 0: |
||||
body['spec']['containers'][0]['args'] = arg_list |
||||
return json.dumps(body) |
||||
|
||||
|
||||
def _make_service_config(service_name, pod_name, service_port_list, |
||||
container_port_list, is_headless): |
||||
"""Creates a string containing the Service definition as required by the Kubernetes API. |
||||
|
||||
NOTE: |
||||
This creates either a Headless Service or 'LoadBalancer' service depending on |
||||
the is_headless parameter. For Headless services, there is no 'type' attribute |
||||
and the 'clusterIP' attribute is set to 'None'. Also, if the service is |
||||
Headless, Kubernetes creates DNS entries for Pods - i.e creates DNS A-records |
||||
mapping the service's name to the Pods' IPs |
||||
""" |
||||
if len(container_port_list) != len(service_port_list): |
||||
print( |
||||
'ERROR: container_port_list and service_port_list must be of same size') |
||||
return '' |
||||
body = { |
||||
'kind': 'Service', |
||||
'apiVersion': 'v1', |
||||
'metadata': { |
||||
'name': service_name, |
||||
'labels': { |
||||
'name': service_name |
||||
} |
||||
}, |
||||
'spec': { |
||||
'ports': [], |
||||
'selector': { |
||||
'name': pod_name |
||||
} |
||||
} |
||||
} |
||||
# Populate the 'ports' list in the 'spec' section. This maps service ports |
||||
# (port numbers that are exposed by Kubernetes) to container ports (i.e port |
||||
# numbers that are exposed by your Docker image) |
||||
for idx in range(len(container_port_list)): |
||||
port_entry = { |
||||
'port': service_port_list[idx], |
||||
'targetPort': container_port_list[idx], |
||||
'protocol': 'TCP' |
||||
} |
||||
body['spec']['ports'].append(port_entry) |
||||
|
||||
# Make this either a LoadBalancer service or a headless service depending on |
||||
# the is_headless parameter |
||||
if is_headless: |
||||
body['spec']['clusterIP'] = 'None' |
||||
else: |
||||
body['spec']['type'] = 'LoadBalancer' |
||||
return json.dumps(body) |
||||
|
||||
|
||||
def _print_connection_error(msg): |
||||
print('ERROR: Connection failed. Did you remember to run Kubenetes proxy on ' |
||||
'localhost (i.e kubectl proxy --port=<proxy_port>) ?. Error: %s' % msg) |
||||
|
||||
def _do_post(post_url, api_name, request_body): |
||||
"""Helper to do HTTP POST. |
||||
|
||||
Note: |
||||
1) On success, Kubernetes returns a success code of 201(CREATED) not 200(OK) |
||||
2) A response code of 509(CONFLICT) is interpreted as a success code (since |
||||
the error is most likely due to the resource already existing). This makes |
||||
_do_post() idempotent which is semantically desirable. |
||||
""" |
||||
is_success = True |
||||
try: |
||||
r = requests.post(post_url, data=request_body, timeout=_REQUEST_TIMEOUT_SECS) |
||||
if r.status_code == requests.codes.conflict: |
||||
print('WARN: Looks like the resource already exists. Api: %s, url: %s' % |
||||
(api_name, post_url)) |
||||
elif r.status_code != requests.codes.created: |
||||
print('ERROR: %s API returned error. HTTP response: (%d) %s' % |
||||
(api_name, r.status_code, r.text)) |
||||
is_success = False |
||||
except(requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: |
||||
is_success = False |
||||
_print_connection_error(str(e)) |
||||
return is_success |
||||
|
||||
|
||||
def _do_delete(del_url, api_name): |
||||
"""Helper to do HTTP DELETE. |
||||
|
||||
Note: A response code of 404(NOT_FOUND) is treated as success to keep |
||||
_do_delete() idempotent. |
||||
""" |
||||
is_success = True |
||||
try: |
||||
r = requests.delete(del_url, timeout=_REQUEST_TIMEOUT_SECS) |
||||
if r.status_code == requests.codes.not_found: |
||||
print('WARN: The resource does not exist. Api: %s, url: %s' % |
||||
(api_name, del_url)) |
||||
elif r.status_code != requests.codes.ok: |
||||
print('ERROR: %s API returned error. HTTP response: %s' % |
||||
(api_name, r.text)) |
||||
is_success = False |
||||
except(requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: |
||||
is_success = False |
||||
_print_connection_error(str(e)) |
||||
return is_success |
||||
|
||||
|
||||
def create_service(kube_host, kube_port, namespace, service_name, pod_name, |
||||
service_port_list, container_port_list, is_headless): |
||||
"""Creates either a Headless Service or a LoadBalancer Service depending |
||||
on the is_headless parameter. |
||||
""" |
||||
post_url = 'http://%s:%d/api/v1/namespaces/%s/services' % ( |
||||
kube_host, kube_port, namespace) |
||||
request_body = _make_service_config(service_name, pod_name, service_port_list, |
||||
container_port_list, is_headless) |
||||
return _do_post(post_url, 'Create Service', request_body) |
||||
|
||||
|
||||
def create_pod(kube_host, kube_port, namespace, pod_name, image_name, |
||||
container_port_list, cmd_list, arg_list): |
||||
"""Creates a Kubernetes Pod. |
||||
|
||||
Note that it is generally NOT considered a good practice to directly create |
||||
Pods. Typically, the recommendation is to create 'Controllers' to create and |
||||
manage Pods' lifecycle. Currently Kubernetes only supports 'Replication |
||||
Controller' which creates a configurable number of 'identical Replicas' of |
||||
Pods and automatically restarts any Pods in case of failures (for eg: Machine |
||||
failures in Kubernetes). This makes it less flexible for our test use cases |
||||
where we might want slightly different set of args to each Pod. Hence we |
||||
directly create Pods and not care much about Kubernetes failures since those |
||||
are very rare. |
||||
""" |
||||
post_url = 'http://%s:%d/api/v1/namespaces/%s/pods' % (kube_host, kube_port, |
||||
namespace) |
||||
request_body = _make_pod_config(pod_name, image_name, container_port_list, |
||||
cmd_list, arg_list) |
||||
return _do_post(post_url, 'Create Pod', request_body) |
||||
|
||||
|
||||
def delete_service(kube_host, kube_port, namespace, service_name): |
||||
del_url = 'http://%s:%d/api/v1/namespaces/%s/services/%s' % ( |
||||
kube_host, kube_port, namespace, service_name) |
||||
return _do_delete(del_url, 'Delete Service') |
||||
|
||||
|
||||
def delete_pod(kube_host, kube_port, namespace, pod_name): |
||||
del_url = 'http://%s:%d/api/v1/namespaces/%s/pods/%s' % (kube_host, kube_port, |
||||
namespace, pod_name) |
||||
return _do_delete(del_url, 'Delete Pod') |
@ -0,0 +1,72 @@ |
||||
package http2interop |
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"fmt" |
||||
"io" |
||||
) |
||||
|
||||
type GoAwayFrame struct { |
||||
Header FrameHeader |
||||
Reserved |
||||
StreamID |
||||
// TODO(carl-mastrangelo): make an enum out of this.
|
||||
Code uint32 |
||||
Data []byte |
||||
} |
||||
|
||||
func (f *GoAwayFrame) GetHeader() *FrameHeader { |
||||
return &f.Header |
||||
} |
||||
|
||||
func (f *GoAwayFrame) ParsePayload(r io.Reader) error { |
||||
raw := make([]byte, f.Header.Length) |
||||
if _, err := io.ReadFull(r, raw); err != nil { |
||||
return err |
||||
} |
||||
return f.UnmarshalPayload(raw) |
||||
} |
||||
|
||||
func (f *GoAwayFrame) UnmarshalPayload(raw []byte) error { |
||||
if f.Header.Length != len(raw) { |
||||
return fmt.Errorf("Invalid Payload length %d != %d", f.Header.Length, len(raw)) |
||||
} |
||||
if f.Header.Length < 8 { |
||||
return fmt.Errorf("Invalid Payload length %d", f.Header.Length) |
||||
} |
||||
*f = GoAwayFrame{ |
||||
Reserved: Reserved(raw[0]>>7 == 1), |
||||
StreamID: StreamID(binary.BigEndian.Uint32(raw[0:4]) & 0x7fffffff), |
||||
Code: binary.BigEndian.Uint32(raw[4:8]), |
||||
Data: []byte(string(raw[8:])), |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (f *GoAwayFrame) MarshalPayload() ([]byte, error) { |
||||
raw := make([]byte, 8, 8+len(f.Data)) |
||||
binary.BigEndian.PutUint32(raw[:4], uint32(f.StreamID)) |
||||
binary.BigEndian.PutUint32(raw[4:8], f.Code) |
||||
raw = append(raw, f.Data...) |
||||
|
||||
return raw, nil |
||||
} |
||||
|
||||
func (f *GoAwayFrame) MarshalBinary() ([]byte, error) { |
||||
payload, err := f.MarshalPayload() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
f.Header.Length = len(payload) |
||||
f.Header.Type = GoAwayFrameType |
||||
header, err := f.Header.MarshalBinary() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
header = append(header, payload...) |
||||
|
||||
return header, nil |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue