mirror of https://github.com/grpc/grpc-node.git
Extension module now compiles and some tests pass
This commit is contained in:
parent
3d35d387a1
commit
6f8dde55cc
|
@ -34,11 +34,9 @@
|
|||
"ext/channel.cc",
|
||||
"ext/completion_queue_async_worker.cc",
|
||||
"ext/credentials.cc",
|
||||
"ext/event.cc",
|
||||
"ext/node_grpc.cc",
|
||||
"ext/server.cc",
|
||||
"ext/server_credentials.cc",
|
||||
"ext/tag.cc",
|
||||
"ext/timeval.cc"
|
||||
],
|
||||
'conditions' : [
|
||||
|
|
107
ext/call.cc
107
ext/call.cc
|
@ -55,6 +55,7 @@ namespace node {
|
|||
using ::node::Buffer;
|
||||
using v8::Arguments;
|
||||
using v8::Array;
|
||||
using v8::Boolean;
|
||||
using v8::Exception;
|
||||
using v8::External;
|
||||
using v8::Function;
|
||||
|
@ -80,6 +81,7 @@ bool CreateMetadataArray(
|
|||
std::vector<unique_ptr<NanUtf8String> > *string_handles,
|
||||
std::vector<unique_ptr<PersistentHolder> > *handles) {
|
||||
NanScope();
|
||||
grpc_metadata_array_init(array);
|
||||
Handle<Array> keys(metadata->GetOwnPropertyNames());
|
||||
for (unsigned int i = 0; i < keys->Length(); i++) {
|
||||
Handle<String> current_key(keys->Get(i)->ToString());
|
||||
|
@ -156,12 +158,12 @@ Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
|
|||
|
||||
Handle<Value> Op::GetOpType() const {
|
||||
NanEscapableScope();
|
||||
return NanEscapeScope(NanNew(GetTypeString()));
|
||||
return NanEscapeScope(NanNew<String>(GetTypeString()));
|
||||
}
|
||||
|
||||
class SendMetadataOp : public Op {
|
||||
public:
|
||||
Handle<Value> GetNodeValue() {
|
||||
Handle<Value> GetNodeValue() const {
|
||||
NanEscapableScope();
|
||||
return NanEscapeScope(NanTrue());
|
||||
}
|
||||
|
@ -180,14 +182,14 @@ class SendMetadataOp : public Op {
|
|||
return true;
|
||||
}
|
||||
protected:
|
||||
std::string GetTypeString() {
|
||||
std::string GetTypeString() const {
|
||||
return "send metadata";
|
||||
}
|
||||
};
|
||||
|
||||
class SendMessageOp : public Op {
|
||||
public:
|
||||
Handle<Value> GetNodeValue() {
|
||||
Handle<Value> GetNodeValue() const {
|
||||
NanEscapableScope();
|
||||
return NanEscapeScope(NanTrue());
|
||||
}
|
||||
|
@ -197,20 +199,22 @@ class SendMessageOp : public Op {
|
|||
if (!Buffer::HasInstance(value)) {
|
||||
return false;
|
||||
}
|
||||
out->data.send_message = BufferToByteBuffer(obj->Get(type));
|
||||
out->data.send_message = BufferToByteBuffer(value);
|
||||
Persistent<Value> handle;
|
||||
NanAssignPersistent(handle, value);
|
||||
handles->push_back(unique_ptr<PersistentHolder>(
|
||||
new PersistentHolder(handle)));
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
std::string GetTypeString() {
|
||||
std::string GetTypeString() const {
|
||||
return "send message";
|
||||
}
|
||||
};
|
||||
|
||||
class SendClientCloseOp : public Op {
|
||||
public:
|
||||
Handle<Value> GetNodeValue() {
|
||||
Handle<Value> GetNodeValue() const {
|
||||
NanEscapableScope();
|
||||
return NanEscapeScope(NanTrue());
|
||||
}
|
||||
|
@ -220,14 +224,14 @@ class SendClientCloseOp : public Op {
|
|||
return true;
|
||||
}
|
||||
protected:
|
||||
std::string GetTypeString() {
|
||||
std::string GetTypeString() const {
|
||||
return "client close";
|
||||
}
|
||||
};
|
||||
|
||||
class SendServerStatusOp : public Op {
|
||||
public:
|
||||
Handle<Value> GetNodeValue() {
|
||||
Handle<Value> GetNodeValue() const {
|
||||
NanEscapableScope();
|
||||
return NanEscapeScope(NanTrue());
|
||||
}
|
||||
|
@ -265,10 +269,10 @@ class SendServerStatusOp : public Op {
|
|||
return true;
|
||||
}
|
||||
protected:
|
||||
std::string GetTypeString() {
|
||||
std::string GetTypeString() const {
|
||||
return "send status";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class GetMetadataOp : public Op {
|
||||
public:
|
||||
|
@ -289,10 +293,11 @@ class GetMetadataOp : public Op {
|
|||
std::vector<unique_ptr<NanUtf8String> > *strings,
|
||||
std::vector<unique_ptr<PersistentHolder> > *handles) {
|
||||
out->data.recv_initial_metadata = &recv_metadata;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string GetTypeString() {
|
||||
std::string GetTypeString() const {
|
||||
return "metadata";
|
||||
}
|
||||
|
||||
|
@ -323,7 +328,7 @@ class ReadMessageOp : public Op {
|
|||
}
|
||||
|
||||
protected:
|
||||
std::string GetTypeString() {
|
||||
std::string GetTypeString() const {
|
||||
return "read";
|
||||
}
|
||||
|
||||
|
@ -334,12 +339,13 @@ class ReadMessageOp : public Op {
|
|||
class ClientStatusOp : public Op {
|
||||
public:
|
||||
ClientStatusOp() {
|
||||
grpc_metadata_array_init(&metadata);
|
||||
grpc_metadata_array_init(&metadata_array);
|
||||
status_details = NULL;
|
||||
details_capacity = 0;
|
||||
}
|
||||
|
||||
~ClientStatusOp() {
|
||||
gprc_metadata_array_destroy(&metadata_array);
|
||||
grpc_metadata_array_destroy(&metadata_array);
|
||||
gpr_free(status_details);
|
||||
}
|
||||
|
||||
|
@ -357,7 +363,7 @@ class ClientStatusOp : public Op {
|
|||
NanEscapableScope();
|
||||
Handle<Object> status_obj = NanNew<Object>();
|
||||
status_obj->Set(NanNew("code"), NanNew<Number>(status));
|
||||
if (event->data.finished.details != NULL) {
|
||||
if (status_details != NULL) {
|
||||
status_obj->Set(NanNew("details"), String::New(status_details));
|
||||
}
|
||||
status_obj->Set(NanNew("metadata"), ParseMetadata(&metadata_array));
|
||||
|
@ -378,7 +384,7 @@ class ServerCloseResponseOp : public Op {
|
|||
public:
|
||||
Handle<Value> GetNodeValue() const {
|
||||
NanEscapableScope();
|
||||
NanEscapeScope(NanNew<Boolean>(cancelled));
|
||||
return NanEscapeScope(NanNew<Boolean>(cancelled));
|
||||
}
|
||||
|
||||
bool ParseOp(Handle<Value> value, grpc_op *out,
|
||||
|
@ -397,27 +403,43 @@ class ServerCloseResponseOp : public Op {
|
|||
int cancelled;
|
||||
};
|
||||
|
||||
struct tag {
|
||||
tag(NanCallback *callback, std::vector<unique_ptr<Op> > *ops,
|
||||
std::vector<unique_ptr<PersistentHolder> > *handles,
|
||||
std::vector<unique_ptr<NanUtf8String> > *strings) :
|
||||
callback(callback), ops(ops), handles(handles), strings(strings){
|
||||
tag::tag(NanCallback *callback, std::vector<unique_ptr<Op> > *ops,
|
||||
std::vector<unique_ptr<PersistentHolder> > *handles,
|
||||
std::vector<unique_ptr<NanUtf8String> > *strings) :
|
||||
callback(callback), ops(ops), handles(handles), strings(strings){
|
||||
}
|
||||
tag::~tag() {
|
||||
delete callback;
|
||||
delete ops;
|
||||
if (handles != NULL) {
|
||||
delete handles;
|
||||
}
|
||||
~tag() {
|
||||
if (strings != null) {
|
||||
for (std::vector<NanUtf8String *>::iterator it = strings.begin();
|
||||
it != strings.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
delete strings;
|
||||
}
|
||||
delete callback;
|
||||
delete ops;
|
||||
if (handles != null) {
|
||||
delete handles;
|
||||
}
|
||||
if (strings != NULL) {
|
||||
delete strings;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Handle<Value> GetTagNodeValue(void *tag) {
|
||||
NanEscapableScope();
|
||||
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
|
||||
Handle<Object> tag_obj = NanNew<Object>();
|
||||
for (std::vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
|
||||
it != tag_struct->ops->end(); ++it) {
|
||||
Op *op_ptr = it->get();
|
||||
tag_obj->Set(op_ptr->GetOpType(), op_ptr->GetNodeValue());
|
||||
}
|
||||
return NanEscapeScope(tag_obj);
|
||||
}
|
||||
|
||||
NanCallback GetTagCallback(void *tag) {
|
||||
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
|
||||
return *tag_struct->callback;
|
||||
}
|
||||
|
||||
void DestroyTag(void *tag) {
|
||||
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
|
||||
delete tag_struct;
|
||||
}
|
||||
|
||||
Call::Call(grpc_call *call) : wrapped_call(call) {}
|
||||
|
||||
|
@ -559,13 +581,16 @@ NAN_METHOD(Call::StartBatch) {
|
|||
default:
|
||||
return NanThrowError("Argument object had an unrecognized key");
|
||||
}
|
||||
op.ParseOp(obj.get(type), &ops[i], strings, handles);
|
||||
op_vector.push_back(unique_ptr<Op>(op));
|
||||
if (!op->ParseOp(obj->Get(type), &ops[i], strings, handles)) {
|
||||
return NanThrowTypeError("Incorrectly typed arguments to startBatch");
|
||||
}
|
||||
op_vector->push_back(unique_ptr<Op>(op));
|
||||
}
|
||||
grpc_call_error error = grpc_call_start_batch(
|
||||
call->wrapped_call, ops, nops, new struct tag(args[1].As<Function>(),
|
||||
op_vector, nops, handles,
|
||||
strings));
|
||||
call->wrapped_call, ops, nops, new struct tag(
|
||||
new NanCallback(args[1].As<Function>()),
|
||||
op_vector, handles,
|
||||
strings));
|
||||
if (error != GRPC_CALL_OK) {
|
||||
return NanThrowError("startBatch failed", error);
|
||||
}
|
||||
|
|
14
ext/call.h
14
ext/call.h
|
@ -35,6 +35,7 @@
|
|||
#define NET_GRPC_NODE_CALL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <node.h>
|
||||
#include <nan.h>
|
||||
|
@ -47,9 +48,12 @@ namespace node {
|
|||
|
||||
using std::unique_ptr;
|
||||
|
||||
v8::Handle<v8::Value> ParseMetadata(const grpc_metadata_array *metadata_array);
|
||||
|
||||
class PersistentHolder {
|
||||
public:
|
||||
explicit PersistentHolder(v8::Persistent<v8::Value> persist) : persist(persist) {
|
||||
explicit PersistentHolder(v8::Persistent<v8::Value> persist) :
|
||||
persist(persist) {
|
||||
}
|
||||
|
||||
~PersistentHolder() {
|
||||
|
@ -69,7 +73,7 @@ class Op {
|
|||
v8::Handle<v8::Value> GetOpType() const;
|
||||
|
||||
protected:
|
||||
virtual std::string GetTypeString() const;
|
||||
virtual std::string GetTypeString() const = 0;
|
||||
};
|
||||
|
||||
struct tag {
|
||||
|
@ -83,6 +87,12 @@ struct tag {
|
|||
std::vector<unique_ptr<NanUtf8String> > *strings;
|
||||
};
|
||||
|
||||
v8::Handle<v8::Value> GetTagNodeValue(void *tag);
|
||||
|
||||
NanCallback GetTagCallback(void *tag);
|
||||
|
||||
void DestroyTag(void *tag);
|
||||
|
||||
/* Wrapper class for grpc_call structs. */
|
||||
class Call : public ::node::ObjectWrap {
|
||||
public:
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "grpc/grpc.h"
|
||||
#include "grpc/support/time.h"
|
||||
#include "completion_queue_async_worker.h"
|
||||
#include "tag.h"
|
||||
#include "call.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace node {
|
||||
|
@ -78,7 +78,7 @@ void CompletionQueueAsyncWorker::Init(Handle<Object> exports) {
|
|||
void CompletionQueueAsyncWorker::HandleOKCallback() {
|
||||
NanScope();
|
||||
NanCallback callback = GetTagCallback(result->tag);
|
||||
Handle<Value> argv[] = {NanNull(), GetNodeValue(result->tag)};
|
||||
Handle<Value> argv[] = {NanNull(), GetTagNodeValue(result->tag)};
|
||||
|
||||
DestroyTag(result->tag);
|
||||
grpc_event_finish(result);
|
||||
|
|
|
@ -130,37 +130,6 @@ void InitCallErrorConstants(Handle<Object> exports) {
|
|||
call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS);
|
||||
}
|
||||
|
||||
void InitOpErrorConstants(Handle<Object> exports) {
|
||||
NanScope();
|
||||
Handle<Object> op_error = Object::New();
|
||||
exports->Set(NanNew("opError"), op_error);
|
||||
Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_OP_OK));
|
||||
op_error->Set(NanNew("OK"), OK);
|
||||
Handle<Value> ERROR(NanNew<Uint32, uint32_t>(GRPC_OP_ERROR));
|
||||
op_error->Set(NanNew("ERROR"), ERROR);
|
||||
}
|
||||
|
||||
void InitCompletionTypeConstants(Handle<Object> exports) {
|
||||
NanScope();
|
||||
Handle<Object> completion_type = Object::New();
|
||||
exports->Set(NanNew("completionType"), completion_type);
|
||||
Handle<Value> QUEUE_SHUTDOWN(NanNew<Uint32, uint32_t>(GRPC_QUEUE_SHUTDOWN));
|
||||
completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN);
|
||||
Handle<Value> READ(NanNew<Uint32, uint32_t>(GRPC_READ));
|
||||
completion_type->Set(NanNew("READ"), READ);
|
||||
Handle<Value> WRITE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_WRITE_ACCEPTED));
|
||||
completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED);
|
||||
Handle<Value> FINISH_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_FINISH_ACCEPTED));
|
||||
completion_type->Set(NanNew("FINISH_ACCEPTED"), FINISH_ACCEPTED);
|
||||
Handle<Value> CLIENT_METADATA_READ(
|
||||
NanNew<Uint32, uint32_t>(GRPC_CLIENT_METADATA_READ));
|
||||
completion_type->Set(NanNew("CLIENT_METADATA_READ"), CLIENT_METADATA_READ);
|
||||
Handle<Value> FINISHED(NanNew<Uint32, uint32_t>(GRPC_FINISHED));
|
||||
completion_type->Set(NanNew("FINISHED"), FINISHED);
|
||||
Handle<Value> SERVER_RPC_NEW(NanNew<Uint32, uint32_t>(GRPC_SERVER_RPC_NEW));
|
||||
completion_type->Set(NanNew("SERVER_RPC_NEW"), SERVER_RPC_NEW);
|
||||
}
|
||||
|
||||
void InitOpTypeConstants(Handle<Object> exports) {
|
||||
NanScope();
|
||||
Handle<Object> op_type = Object::New();
|
||||
|
@ -196,8 +165,6 @@ void init(Handle<Object> exports) {
|
|||
grpc_init();
|
||||
InitStatusConstants(exports);
|
||||
InitCallErrorConstants(exports);
|
||||
InitOpErrorConstants(exports);
|
||||
InitCompletionTypeConstants(exports);
|
||||
InitOpTypeConstants(exports);
|
||||
|
||||
grpc::node::Call::Init(exports);
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
#include "grpc/grpc_security.h"
|
||||
#include "call.h"
|
||||
#include "completion_queue_async_worker.h"
|
||||
#include "tag.h"
|
||||
#include "server_credentials.h"
|
||||
#include "timeval.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace node {
|
||||
|
@ -55,6 +55,7 @@ using std::unique_ptr;
|
|||
using v8::Arguments;
|
||||
using v8::Array;
|
||||
using v8::Boolean;
|
||||
using v8::Date;
|
||||
using v8::Exception;
|
||||
using v8::Function;
|
||||
using v8::FunctionTemplate;
|
||||
|
@ -80,12 +81,12 @@ class NewCallOp : public Op {
|
|||
|
||||
~NewCallOp() {
|
||||
grpc_call_details_destroy(&details);
|
||||
grpc_metadata_array_destroy(&details);
|
||||
grpc_metadata_array_destroy(&request_metadata);
|
||||
}
|
||||
|
||||
Handle<Value> GetNodeValue() const {
|
||||
NanEscapableScope();
|
||||
if (*call == NULL) {
|
||||
if (call == NULL) {
|
||||
return NanEscapeScope(NanNull());
|
||||
}
|
||||
Handle<Object> obj = NanNew<Object>();
|
||||
|
@ -99,15 +100,20 @@ class NewCallOp : public Op {
|
|||
}
|
||||
|
||||
bool ParseOp(Handle<Value> value, grpc_op *out,
|
||||
std::vector<unique_ptr<NanUtf8String> > strings,
|
||||
std::vector<unique_ptr<PersistentHolder> > handles) {
|
||||
std::vector<unique_ptr<NanUtf8String> > *strings,
|
||||
std::vector<unique_ptr<PersistentHolder> > *handles) {
|
||||
return true;
|
||||
}
|
||||
|
||||
grpc_call *call;
|
||||
grpc_call_details details;
|
||||
grpc_metadata_array request_metadata;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string GetTypeString() const {
|
||||
return "new call";
|
||||
}
|
||||
};
|
||||
|
||||
Server::Server(grpc_server *server) : wrapped_server(server) {}
|
||||
|
||||
|
@ -217,12 +223,13 @@ NAN_METHOD(Server::RequestCall) {
|
|||
return NanThrowTypeError("requestCall can only be called on a Server");
|
||||
}
|
||||
Server *server = ObjectWrap::Unwrap<Server>(args.This());
|
||||
Op *op = new NewCallOp();
|
||||
std::vector<unique_ptr<Op> > *ops = { unique_ptr<Op>(op) };
|
||||
NewCallOp *op = new NewCallOp();
|
||||
std::vector<unique_ptr<Op> > *ops = new std::vector<unique_ptr<Op> >();
|
||||
ops->push_back(unique_ptr<Op>(op));
|
||||
grpc_call_error error = grpc_server_request_call(
|
||||
server->wrapped_server, &op->call, &op->details, &op->metadata,
|
||||
server->wrapped_server, &op->call, &op->details, &op->request_metadata,
|
||||
CompletionQueueAsyncWorker::GetQueue(),
|
||||
new struct tag(args[0].As<Function>(), ops, NULL, NULL));
|
||||
new struct tag(new NanCallback(args[0].As<Function>()), ops, NULL, NULL));
|
||||
if (error != GRPC_CALL_OK) {
|
||||
return NanThrowError("requestCall failed", error);
|
||||
}
|
||||
|
|
|
@ -98,105 +98,81 @@ describe('call', function() {
|
|||
}, TypeError);
|
||||
});
|
||||
});
|
||||
describe('addMetadata', function() {
|
||||
it('should succeed with a map from strings to string arrays', function() {
|
||||
describe('startBatch', function() {
|
||||
it('should fail without an object and a function', function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.doesNotThrow(function() {
|
||||
call.addMetadata({'key': ['value']});
|
||||
assert.throws(function() {
|
||||
call.startBatch();
|
||||
});
|
||||
assert.doesNotThrow(function() {
|
||||
call.addMetadata({'key1': ['value1'], 'key2': ['value2']});
|
||||
assert.throws(function() {
|
||||
call.startBatch({});
|
||||
});
|
||||
assert.throws(function() {
|
||||
call.startBatch(null, function(){});
|
||||
});
|
||||
});
|
||||
it('should succeed with a map from strings to buffer arrays', function() {
|
||||
it.skip('should succeed with an empty object', function(done) {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.doesNotThrow(function() {
|
||||
call.addMetadata({'key': [new Buffer('value')]});
|
||||
call.startBatch({}, function(err) {
|
||||
assert.ifError(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('startBatch with metadata', function() {
|
||||
it('should succeed with a map of strings to string arrays', function(done) {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.doesNotThrow(function() {
|
||||
call.addMetadata({'key1': [new Buffer('value1')],
|
||||
'key2': [new Buffer('value2')]});
|
||||
var batch = {};
|
||||
batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'],
|
||||
'key2': ['value2']};
|
||||
call.startBatch(batch, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.deepEqual(resp, {'send metadata': true});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should succeed with a map of strings to buffer arrays', function(done) {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.doesNotThrow(function() {
|
||||
var batch = {};
|
||||
batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||
'key1': [new Buffer('value1')],
|
||||
'key2': [new Buffer('value2')]
|
||||
};
|
||||
call.startBatch(batch, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.deepEqual(resp, {'send metadata': true});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should fail with other parameter types', function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.throws(function() {
|
||||
call.addMetadata();
|
||||
var batch = {};
|
||||
batch[grpc.opType.SEND_INITIAL_METADATA] = undefined;
|
||||
call.startBatch(batch, function(){});
|
||||
});
|
||||
assert.throws(function() {
|
||||
call.addMetadata(null);
|
||||
var batch = {};
|
||||
batch[grpc.opType.SEND_INITIAL_METADATA] = null;
|
||||
call.startBatch(batch, function(){});
|
||||
}, TypeError);
|
||||
assert.throws(function() {
|
||||
call.addMetadata('value');
|
||||
var batch = {};
|
||||
batch[grpc.opType.SEND_INITIAL_METADATA] = 'value';
|
||||
call.startBatch(batch, function(){});
|
||||
}, TypeError);
|
||||
assert.throws(function() {
|
||||
call.addMetadata(5);
|
||||
var batch = {};
|
||||
batch[grpc.opType.SEND_INITIAL_METADATA] = 5;
|
||||
call.startBatch(batch, function(){});
|
||||
}, TypeError);
|
||||
});
|
||||
it('should fail if invoke was already called', function(done) {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
call.invoke(function() {},
|
||||
function() {done();},
|
||||
0);
|
||||
assert.throws(function() {
|
||||
call.addMetadata({'key': ['value']});
|
||||
}, function(err) {
|
||||
return err.code === grpc.callError.ALREADY_INVOKED;
|
||||
});
|
||||
// Cancel to speed up the test
|
||||
call.cancel();
|
||||
});
|
||||
});
|
||||
describe('invoke', function() {
|
||||
it('should fail with fewer than 3 arguments', function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.throws(function() {
|
||||
call.invoke();
|
||||
}, TypeError);
|
||||
assert.throws(function() {
|
||||
call.invoke(function() {});
|
||||
}, TypeError);
|
||||
assert.throws(function() {
|
||||
call.invoke(function() {},
|
||||
function() {});
|
||||
}, TypeError);
|
||||
});
|
||||
it('should work with 2 args and an int', function(done) {
|
||||
assert.doesNotThrow(function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
call.invoke(function() {},
|
||||
function() {done();},
|
||||
0);
|
||||
// Cancel to speed up the test
|
||||
call.cancel();
|
||||
});
|
||||
});
|
||||
it('should reject incorrectly typed arguments', function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.throws(function() {
|
||||
call.invoke(0, 0, 0);
|
||||
}, TypeError);
|
||||
assert.throws(function() {
|
||||
call.invoke(function() {},
|
||||
function() {}, 'test');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('serverAccept', function() {
|
||||
it('should fail with fewer than 1 argument1', function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.throws(function() {
|
||||
call.serverAccept();
|
||||
}, TypeError);
|
||||
});
|
||||
it('should return an error when called on a client Call', function() {
|
||||
var call = new grpc.Call(channel, 'method', getDeadline(1));
|
||||
assert.throws(function() {
|
||||
call.serverAccept(function() {});
|
||||
}, function(err) {
|
||||
return err.code === grpc.callError.NOT_ON_CLIENT;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('cancel', function() {
|
||||
it('should succeed', function() {
|
||||
|
|
|
@ -76,31 +76,6 @@ var callErrorNames = [
|
|||
'INVALID_FLAGS'
|
||||
];
|
||||
|
||||
/**
|
||||
* List of all op error names
|
||||
* @const
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
var opErrorNames = [
|
||||
'OK',
|
||||
'ERROR'
|
||||
];
|
||||
|
||||
/**
|
||||
* List of all completion type names
|
||||
* @const
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
var completionTypeNames = [
|
||||
'QUEUE_SHUTDOWN',
|
||||
'READ',
|
||||
'WRITE_ACCEPTED',
|
||||
'FINISH_ACCEPTED',
|
||||
'CLIENT_METADATA_READ',
|
||||
'FINISHED',
|
||||
'SERVER_RPC_NEW'
|
||||
];
|
||||
|
||||
describe('constants', function() {
|
||||
it('should have all of the status constants', function() {
|
||||
for (var i = 0; i < statusNames.length; i++) {
|
||||
|
@ -114,16 +89,4 @@ describe('constants', function() {
|
|||
'call error missing: ' + callErrorNames[i]);
|
||||
}
|
||||
});
|
||||
it('should have all of the op errors', function() {
|
||||
for (var i = 0; i < opErrorNames.length; i++) {
|
||||
assert(grpc.opError.hasOwnProperty(opErrorNames[i]),
|
||||
'op error missing: ' + opErrorNames[i]);
|
||||
}
|
||||
});
|
||||
it('should have all of the completion types', function() {
|
||||
for (var i = 0; i < completionTypeNames.length; i++) {
|
||||
assert(grpc.completionType.hasOwnProperty(completionTypeNames[i]),
|
||||
'completion type missing: ' + completionTypeNames[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -110,52 +110,61 @@ describe('end-to-end', function() {
|
|||
assert.strictEqual(event.data, grpc.opError.OK);
|
||||
});
|
||||
});
|
||||
it('should successfully send and receive metadata', function(complete) {
|
||||
var done = multiDone(complete, 2);
|
||||
it.only('should successfully send and receive metadata', function(done) {
|
||||
debugger;
|
||||
var deadline = new Date();
|
||||
deadline.setSeconds(deadline.getSeconds() + 3);
|
||||
var status_text = 'xyz';
|
||||
var call = new grpc.Call(channel,
|
||||
'dummy_method',
|
||||
deadline);
|
||||
call.addMetadata({'client_key': ['client_value']});
|
||||
call.invoke(function(event) {
|
||||
assert.strictEqual(event.type,
|
||||
grpc.completionType.CLIENT_METADATA_READ);
|
||||
assert.strictEqual(event.data.server_key[0].toString(), 'server_value');
|
||||
},function(event) {
|
||||
assert.strictEqual(event.type, grpc.completionType.FINISHED);
|
||||
var status = event.data;
|
||||
assert.strictEqual(status.code, grpc.status.OK);
|
||||
assert.strictEqual(status.details, status_text);
|
||||
var client_batch = {};
|
||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||
'client_key': ['client_value']
|
||||
};
|
||||
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(client_batch, function(err, response) {
|
||||
assert.ifError(err);
|
||||
assert.deepEqual(response, {
|
||||
'send metadata': true,
|
||||
'client close': true,
|
||||
'metadata': {'server_key': [new Buffer('server_value')]},
|
||||
'status': {
|
||||
'code': grpc.status.OK,
|
||||
'details': status_text
|
||||
}
|
||||
});
|
||||
done();
|
||||
}, 0);
|
||||
|
||||
server.requestCall(function(event) {
|
||||
assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
|
||||
assert.strictEqual(event.data.metadata.client_key[0].toString(),
|
||||
'client_value');
|
||||
var server_call = event.call;
|
||||
assert.notEqual(server_call, null);
|
||||
server_call.serverAccept(function(event) {
|
||||
assert.strictEqual(event.type, grpc.completionType.FINISHED);
|
||||
}, 0);
|
||||
server_call.addMetadata({'server_key': ['server_value']});
|
||||
server_call.serverEndInitialMetadata(0);
|
||||
server_call.startWriteStatus(
|
||||
grpc.status.OK,
|
||||
status_text,
|
||||
function(event) {
|
||||
assert.strictEqual(event.type,
|
||||
grpc.completionType.FINISH_ACCEPTED);
|
||||
assert.strictEqual(event.data, grpc.opError.OK);
|
||||
done();
|
||||
});
|
||||
});
|
||||
call.writesDone(function(event) {
|
||||
assert.strictEqual(event.type,
|
||||
grpc.completionType.FINISH_ACCEPTED);
|
||||
assert.strictEqual(event.data, grpc.opError.OK);
|
||||
|
||||
server.requestCall(function(err, call_details) {
|
||||
var new_call = call_details['new call'];
|
||||
assert.notEqual(new_call, null);
|
||||
assert.strictEqual(new_call.metadata.client_key[0].toString(),
|
||||
'client_value');
|
||||
var server_call = new_call.call;
|
||||
assert.notEqual(server_call, null);
|
||||
var server_batch = {};
|
||||
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||
'server_key': ['server_value']
|
||||
};
|
||||
server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
||||
'metadata': {},
|
||||
'code': grpc.status.OK,
|
||||
'details': status_text
|
||||
};
|
||||
server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
|
||||
console.log(server_batch);
|
||||
server_call.startBatch(server_batch, function(err, response) {
|
||||
assert.ifError(err);
|
||||
assert.deepEqual(response, {
|
||||
'send metadata': true,
|
||||
'send status': true,
|
||||
'cancelled': false
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should send and receive data without error', function(complete) {
|
||||
|
|
Loading…
Reference in New Issue