mirror of https://github.com/grpc/grpc.git
commit
5d4d1ee34e
226 changed files with 6934 additions and 2267 deletions
@ -0,0 +1,392 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCXX_SUPPORT_SYNC_STREAM_H |
||||
#define GRPCXX_SUPPORT_SYNC_STREAM_H |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include <grpc++/channel.h> |
||||
#include <grpc++/client_context.h> |
||||
#include <grpc++/completion_queue.h> |
||||
#include <grpc++/impl/call.h> |
||||
#include <grpc++/impl/service_type.h> |
||||
#include <grpc++/server_context.h> |
||||
#include <grpc++/support/status.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
// Common interface for all client side streaming.
|
||||
class ClientStreamingInterface { |
||||
public: |
||||
virtual ~ClientStreamingInterface() {} |
||||
|
||||
// Wait until the stream finishes, and return the final status. When the
|
||||
// client side declares it has no more message to send, either implicitly or
|
||||
// by calling WritesDone, it needs to make sure there is no more message to
|
||||
// be received from the server, either implicitly or by getting a false from
|
||||
// a Read().
|
||||
// This function will return either:
|
||||
// - when all incoming messages have been read and the server has returned
|
||||
// status
|
||||
// - OR when the server has returned a non-OK status
|
||||
virtual Status Finish() = 0; |
||||
}; |
||||
|
||||
// An interface that yields a sequence of R messages.
|
||||
template <class R> |
||||
class ReaderInterface { |
||||
public: |
||||
virtual ~ReaderInterface() {} |
||||
|
||||
// Blocking read a message and parse to msg. Returns true on success.
|
||||
// The method returns false when there will be no more incoming messages,
|
||||
// either because the other side has called WritesDone or the stream has
|
||||
// failed (or been cancelled).
|
||||
virtual bool Read(R* msg) = 0; |
||||
}; |
||||
|
||||
// An interface that can be fed a sequence of W messages.
|
||||
template <class W> |
||||
class WriterInterface { |
||||
public: |
||||
virtual ~WriterInterface() {} |
||||
|
||||
// Blocking write msg to the stream. Returns true on success.
|
||||
// Returns false when the stream has been closed.
|
||||
virtual bool Write(const W& msg, const WriteOptions& options) = 0; |
||||
|
||||
inline bool Write(const W& msg) { return Write(msg, WriteOptions()); } |
||||
}; |
||||
|
||||
template <class R> |
||||
class ClientReaderInterface : public ClientStreamingInterface, |
||||
public ReaderInterface<R> { |
||||
public: |
||||
virtual void WaitForInitialMetadata() = 0; |
||||
}; |
||||
|
||||
template <class R> |
||||
class ClientReader GRPC_FINAL : public ClientReaderInterface<R> { |
||||
public: |
||||
// Blocking create a stream and write the first request out.
|
||||
template <class W> |
||||
ClientReader(Channel* channel, const RpcMethod& method, |
||||
ClientContext* context, const W& request) |
||||
: context_(context), call_(channel->CreateCall(method, context, &cq_)) { |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, |
||||
CallOpClientSendClose> ops; |
||||
ops.SendInitialMetadata(context->send_initial_metadata_); |
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(ops.SendMessage(request).ok()); |
||||
ops.ClientSendClose(); |
||||
call_.PerformOps(&ops); |
||||
cq_.Pluck(&ops); |
||||
} |
||||
|
||||
// Blocking wait for initial metadata from server. The received metadata
|
||||
// can only be accessed after this call returns. Should only be called before
|
||||
// the first read. Calling this method is optional, and if it is not called
|
||||
// the metadata will be available in ClientContext after the first read.
|
||||
void WaitForInitialMetadata() { |
||||
GPR_ASSERT(!context_->initial_metadata_received_); |
||||
|
||||
CallOpSet<CallOpRecvInitialMetadata> ops; |
||||
ops.RecvInitialMetadata(context_); |
||||
call_.PerformOps(&ops); |
||||
cq_.Pluck(&ops); // status ignored
|
||||
} |
||||
|
||||
bool Read(R* msg) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops; |
||||
if (!context_->initial_metadata_received_) { |
||||
ops.RecvInitialMetadata(context_); |
||||
} |
||||
ops.RecvMessage(msg); |
||||
call_.PerformOps(&ops); |
||||
return cq_.Pluck(&ops) && ops.got_message; |
||||
} |
||||
|
||||
Status Finish() GRPC_OVERRIDE { |
||||
CallOpSet<CallOpClientRecvStatus> ops; |
||||
Status status; |
||||
ops.ClientRecvStatus(context_, &status); |
||||
call_.PerformOps(&ops); |
||||
GPR_ASSERT(cq_.Pluck(&ops)); |
||||
return status; |
||||
} |
||||
|
||||
private: |
||||
ClientContext* context_; |
||||
CompletionQueue cq_; |
||||
Call call_; |
||||
}; |
||||
|
||||
template <class W> |
||||
class ClientWriterInterface : public ClientStreamingInterface, |
||||
public WriterInterface<W> { |
||||
public: |
||||
virtual bool WritesDone() = 0; |
||||
}; |
||||
|
||||
template <class W> |
||||
class ClientWriter : public ClientWriterInterface<W> { |
||||
public: |
||||
// Blocking create a stream.
|
||||
template <class R> |
||||
ClientWriter(Channel* channel, const RpcMethod& method, |
||||
ClientContext* context, R* response) |
||||
: context_(context), call_(channel->CreateCall(method, context, &cq_)) { |
||||
finish_ops_.RecvMessage(response); |
||||
|
||||
CallOpSet<CallOpSendInitialMetadata> ops; |
||||
ops.SendInitialMetadata(context->send_initial_metadata_); |
||||
call_.PerformOps(&ops); |
||||
cq_.Pluck(&ops); |
||||
} |
||||
|
||||
using WriterInterface<W>::Write; |
||||
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpSendMessage> ops; |
||||
if (!ops.SendMessage(msg, options).ok()) { |
||||
return false; |
||||
} |
||||
call_.PerformOps(&ops); |
||||
return cq_.Pluck(&ops); |
||||
} |
||||
|
||||
bool WritesDone() GRPC_OVERRIDE { |
||||
CallOpSet<CallOpClientSendClose> ops; |
||||
ops.ClientSendClose(); |
||||
call_.PerformOps(&ops); |
||||
return cq_.Pluck(&ops); |
||||
} |
||||
|
||||
// Read the final response and wait for the final status.
|
||||
Status Finish() GRPC_OVERRIDE { |
||||
Status status; |
||||
finish_ops_.ClientRecvStatus(context_, &status); |
||||
call_.PerformOps(&finish_ops_); |
||||
GPR_ASSERT(cq_.Pluck(&finish_ops_)); |
||||
return status; |
||||
} |
||||
|
||||
private: |
||||
ClientContext* context_; |
||||
CallOpSet<CallOpGenericRecvMessage, CallOpClientRecvStatus> finish_ops_; |
||||
CompletionQueue cq_; |
||||
Call call_; |
||||
}; |
||||
|
||||
// Client-side interface for bi-directional streaming.
|
||||
template <class W, class R> |
||||
class ClientReaderWriterInterface : public ClientStreamingInterface, |
||||
public WriterInterface<W>, |
||||
public ReaderInterface<R> { |
||||
public: |
||||
virtual void WaitForInitialMetadata() = 0; |
||||
virtual bool WritesDone() = 0; |
||||
}; |
||||
|
||||
template <class W, class R> |
||||
class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> { |
||||
public: |
||||
// Blocking create a stream.
|
||||
ClientReaderWriter(Channel* channel, const RpcMethod& method, |
||||
ClientContext* context) |
||||
: context_(context), call_(channel->CreateCall(method, context, &cq_)) { |
||||
CallOpSet<CallOpSendInitialMetadata> ops; |
||||
ops.SendInitialMetadata(context->send_initial_metadata_); |
||||
call_.PerformOps(&ops); |
||||
cq_.Pluck(&ops); |
||||
} |
||||
|
||||
// Blocking wait for initial metadata from server. The received metadata
|
||||
// can only be accessed after this call returns. Should only be called before
|
||||
// the first read. Calling this method is optional, and if it is not called
|
||||
// the metadata will be available in ClientContext after the first read.
|
||||
void WaitForInitialMetadata() { |
||||
GPR_ASSERT(!context_->initial_metadata_received_); |
||||
|
||||
CallOpSet<CallOpRecvInitialMetadata> ops; |
||||
ops.RecvInitialMetadata(context_); |
||||
call_.PerformOps(&ops); |
||||
cq_.Pluck(&ops); // status ignored
|
||||
} |
||||
|
||||
bool Read(R* msg) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops; |
||||
if (!context_->initial_metadata_received_) { |
||||
ops.RecvInitialMetadata(context_); |
||||
} |
||||
ops.RecvMessage(msg); |
||||
call_.PerformOps(&ops); |
||||
return cq_.Pluck(&ops) && ops.got_message; |
||||
} |
||||
|
||||
using WriterInterface<W>::Write; |
||||
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpSendMessage> ops; |
||||
if (!ops.SendMessage(msg, options).ok()) return false; |
||||
call_.PerformOps(&ops); |
||||
return cq_.Pluck(&ops); |
||||
} |
||||
|
||||
bool WritesDone() GRPC_OVERRIDE { |
||||
CallOpSet<CallOpClientSendClose> ops; |
||||
ops.ClientSendClose(); |
||||
call_.PerformOps(&ops); |
||||
return cq_.Pluck(&ops); |
||||
} |
||||
|
||||
Status Finish() GRPC_OVERRIDE { |
||||
CallOpSet<CallOpClientRecvStatus> ops; |
||||
Status status; |
||||
ops.ClientRecvStatus(context_, &status); |
||||
call_.PerformOps(&ops); |
||||
GPR_ASSERT(cq_.Pluck(&ops)); |
||||
return status; |
||||
} |
||||
|
||||
private: |
||||
ClientContext* context_; |
||||
CompletionQueue cq_; |
||||
Call call_; |
||||
}; |
||||
|
||||
template <class R> |
||||
class ServerReader GRPC_FINAL : public ReaderInterface<R> { |
||||
public: |
||||
ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} |
||||
|
||||
void SendInitialMetadata() { |
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_); |
||||
|
||||
CallOpSet<CallOpSendInitialMetadata> ops; |
||||
ops.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
call_->PerformOps(&ops); |
||||
call_->cq()->Pluck(&ops); |
||||
} |
||||
|
||||
bool Read(R* msg) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpRecvMessage<R>> ops; |
||||
ops.RecvMessage(msg); |
||||
call_->PerformOps(&ops); |
||||
return call_->cq()->Pluck(&ops) && ops.got_message; |
||||
} |
||||
|
||||
private: |
||||
Call* const call_; |
||||
ServerContext* const ctx_; |
||||
}; |
||||
|
||||
template <class W> |
||||
class ServerWriter GRPC_FINAL : public WriterInterface<W> { |
||||
public: |
||||
ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} |
||||
|
||||
void SendInitialMetadata() { |
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_); |
||||
|
||||
CallOpSet<CallOpSendInitialMetadata> ops; |
||||
ops.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
call_->PerformOps(&ops); |
||||
call_->cq()->Pluck(&ops); |
||||
} |
||||
|
||||
using WriterInterface<W>::Write; |
||||
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops; |
||||
if (!ops.SendMessage(msg, options).ok()) { |
||||
return false; |
||||
} |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
ops.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
call_->PerformOps(&ops); |
||||
return call_->cq()->Pluck(&ops); |
||||
} |
||||
|
||||
private: |
||||
Call* const call_; |
||||
ServerContext* const ctx_; |
||||
}; |
||||
|
||||
// Server-side interface for bi-directional streaming.
|
||||
template <class W, class R> |
||||
class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>, |
||||
public ReaderInterface<R> { |
||||
public: |
||||
ServerReaderWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} |
||||
|
||||
void SendInitialMetadata() { |
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_); |
||||
|
||||
CallOpSet<CallOpSendInitialMetadata> ops; |
||||
ops.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
call_->PerformOps(&ops); |
||||
call_->cq()->Pluck(&ops); |
||||
} |
||||
|
||||
bool Read(R* msg) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpRecvMessage<R>> ops; |
||||
ops.RecvMessage(msg); |
||||
call_->PerformOps(&ops); |
||||
return call_->cq()->Pluck(&ops) && ops.got_message; |
||||
} |
||||
|
||||
using WriterInterface<W>::Write; |
||||
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE { |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops; |
||||
if (!ops.SendMessage(msg, options).ok()) { |
||||
return false; |
||||
} |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
ops.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
call_->PerformOps(&ops); |
||||
return call_->cq()->Pluck(&ops); |
||||
} |
||||
|
||||
private: |
||||
Call* const call_; |
||||
ServerContext* const ctx_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCXX_SUPPORT_SYNC_STREAM_H
|
@ -1,80 +0,0 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CPP_CLIENT_CHANNEL_H |
||||
#define GRPC_INTERNAL_CPP_CLIENT_CHANNEL_H |
||||
|
||||
#include <memory> |
||||
|
||||
#include <grpc++/channel_interface.h> |
||||
#include <grpc++/config.h> |
||||
#include <grpc++/impl/grpc_library.h> |
||||
|
||||
struct grpc_channel; |
||||
|
||||
namespace grpc { |
||||
class Call; |
||||
class CallOpSetInterface; |
||||
class ChannelArguments; |
||||
class CompletionQueue; |
||||
class Credentials; |
||||
class StreamContextInterface; |
||||
|
||||
class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface { |
||||
public: |
||||
explicit Channel(grpc_channel* c_channel); |
||||
Channel(const grpc::string& host, grpc_channel* c_channel); |
||||
~Channel() GRPC_OVERRIDE; |
||||
|
||||
void* RegisterMethod(const char* method) GRPC_OVERRIDE; |
||||
Call CreateCall(const RpcMethod& method, ClientContext* context, |
||||
CompletionQueue* cq) GRPC_OVERRIDE; |
||||
void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE; |
||||
|
||||
grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE; |
||||
|
||||
private: |
||||
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, |
||||
gpr_timespec deadline, CompletionQueue* cq, |
||||
void* tag) GRPC_OVERRIDE; |
||||
|
||||
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, |
||||
gpr_timespec deadline) GRPC_OVERRIDE; |
||||
|
||||
const grpc::string host_; |
||||
grpc_channel* const c_channel_; // owned
|
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_INTERNAL_CPP_CLIENT_CHANNEL_H
|
@ -0,0 +1,222 @@ |
||||
#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.Runtime.InteropServices; |
||||
using System.Threading.Tasks; |
||||
|
||||
using Grpc.Core.Internal; |
||||
using NUnit.Framework; |
||||
|
||||
namespace Grpc.Core.Internal.Tests |
||||
{ |
||||
public class AsyncCallTest |
||||
{ |
||||
Channel channel; |
||||
FakeNativeCall fakeCall; |
||||
AsyncCall<string, string> asyncCall; |
||||
|
||||
[SetUp] |
||||
public void Init() |
||||
{ |
||||
channel = new Channel("localhost", Credentials.Insecure); |
||||
|
||||
fakeCall = new FakeNativeCall(); |
||||
|
||||
var callDetails = new CallInvocationDetails<string, string>(channel, "someMethod", null, Marshallers.StringMarshaller, Marshallers.StringMarshaller, new CallOptions()); |
||||
asyncCall = new AsyncCall<string, string>(callDetails, fakeCall); |
||||
} |
||||
|
||||
[TearDown] |
||||
public void Cleanup() |
||||
{ |
||||
channel.ShutdownAsync().Wait(); |
||||
} |
||||
|
||||
[Test] |
||||
public void AsyncUnary_CompletionSuccess() |
||||
{ |
||||
var resultTask = asyncCall.UnaryCallAsync("abc"); |
||||
fakeCall.UnaryResponseClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()), new byte[] { 1, 2, 3 }, new Metadata()); |
||||
Assert.IsTrue(resultTask.IsCompleted); |
||||
Assert.IsTrue(fakeCall.IsDisposed); |
||||
Assert.AreEqual(Status.DefaultSuccess, asyncCall.GetStatus()); |
||||
} |
||||
|
||||
[Test] |
||||
public void AsyncUnary_CompletionFailure() |
||||
{ |
||||
var resultTask = asyncCall.UnaryCallAsync("abc"); |
||||
fakeCall.UnaryResponseClientHandler(false, new ClientSideStatus(new Status(StatusCode.Internal, ""), null), new byte[] { 1, 2, 3 }, new Metadata()); |
||||
|
||||
Assert.IsTrue(resultTask.IsCompleted); |
||||
Assert.IsTrue(fakeCall.IsDisposed); |
||||
|
||||
Assert.AreEqual(StatusCode.Internal, asyncCall.GetStatus().StatusCode); |
||||
Assert.IsNull(asyncCall.GetTrailers()); |
||||
var ex = Assert.Throws<RpcException>(() => resultTask.GetAwaiter().GetResult()); |
||||
Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); |
||||
} |
||||
|
||||
internal class FakeNativeCall : INativeCall |
||||
{ |
||||
public UnaryResponseClientHandler UnaryResponseClientHandler |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public ReceivedMessageHandler ReceivedMessageHandler |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public SendCompletionHandler SendCompletionHandler |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public bool IsCancelled |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public bool IsDisposed |
||||
{ |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public void Cancel() |
||||
{ |
||||
IsCancelled = true; |
||||
} |
||||
|
||||
public void CancelWithStatus(Status status) |
||||
{ |
||||
IsCancelled = true; |
||||
} |
||||
|
||||
public string GetPeer() |
||||
{ |
||||
return "PEER"; |
||||
} |
||||
|
||||
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) |
||||
{ |
||||
UnaryResponseClientHandler = callback; |
||||
} |
||||
|
||||
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray) |
||||
{ |
||||
UnaryResponseClientHandler = callback; |
||||
} |
||||
|
||||
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) |
||||
{ |
||||
ReceivedStatusOnClientHandler = callback; |
||||
} |
||||
|
||||
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray) |
||||
{ |
||||
ReceivedStatusOnClientHandler = callback; |
||||
} |
||||
|
||||
public void StartReceiveMessage(ReceivedMessageHandler callback) |
||||
{ |
||||
ReceivedMessageHandler = callback; |
||||
} |
||||
|
||||
public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback) |
||||
{ |
||||
ReceivedResponseHeadersHandler = callback; |
||||
} |
||||
|
||||
public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray) |
||||
{ |
||||
SendCompletionHandler = callback; |
||||
} |
||||
|
||||
public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata) |
||||
{ |
||||
SendCompletionHandler = callback; |
||||
} |
||||
|
||||
public void StartSendCloseFromClient(SendCompletionHandler callback) |
||||
{ |
||||
SendCompletionHandler = callback; |
||||
} |
||||
|
||||
public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata) |
||||
{ |
||||
SendCompletionHandler = callback; |
||||
} |
||||
|
||||
public void StartServerSide(ReceivedCloseOnServerHandler callback) |
||||
{ |
||||
ReceivedCloseOnServerHandler = callback; |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
IsDisposed = true; |
||||
} |
||||
} |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue