pull/2151/head
Siddharth Rakesh 10 years ago
commit 668f33c6f3
  1. 11
      src/compiler/cpp_generator.cc
  2. 105
      src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
  3. 6
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  4. 75
      src/csharp/Grpc.Core.Tests/Internal/ChannelArgsSafeHandleTest.cs
  5. 40
      src/csharp/Grpc.Core/Channel.cs
  6. 115
      src/csharp/Grpc.Core/ChannelArgs.cs
  7. 178
      src/csharp/Grpc.Core/ChannelOptions.cs
  8. 6
      src/csharp/Grpc.Core/Grpc.Core.csproj
  9. 8
      src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
  10. 4
      src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
  11. 18
      src/csharp/Grpc.Core/Server.cs
  12. 10
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  13. 9
      src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
  14. 10
      src/csharp/ext/grpc_csharp_ext.c
  15. 137
      src/php/README.md
  16. 4
      src/php/bin/run_gen_code_test.sh
  17. 7
      src/php/composer.json
  18. 2
      src/php/tests/generated_code/AbstractGeneratedCodeTest.php
  19. 2
      src/php/tests/interop/interop_client.php
  20. 13
      src/python/src/grpc/_adapter/_c/utility.c
  21. 132
      test/compiler/python_plugin_test.py
  22. 2
      tools/run_tests/build_python.sh
  23. 16
      tools/run_tests/jobset.py
  24. 9
      tools/run_tests/run_tests.py

@ -849,6 +849,9 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
"::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"const $Request$* request, $Response$* response) {\n");
printer->Print(" (void) context;\n");
printer->Print(" (void) request;\n");
printer->Print(" (void) response;\n");
printer->Print(
" return ::grpc::Status("
"::grpc::StatusCode::UNIMPLEMENTED);\n");
@ -859,6 +862,9 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
"::grpc::ServerContext* context, "
"::grpc::ServerReader< $Request$>* reader, "
"$Response$* response) {\n");
printer->Print(" (void) context;\n");
printer->Print(" (void) reader;\n");
printer->Print(" (void) response;\n");
printer->Print(
" return ::grpc::Status("
"::grpc::StatusCode::UNIMPLEMENTED);\n");
@ -869,6 +875,9 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
"::grpc::ServerContext* context, "
"const $Request$* request, "
"::grpc::ServerWriter< $Response$>* writer) {\n");
printer->Print(" (void) context;\n");
printer->Print(" (void) request;\n");
printer->Print(" (void) writer;\n");
printer->Print(
" return ::grpc::Status("
"::grpc::StatusCode::UNIMPLEMENTED);\n");
@ -879,6 +888,8 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
"::grpc::ServerContext* context, "
"::grpc::ServerReaderWriter< $Response$, $Request$>* "
"stream) {\n");
printer->Print(" (void) context;\n");
printer->Print(" (void) stream;\n");
printer->Print(
" return ::grpc::Status("
"::grpc::StatusCode::UNIMPLEMENTED);\n");

@ -0,0 +1,105 @@
#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 Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
{
public class ChannelOptionsTest
{
[Test]
public void IntOption()
{
var option = new ChannelOption("somename", 1);
Assert.AreEqual(ChannelOption.OptionType.Integer, option.Type);
Assert.AreEqual("somename", option.Name);
Assert.AreEqual(1, option.IntValue);
Assert.Throws(typeof(InvalidOperationException), () => { var s = option.StringValue; });
}
[Test]
public void StringOption()
{
var option = new ChannelOption("somename", "ABCDEF");
Assert.AreEqual(ChannelOption.OptionType.String, option.Type);
Assert.AreEqual("somename", option.Name);
Assert.AreEqual("ABCDEF", option.StringValue);
Assert.Throws(typeof(InvalidOperationException), () => { var s = option.IntValue; });
}
[Test]
public void ConstructorPreconditions()
{
Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, "abc"); });
Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, 1); });
Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption("abc", null); });
}
[Test]
public void CreateChannelArgsNull()
{
var channelArgs = ChannelOptions.CreateChannelArgs(null);
Assert.IsTrue(channelArgs.IsInvalid);
}
[Test]
public void CreateChannelArgsEmpty()
{
var options = new List<ChannelOption>();
var channelArgs = ChannelOptions.CreateChannelArgs(options);
channelArgs.Dispose();
}
[Test]
public void CreateChannelArgs()
{
var options = new List<ChannelOption>
{
new ChannelOption("ABC", "XYZ"),
new ChannelOption("somename", "IJKLM"),
new ChannelOption("intoption", 12345),
new ChannelOption("GHIJK", 12345),
};
var channelArgs = ChannelOptions.CreateChannelArgs(options);
channelArgs.Dispose();
}
}
}

@ -3,8 +3,6 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{86EC5CB4-4EA2-40A2-8057-86542A0353BB}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Grpc.Core.Tests</RootNamespace>
@ -48,6 +46,8 @@
<Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
<Compile Include="Internal\CompletionQueueSafeHandleTest.cs" />
<Compile Include="Internal\CompletionQueueEventTest.cs" />
<Compile Include="Internal\ChannelArgsSafeHandleTest.cs" />
<Compile Include="ChannelOptionsTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -63,4 +63,4 @@
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup />
</Project>
</Project>

@ -0,0 +1,75 @@
#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 Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
{
public class ChannelArgsSafeHandleTest
{
[Test]
public void CreateEmptyAndDestroy()
{
var channelArgs = ChannelArgsSafeHandle.Create(0);
channelArgs.Dispose();
}
[Test]
public void CreateNonEmptyAndDestroy()
{
var channelArgs = ChannelArgsSafeHandle.Create(5);
channelArgs.Dispose();
}
[Test]
public void CreateNullAndDestroy()
{
var channelArgs = ChannelArgsSafeHandle.CreateNull();
channelArgs.Dispose();
}
[Test]
public void CreateFillAndDestroy()
{
var channelArgs = ChannelArgsSafeHandle.Create(3);
channelArgs.SetInteger(0, "somekey", 12345);
channelArgs.SetString(1, "somekey", "abcdefghijkl");
channelArgs.SetString(2, "somekey", "XYZ");
channelArgs.Dispose();
}
}
}

@ -29,6 +29,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@ -50,10 +51,10 @@ namespace Grpc.Core
/// </summary>
/// <param name="host">The DNS name of IP address of the host.</param>
/// <param name="credentials">Optional credentials to create a secure channel.</param>
/// <param name="channelArgs">Optional channel arguments.</param>
public Channel(string host, Credentials credentials = null, ChannelArgs channelArgs = null)
/// <param name="options">Channel options.</param>
public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
{
using (ChannelArgsSafeHandle nativeChannelArgs = CreateNativeChannelArgs(channelArgs))
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options))
{
if (credentials != null)
{
@ -67,7 +68,7 @@ namespace Grpc.Core
this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs);
}
}
this.target = GetOverridenTarget(host, channelArgs);
this.target = GetOverridenTarget(host, options);
}
/// <summary>
@ -76,9 +77,9 @@ namespace Grpc.Core
/// <param name="host">DNS name or IP address</param>
/// <param name="port">the port</param>
/// <param name="credentials">Optional credentials to create a secure channel.</param>
/// <param name="channelArgs">Optional channel arguments.</param>
public Channel(string host, int port, Credentials credentials = null, ChannelArgs channelArgs = null) :
this(string.Format("{0}:{1}", host, port), credentials, channelArgs)
/// <param name="options">Channel options.</param>
public Channel(string host, int port, Credentials credentials = null, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}
@ -112,22 +113,25 @@ namespace Grpc.Core
}
}
private static string GetOverridenTarget(string target, ChannelArgs args)
/// <summary>
/// Look for SslTargetNameOverride option and return its value instead of originalTarget
/// if found.
/// </summary>
private static string GetOverridenTarget(string originalTarget, IEnumerable<ChannelOption> options)
{
if (args != null && !string.IsNullOrEmpty(args.GetSslTargetNameOverride()))
if (options == null)
{
return args.GetSslTargetNameOverride();
return originalTarget;
}
return target;
}
private static ChannelArgsSafeHandle CreateNativeChannelArgs(ChannelArgs args)
{
if (args == null)
foreach (var option in options)
{
return ChannelArgsSafeHandle.CreateNull();
if (option.Type == ChannelOption.OptionType.String
&& option.Name == ChannelOptions.SslTargetNameOverride)
{
return option.StringValue;
}
}
return args.ToNativeChannelArgs();
return originalTarget;
}
}
}

@ -1,115 +0,0 @@
#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.Collections.Immutable;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
namespace Grpc.Core
{
/// <summary>
/// gRPC channel options.
/// </summary>
public class ChannelArgs
{
public const string SslTargetNameOverrideKey = "grpc.ssl_target_name_override";
readonly ImmutableDictionary<string, string> stringArgs;
private ChannelArgs(ImmutableDictionary<string, string> stringArgs)
{
this.stringArgs = stringArgs;
}
public string GetSslTargetNameOverride()
{
string result;
if (stringArgs.TryGetValue(SslTargetNameOverrideKey, out result))
{
return result;
}
return null;
}
public static Builder CreateBuilder()
{
return new Builder();
}
public class Builder
{
readonly Dictionary<string, string> stringArgs = new Dictionary<string, string>();
// TODO: AddInteger not supported yet.
public Builder AddString(string key, string value)
{
stringArgs.Add(key, value);
return this;
}
public ChannelArgs Build()
{
return new ChannelArgs(stringArgs.ToImmutableDictionary());
}
}
/// <summary>
/// Creates native object for the channel arguments.
/// </summary>
/// <returns>The native channel arguments.</returns>
internal ChannelArgsSafeHandle ToNativeChannelArgs()
{
ChannelArgsSafeHandle nativeArgs = null;
try
{
nativeArgs = ChannelArgsSafeHandle.Create(stringArgs.Count);
int i = 0;
foreach (var entry in stringArgs)
{
nativeArgs.SetString(i, entry.Key, entry.Value);
i++;
}
return nativeArgs;
}
catch (Exception)
{
if (nativeArgs != null)
{
nativeArgs.Dispose();
}
throw;
}
}
}
}

@ -0,0 +1,178 @@
#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.Collections.Immutable;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Channel option specified when creating a channel.
/// Corresponds to grpc_channel_args from grpc/grpc.h.
/// </summary>
public sealed class ChannelOption
{
public enum OptionType
{
Integer,
String
}
private readonly OptionType type;
private readonly string name;
private readonly int intValue;
private readonly string stringValue;
/// <summary>
/// Creates a channel option with a string value.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="stringValue">String value.</param>
public ChannelOption(string name, string stringValue)
{
this.type = OptionType.String;
this.name = Preconditions.CheckNotNull(name);
this.stringValue = Preconditions.CheckNotNull(stringValue);
}
/// <summary>
/// Creates a channel option with an integer value.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="stringValue">String value.</param>
public ChannelOption(string name, int intValue)
{
this.type = OptionType.Integer;
this.name = Preconditions.CheckNotNull(name);
this.intValue = intValue;
}
public OptionType Type
{
get
{
return type;
}
}
public string Name
{
get
{
return name;
}
}
public int IntValue
{
get
{
Preconditions.CheckState(type == OptionType.Integer);
return intValue;
}
}
public string StringValue
{
get
{
Preconditions.CheckState(type == OptionType.String);
return stringValue;
}
}
}
public static class ChannelOptions
{
// Override SSL target check. Only to be used for testing.
public const string SslTargetNameOverride = "grpc.ssl_target_name_override";
// Enable census for tracing and stats collection
public const string Census = "grpc.census";
// Maximum number of concurrent incoming streams to allow on a http2 connection
public const string MaxConcurrentStreams = "grpc.max_concurrent_streams";
// Maximum message length that the channel can receive
public const string MaxMessageLength = "grpc.max_message_length";
// Initial sequence number for http2 transports
public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number";
/// <summary>
/// Creates native object for a collection of channel options.
/// </summary>
/// <returns>The native channel arguments.</returns>
internal static ChannelArgsSafeHandle CreateChannelArgs(IEnumerable<ChannelOption> options)
{
if (options == null)
{
return ChannelArgsSafeHandle.CreateNull();
}
var optionList = new List<ChannelOption>(options); // It's better to do defensive copy
ChannelArgsSafeHandle nativeArgs = null;
try
{
nativeArgs = ChannelArgsSafeHandle.Create(optionList.Count);
for (int i = 0; i < optionList.Count; i++)
{
var option = optionList[i];
if (option.Type == ChannelOption.OptionType.Integer)
{
nativeArgs.SetInteger(i, option.Name, option.IntValue);
}
else if (option.Type == ChannelOption.OptionType.String)
{
nativeArgs.SetString(i, option.Name, option.StringValue);
}
else
{
throw new InvalidOperationException("Unknown option type");
}
}
return nativeArgs;
}
catch (Exception)
{
if (nativeArgs != null)
{
nativeArgs.Dispose();
}
throw;
}
}
}
}

@ -5,8 +5,6 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Grpc.Core</RootNamespace>
@ -78,7 +76,6 @@
<Compile Include="Internal\CredentialsSafeHandle.cs" />
<Compile Include="Credentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
<Compile Include="ChannelArgs.cs" />
<Compile Include="Internal\AsyncCompletion.cs" />
<Compile Include="Internal\AsyncCallBase.cs" />
<Compile Include="Internal\AsyncCallServer.cs" />
@ -103,6 +100,7 @@
<Compile Include="Internal\CompletionQueueEvent.cs" />
<Compile Include="Internal\CompletionRegistry.cs" />
<Compile Include="Internal\BatchContextSafeHandle.cs" />
<Compile Include="ChannelOptions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@ -132,4 +130,4 @@
</Target>
<Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
<Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
</Project>
</Project>

@ -45,6 +45,9 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
static extern void grpcsharp_channel_args_set_string(ChannelArgsSafeHandle args, UIntPtr index, string key, string value);
[DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
static extern void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_channel_args_destroy(IntPtr args);
@ -67,6 +70,11 @@ namespace Grpc.Core.Internal
grpcsharp_channel_args_set_string(this, new UIntPtr((uint)index), key, value);
}
public void SetInteger(int index, string key, int value)
{
grpcsharp_channel_args_set_integer(this, new UIntPtr((uint)index), key, value);
}
protected override bool ReleaseHandle()
{
grpcsharp_channel_args_destroy(handle);

@ -45,7 +45,7 @@ namespace Grpc.Core.Internal
internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid
{
[DllImport("grpc_csharp_ext.dll")]
static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args);
static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args);
[DllImport("grpc_csharp_ext.dll")]
static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
@ -72,7 +72,7 @@ namespace Grpc.Core.Internal
{
}
public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, IntPtr args)
public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args)
{
return grpcsharp_server_create(cq, args);
}

@ -52,9 +52,6 @@ namespace Grpc.Core
/// </summary>
public const int PickUnusedPort = 0;
//readonly OpCompletionDelegate serverShutdownHandler;
//readonly OpCompletionDelegate newServerRpcHandler;
readonly ServerSafeHandle handle;
readonly object myLock = new object();
@ -64,11 +61,16 @@ namespace Grpc.Core
bool startRequested;
bool shutdownRequested;
public Server()
/// <summary>
/// Create a new server.
/// </summary>
/// <param name="options">Channel options.</param>
public Server(IEnumerable<ChannelOption> options = null)
{
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero);
//this.newServerRpcHandler = HandleNewServerRpc;
//this.serverShutdownHandler = HandleServerShutdown;
using (var channelArgs = ChannelOptions.CreateChannelArgs(options))
{
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), channelArgs);
}
}
/// <summary>
@ -141,8 +143,6 @@ namespace Grpc.Core
Preconditions.CheckState(!shutdownRequested);
shutdownRequested = true;
}
var ctx = BatchContextSafeHandle.Create();
handle.ShutdownAndNotify(HandleServerShutdown);
await shutdownTcs.Task;
handle.Dispose();

@ -110,14 +110,16 @@ namespace Grpc.IntegrationTesting
credentials = TestCredentials.CreateTestClientCredentials(options.useTestCa);
}
ChannelArgs channelArgs = null;
List<ChannelOption> channelOptions = null;
if (!string.IsNullOrEmpty(options.serverHostOverride))
{
channelArgs = ChannelArgs.CreateBuilder()
.AddString(ChannelArgs.SslTargetNameOverrideKey, options.serverHostOverride).Build();
channelOptions = new List<ChannelOption>
{
new ChannelOption(ChannelOptions.SslTargetNameOverride, options.serverHostOverride)
};
}
using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelArgs))
using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions))
{
var stubConfig = StubConfiguration.Default;
if (options.testCase == "service_account_creds" || options.testCase == "compute_engine_creds")

@ -62,10 +62,11 @@ namespace Grpc.IntegrationTesting
int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
server.Start();
var channelArgs = ChannelArgs.CreateBuilder()
.AddString(ChannelArgs.SslTargetNameOverrideKey, TestCredentials.DefaultHostOverride).Build();
channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), channelArgs);
var options = new List<ChannelOption>
{
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
};
channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), options);
client = TestService.NewStub(channel);
}

@ -354,6 +354,16 @@ grpcsharp_channel_args_set_string(grpc_channel_args *args, size_t index,
args->args[index].value.string = gpr_strdup(value);
}
GPR_EXPORT void GPR_CALLTYPE
grpcsharp_channel_args_set_integer(grpc_channel_args *args, size_t index,
const char *key, int value) {
GPR_ASSERT(args);
GPR_ASSERT(index < args->num_args);
args->args[index].type = GRPC_ARG_INTEGER;
args->args[index].key = gpr_strdup(key);
args->args[index].value.integer = value;
}
GPR_EXPORT void GPR_CALLTYPE
grpcsharp_channel_args_destroy(grpc_channel_args *args) {
size_t i;

@ -7,51 +7,122 @@ This directory contains source code for PHP implementation of gRPC layered on sh
Pre-Alpha : This gRPC PHP implementation is work-in-progress and is not expected to work yet.
## LAYOUT
Directory structure is as generated by the PHP utility
[ext_skel](http://php.net/manual/en/internals2.buildsys.skeleton.php)
## ENVIRONMENT
Install `php5` and `php5-dev`.
To run the tests, additionally install `php5-readline` and `phpunit`.
To run the tests, additionally install `phpunit`.
Alternatively, build and install PHP 5.5 or later from source with standard
configuration options.
To also download and install protoc and the PHP code generator.
## Build from Homebrew
On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to
install gRPC.
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s php
```
This will download and run the [gRPC install script][] and compile the gRPC PHP extension.
## Build from Source
Clone this repository
```
$ git clone https://github.com/grpc/grpc.git
```
Build and install the Protocol Buffers compiler (protoc)
```
$ cd grpc
$ git pull --recurse-submodules && git submodule update --init --recursive
$ cd third_party/protobuf
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install
```
Build and install the gRPC C core
```sh
$ cd grpc
$ make
$ sudo make install
```
Build the gRPC PHP extension
```bash
apt-get install -y procps
curl -sSL https://get.rvm.io | sudo bash -s stable --ruby
git clone git@github.com:google/protobuf.git
cd protobuf
./configure
make
make install
git clone git@github.com:murgatroid99/Protobuf-PHP.git
cd Protobuf-PHP
rake pear:package version=1.0
pear install Protobuf-1.0.tgz
```sh
$ cd grpc/src/php/ext/grpc
$ phpize
$ ./configure
$ make
$ sudo make install
```
## BUILDING
In your php.ini file, add the line `extension=grpc.so` to load the extension
at PHP startup.
1. In ./ext/grpc, run the command `phpize` (distributed with PHP)
2. Run `./ext/grpc/configure`
3. In ./ext/grpc, run `make` and `sudo make install`
4. In your php.ini file, add the line `extension=grpc.so` to load the
extension at PHP startup.
Install Composer
## PHPUnit
```sh
$ cd grpc/src/php
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar install
```
## Unit Tests
Run unit tests
```sh
$ cd grpc/src/php
$ ./bin/run_tests.sh
```
## Generated Code Tests
Install `protoc-gen-php`
```sh
$ cd grpc/src/php/vendor/datto/protobuf-php
$ gem install rake ronn
$ rake pear:package version=1.0
$ sudo pear install Protobuf-1.0.tgz
```
Generate client stub code
```sh
$ cd grpc/src/php
$ ./bin/generate_proto_php.sh
```
Run a local server serving the math services
- Please see [Node][] on how to run an example server
```sh
$ cd grpc/src/node
$ npm install
$ nodejs examples/math_server.js
```
Run the generated code tests
```sh
$ cd grpc/src/php
$ ./bin/run_gen_code_test.sh
```
This repo now has PHPUnit tests, which can by run by executing
`./bin/run_tests.sh` after building.
[homebrew]:http://brew.sh
[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Node]:https://github.com/grpc/grpc/tree/master/src/node/examples
There is also a generated code test (`./bin/run_gen_code_test.sh`), which tests
the stub `./tests/generated_code/math.php` against a running localhost server
serving the math service. That stub is generated from
`./tests/generated_code/math.proto`.

@ -30,8 +30,8 @@
cd $(dirname $0)
GRPC_TEST_HOST=localhost:50051 php -d extension_dir=../ext/grpc/modules/ \
-d extension=grpc.so /usr/local/bin/phpunit -v --debug --strict \
-d extension=grpc.so `which phpunit` -v --debug --strict \
../tests/generated_code/GeneratedCodeTest.php
GRPC_TEST_HOST=localhost:50051 php -d extension_dir=../ext/grpc/modules/ \
-d extension=grpc.so /usr/local/bin/phpunit -v --debug --strict \
-d extension=grpc.so `which phpunit` -v --debug --strict \
../tests/generated_code/GeneratedCodeWithCallbackTest.php

@ -4,8 +4,15 @@
"version": "0.5.0",
"homepage": "http://grpc.io",
"license": "BSD-3-Clause",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/stanley-cheung/Protobuf-PHP"
}
],
"require": {
"php": ">=5.5.0",
"datto/protobuf-php": "dev-master",
"google/auth": "dev-master"
},
"autoload": {

@ -32,8 +32,6 @@
*
*/
require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php');
require 'DrSlump/Protobuf.php';
\DrSlump\Protobuf::autoload();
require 'math.php';
abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
/* These tests require that a server exporting the math service must be

@ -32,8 +32,6 @@
*
*/
require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php');
require 'DrSlump/Protobuf.php';
\DrSlump\Protobuf::autoload();
require 'empty.php';
require 'message_set.php';
require 'messages.php';

@ -40,6 +40,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#include <grpc/support/string_util.h>
#include "grpc/_adapter/_c/types.h"
@ -156,9 +157,10 @@ int pygrpc_produce_op(PyObject *op, grpc_op *result) {
return 0;
}
if (PyTuple_Size(op) != OP_TUPLE_SIZE) {
char buf[64];
snprintf(buf, sizeof(buf), "expected tuple op of length %d", OP_TUPLE_SIZE);
char *buf;
gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE);
PyErr_SetString(PyExc_ValueError, buf);
gpr_free(buf);
return 0;
}
type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX));
@ -353,9 +355,14 @@ double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) {
return timespec.tv_sec + 1e-9*timespec.tv_nsec;
}
/* Because C89 doesn't have a way to check for infinity... */
static int pygrpc_isinf(double x) {
return x * 0 != 0;
}
gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) {
gpr_timespec result;
if isinf(seconds) {
if (pygrpc_isinf(seconds)) {
result = seconds > 0.0 ? gpr_inf_future : gpr_inf_past;
} else {
result.tv_sec = (time_t)seconds;

@ -36,6 +36,7 @@ import shutil
import subprocess
import sys
import tempfile
import threading
import time
import unittest
@ -49,13 +50,13 @@ STUB_IDENTIFIER = 'EarlyAdopterTestServiceStub'
SERVER_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_server'
STUB_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_stub'
# Timeouts and delays.
SHORT_TIMEOUT = 0.1
NORMAL_TIMEOUT = 1
LONG_TIMEOUT = 2
DOES_NOT_MATTER_DELAY = 0
# The timeout used in tests of RPCs that are supposed to expire.
SHORT_TIMEOUT = 2
# The timeout used in tests of RPCs that are not supposed to expire. The
# absurdly large value doesn't matter since no passing execution of this test
# module will ever wait the duration.
LONG_TIMEOUT = 600
NO_DELAY = 0
LONG_DELAY = 1
# Build mode environment variable set by tools/run_tests/run_tests.py.
_build_mode = os.environ['CONFIG']
@ -64,29 +65,36 @@ _build_mode = os.environ['CONFIG']
class _ServicerMethods(object):
def __init__(self, test_pb2, delay):
self._condition = threading.Condition()
self._delay = delay
self._paused = False
self._failed = False
self._fail = False
self._test_pb2 = test_pb2
self._delay = delay
@contextlib.contextmanager
def pause(self): # pylint: disable=invalid-name
self._paused = True
with self._condition:
self._paused = True
yield
self._paused = False
with self._condition:
self._paused = False
self._condition.notify_all()
@contextlib.contextmanager
def fail(self): # pylint: disable=invalid-name
self._failed = True
with self._condition:
self._fail = True
yield
self._failed = False
with self._condition:
self._fail = False
def _control(self): # pylint: disable=invalid-name
if self._failed:
raise ValueError()
with self._condition:
if self._fail:
raise ValueError()
while self._paused:
self._condition.wait()
time.sleep(self._delay)
while self._paused:
time.sleep(0)
def UnaryCall(self, request, unused_rpc_context):
response = self._test_pb2.SimpleResponse()
@ -147,9 +155,8 @@ def _CreateService(test_pb2, delay):
waiting for the service.
Args:
test_pb2: the test_pb2 module generated by this test
delay: delay in seconds per response from the servicer
timeout: how long the stub will wait for the servicer by default.
test_pb2: The test_pb2 module generated by this test.
delay: Delay in seconds per response from the servicer.
Yields:
A (servicer_methods, servicer, stub) three-tuple where servicer_methods is
@ -250,7 +257,7 @@ class PythonPluginTest(unittest.TestCase):
if exc.errno != errno.ENOENT:
raise
# TODO(atash): Figure out which of theses tests is hanging flakily with small
# TODO(atash): Figure out which of these tests is hanging flakily with small
# probability.
def testImportAttributes(self):
@ -265,34 +272,33 @@ class PythonPluginTest(unittest.TestCase):
def testUpDown(self):
import test_pb2
with _CreateService(
test_pb2, DOES_NOT_MATTER_DELAY) as (servicer, stub, unused_server):
test_pb2, NO_DELAY) as (servicer, stub, unused_server):
request = test_pb2.SimpleRequest(response_size=13)
def testUnaryCall(self):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods.
request = test_pb2.SimpleRequest(response_size=13)
response = stub.UnaryCall(request, NORMAL_TIMEOUT)
response = stub.UnaryCall(request, timeout)
expected_response = methods.UnaryCall(request, 'not a real RpcContext!')
self.assertEqual(expected_response, response)
def testUnaryCallAsync(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = test_pb2.SimpleRequest(response_size=13)
with _CreateService(test_pb2, LONG_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
start_time = time.clock()
response_future = stub.UnaryCall.async(request, LONG_TIMEOUT)
# Check that we didn't block on the asynchronous call.
self.assertGreater(LONG_DELAY, time.clock() - start_time)
# Check that the call does not block waiting for the server to respond.
with methods.pause():
response_future = stub.UnaryCall.async(request, LONG_TIMEOUT)
response = response_future.result()
expected_response = methods.UnaryCall(request, 'not a real RpcContext!')
self.assertEqual(expected_response, response)
def testUnaryCallAsyncExpired(self):
import test_pb2 # pylint: disable=g-import-not-at-top
# set the timeout super low...
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
request = test_pb2.SimpleRequest(response_size=13)
with methods.pause():
@ -305,7 +311,7 @@ class PythonPluginTest(unittest.TestCase):
def testUnaryCallAsyncCancelled(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = test_pb2.SimpleRequest(response_size=13)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.pause():
response_future = stub.UnaryCall.async(request, 1)
@ -315,17 +321,17 @@ class PythonPluginTest(unittest.TestCase):
def testUnaryCallAsyncFailed(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = test_pb2.SimpleRequest(response_size=13)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.fail():
response_future = stub.UnaryCall.async(request, NORMAL_TIMEOUT)
response_future = stub.UnaryCall.async(request, LONG_TIMEOUT)
self.assertIsNotNone(response_future.exception())
def testStreamingOutputCall(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
responses = stub.StreamingOutputCall(request, NORMAL_TIMEOUT)
responses = stub.StreamingOutputCall(request, LONG_TIMEOUT)
expected_responses = methods.StreamingOutputCall(
request, 'not a real RpcContext!')
for expected_response, response in itertools.izip_longest(
@ -337,7 +343,7 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingOutputCallExpired(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.pause():
responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT)
@ -349,7 +355,7 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingOutputCallCancelled(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
unused_methods, stub, unused_server):
responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT)
next(responses)
@ -362,7 +368,7 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingOutputCallFailed(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.fail():
responses = stub.StreamingOutputCall(request, 1)
@ -375,20 +381,19 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingInputCall(self):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
response = stub.StreamingInputCall(StreamingInputRequest(test_pb2),
NORMAL_TIMEOUT)
response = stub.StreamingInputCall(
_streaming_input_request_iterator(test_pb2), LONG_TIMEOUT)
expected_response = methods.StreamingInputCall(
_streaming_input_request_iterator(test_pb2), 'not a real RpcContext!')
self.assertEqual(expected_response, response)
def testStreamingInputCallAsync(self):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, LONG_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
start_time = time.clock()
response_future = stub.StreamingInputCall.async(
_streaming_input_request_iterator(test_pb2), LONG_TIMEOUT)
self.assertGreater(LONG_DELAY, time.clock() - start_time)
with methods.pause():
response_future = stub.StreamingInputCall.async(
_streaming_input_request_iterator(test_pb2), LONG_TIMEOUT)
response = response_future.result()
expected_response = methods.StreamingInputCall(
_streaming_input_request_iterator(test_pb2), 'not a real RpcContext!')
@ -396,8 +401,7 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingInputCallAsyncExpired(self):
import test_pb2 # pylint: disable=g-import-not-at-top
# set the timeout super low...
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.pause():
response_future = stub.StreamingInputCall.async(
@ -409,11 +413,12 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingInputCallAsyncCancelled(self):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.pause():
timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods.
response_future = stub.StreamingInputCall.async(
_streaming_input_request_iterator(test_pb2), NORMAL_TIMEOUT)
_streaming_input_request_iterator(test_pb2), timeout)
response_future.cancel()
self.assertTrue(response_future.cancelled())
with self.assertRaises(future.CancelledError):
@ -421,7 +426,7 @@ class PythonPluginTest(unittest.TestCase):
def testStreamingInputCallAsyncFailed(self):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.fail():
response_future = stub.StreamingInputCall.async(
@ -432,7 +437,7 @@ class PythonPluginTest(unittest.TestCase):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
responses = stub.FullDuplexCall(
_full_duplex_request_iterator(test_pb2), NORMAL_TIMEOUT)
_full_duplex_request_iterator(test_pb2), LONG_TIMEOUT)
expected_responses = methods.FullDuplexCall(
_full_duplex_request_iterator(test_pb2), 'not a real RpcContext!')
for expected_response, response in itertools.izip_longest(
@ -444,7 +449,7 @@ class PythonPluginTest(unittest.TestCase):
def testFullDuplexCallExpired(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request_iterator = _full_duplex_request_iterator(test_pb2)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.pause():
responses = stub.FullDuplexCall(request_iterator, SHORT_TIMEOUT)
@ -457,7 +462,7 @@ class PythonPluginTest(unittest.TestCase):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
request_iterator = _full_duplex_request_iterator(test_pb2)
responses = stub.FullDuplexCall(request_iterator, NORMAL_TIMEOUT)
responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT)
next(responses)
responses.cancel()
with self.assertRaises(future.CancelledError):
@ -468,10 +473,10 @@ class PythonPluginTest(unittest.TestCase):
def testFullDuplexCallFailed(self):
import test_pb2 # pylint: disable=g-import-not-at-top
request_iterator = _full_duplex_request_iterator(test_pb2)
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
with methods.fail():
responses = stub.FullDuplexCall(request_iterator, NORMAL_TIMEOUT)
responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT)
self.assertIsNotNone(responses)
with self.assertRaises(exceptions.ServicerError):
next(responses)
@ -480,7 +485,7 @@ class PythonPluginTest(unittest.TestCase):
'forever and fix.')
def testHalfDuplexCall(self):
import test_pb2 # pylint: disable=g-import-not-at-top
with _CreateService(test_pb2, DOES_NOT_MATTER_DELAY) as (
with _CreateService(test_pb2, NO_DELAY) as (
methods, stub, unused_server):
def half_duplex_request_iterator():
request = test_pb2.StreamingOutputCallRequest()
@ -491,32 +496,37 @@ class PythonPluginTest(unittest.TestCase):
request.response_parameters.add(size=3, interval_us=0)
yield request
responses = stub.HalfDuplexCall(
half_duplex_request_iterator(), NORMAL_TIMEOUT)
half_duplex_request_iterator(), LONG_TIMEOUT)
expected_responses = methods.HalfDuplexCall(
HalfDuplexRequest(), 'not a real RpcContext!')
half_duplex_request_iterator(), 'not a real RpcContext!')
for check in itertools.izip_longest(expected_responses, responses):
expected_response, response = check
self.assertEqual(expected_response, response)
def testHalfDuplexCallWedged(self):
import test_pb2 # pylint: disable=g-import-not-at-top
condition = threading.Condition()
wait_cell = [False]
@contextlib.contextmanager
def wait(): # pylint: disable=invalid-name
# Where's Python 3's 'nonlocal' statement when you need it?
wait_cell[0] = True
with condition:
wait_cell[0] = True
yield
wait_cell[0] = False
with condition:
wait_cell[0] = False
condition.notify_all()
def half_duplex_request_iterator():
request = test_pb2.StreamingOutputCallRequest()
request.response_parameters.add(size=1, interval_us=0)
yield request
while wait_cell[0]:
time.sleep(0.1)
with condition:
while wait_cell[0]:
condition.wait()
with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
with wait():
responses = stub.HalfDuplexCall(
half_duplex_request_iterator(), NORMAL_TIMEOUT)
half_duplex_request_iterator(), SHORT_TIMEOUT)
# half-duplex waits for the client to send all info
with self.assertRaises(exceptions.ExpirationError):
next(responses)

@ -38,5 +38,5 @@ rm -rf python2.7_virtual_environment
virtualenv -p /usr/bin/python2.7 python2.7_virtual_environment
source python2.7_virtual_environment/bin/activate
pip install -r src/python/requirements.txt
CFLAGS=-I$root/include LDFLAGS=-L$root/libs/$CONFIG pip install src/python/src
CFLAGS="-I$root/include -std=c89" LDFLAGS=-L$root/libs/$CONFIG pip install src/python/src
pip install src/python/interop

@ -223,6 +223,7 @@ class Jobset(object):
self._travis = travis
self._cache = cache
self._stop_on_failure = stop_on_failure
self._hashes = {}
def start(self, spec):
"""Start a job. Return True on success, False on failure."""
@ -231,11 +232,15 @@ class Jobset(object):
self.reap()
if self.cancelled(): return False
if spec.hash_targets:
bin_hash = hashlib.sha1()
for fn in spec.hash_targets:
with open(which(fn)) as f:
bin_hash.update(f.read())
bin_hash = bin_hash.hexdigest()
if spec.identity() in self._hashes:
bin_hash = self._hashes[spec.identity()]
else:
bin_hash = hashlib.sha1()
for fn in spec.hash_targets:
with open(which(fn)) as f:
bin_hash.update(f.read())
bin_hash = bin_hash.hexdigest()
self._hashes[spec.identity()] = bin_hash
should_run = self._cache.should_run(spec.identity(), bin_hash)
else:
bin_hash = None
@ -266,6 +271,7 @@ class Jobset(object):
for job in self._running:
job.kill()
dead.add(job)
break
for job in dead:
self._completed += 1
self._running.remove(job)

@ -313,7 +313,7 @@ _CONFIGS = {
'dbg': SimpleConfig('dbg'),
'opt': SimpleConfig('opt'),
'tsan': SimpleConfig('tsan', environ={
'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt'}),
'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1'}),
'msan': SimpleConfig('msan'),
'ubsan': SimpleConfig('ubsan'),
'asan': SimpleConfig('asan', environ={
@ -449,6 +449,7 @@ class TestCache(object):
def __init__(self, use_cache_results):
self._last_successful_run = {}
self._use_cache_results = use_cache_results
self._last_save = time.time()
def should_run(self, cmdline, bin_hash):
if cmdline not in self._last_successful_run:
@ -461,7 +462,8 @@ class TestCache(object):
def finished(self, cmdline, bin_hash):
self._last_successful_run[cmdline] = bin_hash
self.save()
if time.time() - self._last_save > 1:
self.save()
def dump(self):
return [{'cmdline': k, 'hash': v}
@ -473,6 +475,7 @@ class TestCache(object):
def save(self):
with open('.run_tests_cache', 'w') as f:
f.write(json.dumps(self.dump()))
self._last_save = time.time()
def maybe_load(self):
if os.path.exists('.run_tests_cache'):
@ -515,6 +518,8 @@ def _build_and_run(check_cancelled, newline_on_success, travis, cache):
for antagonist in antagonists:
antagonist.kill()
if cache: cache.save()
return 0

Loading…
Cancel
Save