I am trying to mock parts of the AWS SDK in C++ for testing. Specifically, I'm mocking a KMSClient and DecryptOutcome object. The MockKMSClient is set to pass in a MockDecryptOutcome into the DecryptResponseReceivedHandler.
Here are my mocked classes:
class MockDecryptOutcome : public Aws::KMS::Model::DecryptOutcome {
public:
Aws::Utils::Base64::Base64 _Base64;
MockDecryptOutcome(string request) {
if (request == SUCCESS) {
EXPECT_CALL(*this, IsSuccess()).WillRepeatedly(Return(true));
Aws::KMS::Model::DecryptResult result;
result.SetPlaintext(_Base64.Decode(SUCCESS));
EXPECT_CALL(*this, GetResult()).WillRepeatedly(Return(result));
} else {
EXPECT_CALL(*this, IsSuccess()).WillRepeatedly(Return(false));
if (request == GRANT_TOKEN_NEEDED) {
EXPECT_CALL(*this, GetError()).WillRepeatedly(Return(Aws::KMS::KMSErrors::ACCESS_DENIED));
} else if (request == ENDPOINT_ERROR) {
EXPECT_CALL(*this, GetError()).WillRepeatedly(Return(Aws::KMS::KMSErrors::NETWORK_CONNECTION));
}
}
}
virtual ~MockDecryptOutcome() {};
MOCK_METHOD0(IsSuccess, bool());
MOCK_METHOD0(GetResult, Aws::KMS::Model::DecryptResult());
MOCK_CONST_METHOD0(GetError, Aws::KMS::KMSErrors());
};
class MockKMSClient : public Aws::KMS::KMSClient {
public:
MockKMSClient() {
EXPECT_CALL(*this, DecryptAsync_impl(_, _)).WillRepeatedly(Invoke(this, &MockKMSClient::do_DecryptAsync));
}
virtual ~MockKMSClient() {};
Aws::Utils::Base64::Base64 _Base64;
// Have to invoke Mocked method manually to discard optional parameter
void DecryptAsync(
const Aws::KMS::Model::DecryptRequest& request,
const Aws::KMS::DecryptResponseReceivedHandler& handler,
const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr
) const
{
DecryptAsync_impl(request, handler);
}
MOCK_CONST_METHOD2(
DecryptAsync_impl,
void(
const Aws::KMS::Model::DecryptRequest& request,
const Aws::KMS::DecryptResponseReceivedHandler& handler
)
);
void do_DecryptAsync(
const Aws::KMS::Model::DecryptRequest& request,
const Aws::KMS::DecryptResponseReceivedHandler& handler
)
{
const MockDecryptOutcome& outcome(_Base64.Encode(request.GetCiphertextBlob()));
cout << &outcome << endl;
handler(this, request, outcome, nullptr);
}
};
The handler is defined in the AWS SDK here: http://sdk.amazonaws.com/cpp/api/LATEST/namespace_aws_1_1_k_m_s.html#a6bb4999b2fbc6cd499913779e42421b3
Here is the callback function:
void KmsCallback::on_decrypt_callback(
const Aws::KMS::KMSClient* client,
const Aws::KMS::Model::DecryptRequest&,
const Aws::KMS::Model::DecryptOutcome& outcome,
const std::shared_ptr<const Aws::Client::AsyncCallerContext>&
)
{
cout << &outcome << endl;
}
Finally, here is where the async function is called:
kms_client->DecryptAsync(
decrypt_request,
std::bind(
&KmsCallback::on_decrypt_callback,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4
)
);
Running this in a test prints out two different memory addresses for the DecryptOutcome variables:
0x7f03b6064dc0
0x7f03b6064dc8
I've tried using the "new" operator, removing "const", and many other combinations to get this to work without success. Any suggestions would be appreciated.
Related
I'm using AsyncWorkerto run an asynchronous task. The problem is that i have numerous tasks to be run, one after another, and the order is important. To keep order i'm using a queuing technique to make sure the AsyncWorkerobjects are created in the wright order, only once each task finishes. I'm storing the Callback in a vector<Function>, and pass that to the AsyncWorker, but i get the following error:
# Fatal error in v8::HandleScope::CreateHandle()
# Cannot create a handle without a HandleScope
Is there some other way of going about this? I also tried using Napi::Persistent, but i can't pass a Napi::FunctionReference variable to AsyncWorker
The caller functions:
Napi::Value BlockChainWrapper::genesis(const Napi::CallbackInfo& info) {
std::lock_guard<std::mutex> guard_ready_queue(ready_queue_mutex);
this->ready_queue_callback.push_back(info[1].As<Napi::Function>());
this->ready_queue_data.push_back(info[0].As<Napi::Object>());
this->ready_queue_func.push_back(BlockChainWrapperTypes::_genesis_ready);
this->ready_queue_env.push_back(info.Env());
return info.Env().Undefined();
}
void BlockChainWrapper::genesis_ready() {
AsyncBlockChainFunctions* asyncWorker = new AsyncBlockChainFunctions(this->ready_queue_callback.front(), 0, blockchain_obj, this->ready_queue_data.front());
asyncWorker->Queue();
}
AsyncWorker constructor:
AsyncBlockChainFunctions::AsyncBlockChainFunctions(Napi::Function& callback, int mode, std::shared_ptr<BlockChain> _blockchain, Napi::Object& resource) : AsyncWorker(callback), mode(mode) {};
EDIT 1
I implemented the PromiseWorker, but still ran into these errors:
BlockChainWrapper inherits ObjectWrap.
Napi::Object BlockChainWrapper::Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
Napi::Function func = DefineClass(env, "BlockChainWrapper", {
InstanceMethod("genesis", &BlockChainWrapper::genesis)
});
constructor = Napi::Persistent(func);
constructor.SuppressDestruct();
exports.Set("BlockChainWrapper", func);
return exports;
}
# Fatal error in HandleScope::HandleScope
# Entering the V8 API without proper locking in place
Modified AsyncWorker constructor, class and resolve function:
class AsyncBlockChainFunctions : public PromiseWorker
AsyncBlockChainFunctions(Napi::Promise::Deferred const &d, std::shared_ptr<BlockChain> _blockchain, int mode, Napi::Object& resource) : PromiseWorker(d), mode(mode) {}
void Resolve(Napi::Promise::Deferred const &deferred) {
deferred.Resolve(Napi::String::New(deferred.Env(), this->block_as_json_string));
};
Caller function:
Napi::Value BlockChainWrapper::genesis(const Napi::CallbackInfo& info) {
std::lock_guard<std::mutex> guard_ready_queue(ready_queue_mutex);
this->ready_queue_data.push_back(info[0].As<Napi::Object>());
this->ready_queue_func.push_back(BlockChainWrapperTypes::_genesis_ready);
this->ready_queue_env.push_back(info.Env());
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
std::cout << "genesis" << std::endl;
return deferred.Promise();
}
Genesis ready called from another queue management thread
void BlockChainWrapper::genesis_ready() {
Napi::Env env = ready_queue_env.front();
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
Napi::Object input_obj = this->ready_queue_data.front().As<Napi::Object>();
auto *x = new AsyncBlockChainFunctions(std::ref(deferred), this->blockchain_obj, 0, input_obj);
x->Queue();
}
I am not sure if I understood you correctly or able to help your original problem, but you should not depend on the order of the execution of AsyncWorker. However the error you mentioned just sounds like you constructed AsyncWorker wrong, i.e. the CallbackInfo might be faulty, i.e. the napi environment its based on.
Promises
However I strongly recommend to use AsyncWorker to just handle the lifetime as I was designed to do, and to switch to the promise pattern.
Based on https://github.com/nodejs/node-addon-api/issues/231#issuecomment-528986145
I recommend you use this as a base class:
#include <napi.h>
class PromiseWorker : public Napi::AsyncWorker {
public:
PromiseWorker(Napi::Promise::Deferred const &d) : AsyncWorker(get_fake_callback(d.Env()).Value()), deferred(d) {}
virtual void Resolve(Napi::Promise::Deferred const &deferred) = 0;
void OnOK() override {
Resolve(deferred);
}
void OnError(Napi::Error const &error) override {
deferred.Reject(error.Value());
}
private:
static Napi::Value noop(Napi::CallbackInfo const &info) {
return info.Env().Undefined();
}
Napi::Reference<Napi::Function> const &get_fake_callback(Napi::Env const &env) {
static Napi::Reference<Napi::Function> fake_callback
= Napi::Reference<Napi::Function>::New(Napi::Function::New(env, noop), 1);
fake_callback.SuppressDestruct();
return fake_callback;
}
Napi::Promise::Deferred deferred;
};
You just then would have to subclass it, override Resolve and Execute, and save the stuff you need in your member privates, and you are done.
Update: I made a full working example on how to use this promises: https://github.com/Superlokkus/spielwiese/tree/napi_promise_example
Note the Promise Method:
#include <napi.h>
#include "promise_worker.hpp"
struct PromiseMethodWorker : PromiseWorker {
PromiseMethodWorker(Napi::Promise::Deferred const &d, int input)
: PromiseWorker(d), input_{std::move(input)} {}
void Resolve(Napi::Promise::Deferred const &deferred) override {
deferred.Resolve(create_js(deferred.Env()));
}
void Execute() override {
output_ = input_ * 5;
}
private:
int input_;
int output_;
Napi::Number create_js(Napi::Env env) const {
Napi::Number js_value = Napi::Number::New(env, output_);
return js_value;
}
};
Napi::Promise PromiseMethod(const Napi::CallbackInfo &info) {
int input = info[0].ToNumber();
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
auto *wk = new PromiseMethodWorker(deferred, input);
wk->Queue();
return deferred.Promise();
}
Usage and Solution
So you could just use the promise returned in JS:
addon.PromiseMethod(42).then(value => add.PromiseMethod(value).then(...))
So you could easily chain these promises together, of wait for all via Promise::all. But so you avoid the so called callback hell. But again, your diffuse order requirement sounds like a XY problem to me.
So instead of many promises/callbacks make it to one, since AsyncWorker seem to make no guarantee about call order. Blocking in one promise, might stall everything. Order in your native code.
The following will work even for an array
async.eachSeries(/*array*/, function(item, nextItem) {
async.waterfall([
function(callback) {
//your logic
callback(null, data);
},
function(data, callback) {
//your logic
callback(null, data2);
},
function(data2, callback) {
//your logic
callback(null, 3); //The number is just for the argument purpose. Can be anything
}
//You can continue adding as many steps as you want
],nextItem)
});
I'm trying to make the equivalent of a Event Listener from Java, but in C++.
My goal is, that I can call a function from a class, which triggers my listener I added to this class.
I found the following Link which gave me a solution to do this.
The problem hereby is, that my program crashed as soon as I tried to call the listeners.
My code is structured like this:
class MessageHandler abstract
{
public:
typedef const std::function<void(int, std::string)> Handler;
void addHandler(Handler& handler) {
handlers.push_back(&handler);
}
private:
std::vector<Handler*> handlers;
protected:
void someFunction(int id, std::string message) {
for (auto& handler : handlers) {
(*handler)(id, message); //Here it will crash
}
}
};
As you maybe already mentioned, this is the base class from which I derive some childclasses. These childclasses call then my "someFunction" code.
And the class where I create one of these childclasses, is structured like this:
class Server
{
private:
SubHandler handler;
void setHandlers() {
handler.addHandler([&](int id, std::string message) { executingFunction(id, message); });
}
void executingFunction(int id, std::string message) {
std::cout << "Listener Worked!" << std::endl;
//Not actually the code inside, but it doesn't matter, case I don't even get to this code
}
};
The program crashes at the line, where I loop over my listeners and call them with error:
"Access violation when reading at position 0x000000000000000010."
(This is translated, so its not the message you will get if you have your Visual Studio set to English)
You should compile your code using /permissive-. The compiler should refuse your code.
void addHandler(Handler& handler) {
handlers.push_back(&handler);
}
You shouldn't be able to send a temporary to this function, but yet you are!
// v----- This lambda is a temporary object --------------------------v
handler.addHandler([&](int id, std::string message) { executingFunction(id, message); });
The lambda object created at that line dies just after the statement is finished.
// v---- pointer to the temporary.
handlers.push_back(&handler);
My recomendation would be to drop the pointer and use std::function object by value. They are made to be used like that:
// abstract is not a C++ keyword.
class MessageHandler /* abstract */
{
public:
// using instead of typedef and non const
using Handler = std::function<void(int, std::string)>;
void addHandler(Handler const& handler) { // const reference
// insert by value
handlers.push_back(handler);
}
private:
// no pointer here.
std::vector<Handler> handlers;
protected:
void someFunction(int id, std::string message) {
for (auto const& handler : handlers) {
handler(id, message); //Here it will not crash anymore
}
}
};
This is because your lambda defined in your Server class method isn't in the scope of your MessageHandler class. I suggest you read through this : https://blog.feabhas.com/2014/03/demystifying-c-lambdas/ to get a good idea of what the problem is and how to fix it.
Though, it might be a good solution to define a struct holding your lambda, which would then work with std::mem_fn.
Hope this helps
Your source is bad :/
You might use instead something like:
class MessageHandler
{
public:
using Handler = std::function<void(int, const std::string&)> Handler;
void addHandler(const Handler& handler) { handlers.push_back(handler); }
void execute(int id, const std::string& message) {
for (auto& handler : handlers) {
(*handler)(id, message);
}
}
private:
std::vector<Handler> handlers;
};
And then use it:
class Server
{
private:
MessageHandler handler;
void setHandlers()
{
handler.addHandler(&Server::executingFunction);
handler.addHandler(
[](int id, const std::string& message)
{
std::cout << message << id << std::endl;
});
}
static void executingFunction(int id, const std::string& message) {
std::cout << "Listener Worked!" << std::endl;
}
};
I'm having the following .proto for Protobuf (2.6.1 to be more detailed):
service InstallService {
rpc getWifiNetworks (WifiRequest) returns (WifiResponse);
}
I've generated java files and i'm having BlockingStub:
TestInstallService.BlockingInterface service = TestInstallService.newBlockingStub(channel);
and i can use if in blocking way (works good):
Wifi.WifiResponse response = service.getWifiNetworks(controller, request);
Now i'm creating C++ client which should work in blocking way too but i can't see any Blocking interfaces neither in proto nor in generated C++ code. How to generate BlockingStub in C++ in Protobuf? How can i pass closure if working in async way?
Generated C++ service file (.cpp):
class InstallService_Stub;
class InstallService : public ::google::protobuf::Service {
protected:
// This class should be treated as an abstract interface.
inline InstallService() {};
public:
virtual ~InstallService();
typedef InstallService_Stub Stub;
static const ::google::protobuf::ServiceDescriptor* descriptor();
virtual void getWifiNetworks(::google::protobuf::RpcController* controller,
const ::WifiRequest* request,
::WifiResponse* response,
::google::protobuf::Closure* done);
// implements Service ----------------------------------------------
const ::google::protobuf::ServiceDescriptor* GetDescriptor();
void CallMethod(const ::google::protobuf::MethodDescriptor* method,
::google::protobuf::RpcController* controller,
const ::google::protobuf::Message* request,
::google::protobuf::Message* response,
::google::protobuf::Closure* done);
const ::google::protobuf::Message& GetRequestPrototype(
const ::google::protobuf::MethodDescriptor* method) const;
const ::google::protobuf::Message& GetResponsePrototype(
const ::google::protobuf::MethodDescriptor* method) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InstallService);
};
class InstallService_Stub : public InstallService {
public:
InstallService_Stub(::google::protobuf::RpcChannel* channel);
InstallService_Stub(::google::protobuf::RpcChannel* channel,
::google::protobuf::Service::ChannelOwnership ownership);
~InstallService_Stub();
inline ::google::protobuf::RpcChannel* channel() { return channel_; }
// implements InstallService ------------------------------------------
void getWifiNetworks(::google::protobuf::RpcController* controller,
const ::WifiRequest* request,
::WifiResponse* response,
::google::protobuf::Closure* done);
private:
::google::protobuf::RpcChannel* channel_;
bool owns_channel_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InstallService_Stub);
};
It seems that no blocking code is generated by protoc so i had to use self-made blocking:
bool callbackFired = false;
void myCallback() {
// ...
callbackFired = true;
}
// run service method
service->myMethod(rpcController, request, response, NewCallback(&myCallback));
// block the thread until callback is invoked
while (!callbackFired);
...
C++ client usage example: https://github.com/4ntoine/protobuf-socket-rpc
The way you do this is to provide your own subclass of InstallService that overrides the methods you want to implement:
struct MyInstallService : public InstallService
{
void getWifiNetworks(::google::protobuf::RpcController* controller,
const ::WifiRequest* request,
::WifiResponse* response,
::google::protobuf::Closure* done) override
{
// do your work here
// fill up the response here
done->Run(); // this will trigger the response
}
};
client side:
Something like this
namespace detail {
template<class F>
struct simple_closure : google::protobuf::Closure {
simple_closure(F f)
: _f(std::move(f))
{}
void Run() override {
_f();
}
private:
F _f;
};
}
template<class F>
std::unique_ptr<detail::simple_closure<F>> make_closure(F&& f) {
return std::make_unique<detail::simple_closure<F>>(std::forward<F>(f));
}
std::unique_ptr<WifiResponse> syncGetWifiNetworks(InstallService_Stub & stub, const WifiRequest& req)
{
auto result = std::make_unique<WifiResponse>();
auto promise = std::promise<std::unique_ptr<WifiResponse>>;
auto future = promise.get_future();
auto controller = allocate_controller(); // you need to write this
auto closure = make_closure([&result, &promise]{
promise.set_value(std::move(result));
});
// assumes you already have an async comms queue - otherwise just
// dispatch this lambda to a std::async(std::launch::async, ...)
comms_queue.dispatch([&controller, &req, &stub, &response]{
stub.getWifiNetworks(controller, &req, response.get(), closure);
};
// HERE is where the current thread blocks until the promise is fulfilled
return future.get();
}
Is it possible to bind functions with derived parameters ? And if how ? I would like to be able to store function points to various functions that all have a similar signature, namely they take a class with input data and return a class with output values. But the different functions require and provide different parameters, hence I am trying to register functions that take derived message classes.
The following code works in part. I can register the function MathService::blank and I can later call it. But I cannot add MathService::add.
The error I get is:
main.cpp:70:93: error: conversion from ‘std::_Bind_helper&)(RequestMessage&, ReplyMessage&), MathService&, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind(MathService*, std::_Placeholder<1>, std::_Placeholder<2>)>}’ to non-scalar type ‘Service::serviceFunction_t {aka std::function}’ requested
serviceFunction_t fn = bind( methodPtr, objectPtr, placeholders::_1, placeholders::_2 );
#include <functional>
#include <unordered_map>
#include <iostream>
using namespace std;
// base class for messages passed around
class BaseMessage
{
public:
virtual void print()
{
cout << "BaseMessage\n";
}
};
// request message with data passed to the service
class RequestMessage : public BaseMessage
{
public:
RequestMessage( int a_, int b_ ) : a( a_ ), b( b_ ) {}
int a;
int b;
void print()
{
cout << "RequestMessage a=" << a << " b=" << b << endl;
}
};
// reply message with return values from the service
class ReplyMessage : public BaseMessage
{
public:
ReplyMessage() : sum( 0 ) {}
int sum;
void print()
{
cout << "ReplyMessage sum=" << sum << endl;
}
};
// Example service provider
class MathService
{
public:
void blank( BaseMessage& request, BaseMessage& reply )
{
request.print();
reply.print();
}
void add( RequestMessage& request, ReplyMessage& reply )
{
reply.sum = request.a + request.b;
}
};
// Class manages services, register a new service with addService and call the service by name using call
class Service
{
public:
using serviceFunction_t = function<void ( BaseMessage&, BaseMessage& )>;
template<class Method, class Obj>
void addService( string name, Method methodPtr, Obj objectPtr )
{
serviceFunction_t fn = bind( methodPtr, objectPtr, placeholders::_1, placeholders::_2 );
pair< string, serviceFunction_t> entry( name, fn );
mFunctionMap.insert( entry );
}
void call( const string& name, BaseMessage& request, BaseMessage& reply )
{
std::unordered_map<string, serviceFunction_t>::const_iterator it;
it = mFunctionMap.find( name );
if( it == mFunctionMap.end() ) {
std::cout << "service not found: " << name << endl;
return;
}
serviceFunction_t fn = it->second;
fn( request, reply );
}
private:
unordered_map<string, serviceFunction_t> mFunctionMap;
};
int main()
{
MathService math;
Service service;
// can add a service with BaseMessages
service.addService( "blank", &MathService::blank, &math );
//*****************************************************
// PROBLEM is here !!
// can not add a service with derived message types, this causes the bind call to fail in Service::addService()
service.addService( "add", &MathService::add, &math );
//*****************************************************
// this works
BaseMessage req1, rep1;
service.call( "blank", req1, rep1 );
// so does this
RequestMessage req2( 1, 2 );
ReplyMessage rep2;
service.call( "blank", req2, rep2 );
// this service is not registered
service.call( "add", req2, rep2 );
}
1) do is a reserved C++ keyword, so your code as-this will never compile
2) std::placeholders_1 does not exist, you surely meant std::placeholders::_1
3) Once this is fixed, yes, it compiles.
I am trying to implement a class that would allow listening on some events and when these emits are emitted, they would get notifications.
So i thought of using Functors,
class MyFunctor {
public:
virtual void emit() {}
vitual void compare() {}
};
class MyFunctorSpecial : public MyFunctor {
void (*)() ab;
public:
MyFunctorSpecial(void (*a)()) : ab(a) {}
void emit() { ab(); }
};
class EventEmitter {
std::map<std::string, std::vector<MyFunctor> > eventMap;
public:
void On(const std::string &, const MyFunctor &) {
// add to the map
}
void Emit(const std::string & eventName) {
// emit the event
// for all listeners in the vector for this event-name
// call the emit of them.
}
};
EventEmitter emitter;
// some function - abc()
MyFunctorSpecial funct(abc);
emitter.On("hello", funct);
emitter.Emit("hello");
But now i want to pass arguments to the listeners. Like
emitter.Emit("hello", 45, false);
I think that this information would be available to Emit() at compile time, about the data-types of the various arguments. Can i use that information to make it happen , using templates or anything.
If there is another kind of pattern for this problem? How can I do this?
The common design pattern for your problem is called the Observer Design-Pattern.
Your so called "functors" are not functors.
If so they would have implemented an operator () method, and could have been called like functions ( thus the name functor). Yours are not.
For example, this is a functor: ( notice the operator())
class MyFunctor
{
public:
void operator()(){};
};
try this simple example as follow:
class event_manager {
std::map<std::string, std::vector<std::function<void( std::string )>>> eventMap;
public:
void on( const std::string &evt_name, std::function<void( std::string )> listener ) {
auto it = eventMap.find( evt_name );
if ( it != eventMap.end( ) ) {
it->second.push_back( listener );
return;
}
eventMap[evt_name] = std::vector<std::function<void( std::string )>>( );
eventMap[evt_name].push_back( listener );
};
void emit( const std::string &evt_name, std::string data ) {
auto evts = eventMap.find( evt_name );
if ( evts == eventMap.end( ) ) return;
for ( std::vector<std::function<void( std::string )>>::iterator it = std::begin( evts->second ); it != std::end( evts->second ); ++it ) {
auto &func = *it;
func( data );
}
}
};
and subscribe and emit event as like:
event_manager evt_mng;
evt_mng.on( "data", [&]( auto res ) {
std::cout << res << std::endl;
} );
evt_mng.emit( "data", "Hello world" );