Commit f17d6738 by amir

add testing to microservice and run them from rest/http

parent 3901676c
......@@ -43,7 +43,7 @@ set (3PARTY_SOURCES ../3party/civetweb/src/civetweb.c ../3party/civetweb/src/Civ
#Generate the shared library from the sources
add_library(Microservice SHARED ${SOURCES} ${3PARTY_SOURCES} src/impl/servers/Microservice_IRestServerZmqImpl.cpp src/impl/servers/Microservice_IRestServerZmqImpl.h src/common/Microservice_Iface.cpp src/impl/clients/MSICommandClientZmqImpl.cpp src/impl/clients/MSICommandClientZmqImpl.h src/impl/Microservice_ICacheClientPocoImpl.h)
add_library(Microservice SHARED ${SOURCES} ${3PARTY_SOURCES} src/impl/servers/Microservice_IRestServerZmqImpl.cpp src/impl/servers/Microservice_IRestServerZmqImpl.h src/common/Microservice_Iface.cpp src/impl/clients/MSICommandClientZmqImpl.cpp src/impl/clients/MSICommandClientZmqImpl.h src/impl/Microservice_ICacheClientPocoImpl.h src/handlers/Microservice_TestHandler.cpp src/handlers/Microservice_TestHandler.h)
target_link_libraries(Microservice ${PROJECT_LINK_LIBS} )
set_target_properties(Microservice PROPERTIES VERSION ${Microservice_VERSION_STRING}
SOVERSION ${Microservice_VERSION_MAJOR})
......
......@@ -20,8 +20,8 @@ RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# app
COPY ./tmp/* /usr/lib/x86_64-linux-gnu/
COPY ./bin/test_Microservice /usr/
COPY ./bin/test_MicroserviceClient /usr/
WORKDIR /usr
ENTRYPOINT ["./test_Microservice"]
ENTRYPOINT ["./test_MicroserviceClient"]
......@@ -38,6 +38,7 @@ Microservice_App::Microservice_App(const char* appName) {
mpc_Configuration = nullptr;
mpc_Logger = nullptr;
mpc_MonitorHandler = nullptr;
p_testHandler_ = nullptr;
mpc_PubSubClient = nullptr;
mpc_ServiceDiscovery = nullptr;
enableMetrics = false;
......@@ -79,7 +80,12 @@ Microservice_App::Microservice_App(const char* appName) {
Microservice_App& Microservice_App::withMonitoring() {
this->mpc_MonitorHandler = new cMicroservice_MonitorHandler();
return addHandler(nsMicroservice_Constants::MON_PREFIX, (Microservice_RestHandler*)mpc_MonitorHandler);
return addHandler(cMicroservice_MonitorHandler::PREFIX, (Microservice_RestHandler*)mpc_MonitorHandler);
}
Microservice_App &Microservice_App::withTesting() {
p_testHandler_ = new Microservice_TestHandler();
return addHandler(Microservice_TestHandler::PREFIX, (Microservice_RestHandler*)p_testHandler_);
}
......@@ -174,6 +180,21 @@ Microservice_App& Microservice_App::addHandler(const char* pba_Prefix, IHandler*
return *this;
}
Microservice_App &Microservice_App::addTest(const char *testName, nsMicroservice_Iface::TestFunction testFunction) {
if (p_testHandler_ == nullptr)
withTesting();
p_testHandler_->addTest(testName,testFunction);
return *this;
}
Microservice_App &Microservice_App::addTest(nsMicroservice_Iface::ITest *p_testClass) {
if (p_testHandler_ == nullptr)
withTesting();
p_testHandler_->addTest(p_testClass);
return *this;
}
/**
*
* @return init ok
......@@ -288,7 +309,8 @@ Microservice_App& Microservice_App::build() {
handler->Init();
// add handler to monitoring
if(this->mpc_MonitorHandler &&
prfxHandler.first.compare(nsMicroservice_Constants::MON_PREFIX) != 0)
( prfxHandler.first.compare(cMicroservice_MonitorHandler::PREFIX) != 0) ||
prfxHandler.first.compare(Microservice_TestHandler::PREFIX) != 0)
{
this->mpc_MonitorHandler->AddHandler(handler);
}
......
......@@ -19,6 +19,7 @@
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <handlers/Microservice_Reactor.h>
#include <handlers/Microservice_TestHandler.h>
#include "Microservice_Client.h"
......@@ -28,6 +29,7 @@ class Microservice_RestHandler;
//class cMicroservice_RestServer;
//class cMicroservice_RMQServer;
class cMicroservice_MonitorHandler;
class Microservice_TestHandler;
using namespace nsMicroservice_Iface;
......@@ -56,6 +58,7 @@ private:
IPubSub* mpc_PubSubClient;
IConfiguration* mpc_Configuration;
cMicroservice_MonitorHandler* mpc_MonitorHandler;
Microservice_TestHandler* p_testHandler_;
IMetricsFactory* p_metricsFactory_;
// servers
// cMicroservice_RestServer* mpc_RestServer;
......@@ -120,7 +123,7 @@ public:
}
Microservice_App& withMonitoring();
Microservice_App& withTesting();
/*************************************************
* ADD SECTION
**************************************************/
......@@ -129,7 +132,8 @@ public:
Microservice_App& addServer(IServer* p_server);
Microservice_App& addClient(cMicroservice_Client *pc_client);
Microservice_App& addHandler(const char* pba_Prefix, IHandler* p_handler);
Microservice_App& addTest(const char* testName, nsMicroservice_Iface::TestFunction testFunction);
Microservice_App& addTest(nsMicroservice_Iface::ITest* p_testClass);
/**************************************************************/
//void AddHandler(const char* pba_Prefix, cMicroservice_BaseHandler* pc_Handler);
......
......@@ -49,7 +49,6 @@ namespace nsMicroservice_Constants
static const char* ERROR_REST_RESPONSE_TEMPLATE_PREFIX = "{ \"success\": false, \"error\": \"";
static const char* ERROR_REST_RESPONSE_TEMPLATE_SUFFIX = "\", \"objectNode\": null ";
static const char* COMMAND_ERROR = "Command Error: ";
static const char* MON_PREFIX = "/_mon";
static const char* LOG_FILE_PATH = "/var/log/mcx/msApp.log";
static const int LOG_FILE_SIZE = 50*1024*1024;
static const char* LOCALHOST = "localhost";
......@@ -59,7 +58,7 @@ namespace nsMicroservice_Constants
static const char *const EXIT_MSG = "exit";
static const int EXIT_MSG_LEN = strlen(EXIT_MSG);
static const int REQUEST_MSG_INITIAL_SIZE = 1024;
static const char *const NOT_IMPLEMENTED = "Not Implemented";
}
/*
......
......@@ -29,6 +29,7 @@ class Microservice_MsgQContext;
class Microservice_PubSubContext;
typedef std::map<std::string, std::deque<std::string> > DequeStringMap;
namespace nsMicroservice_Iface
{
......@@ -157,13 +158,6 @@ namespace nsMicroservice_Iface
virtual const char* getType() final { return TYPE; }
/**
* does it support async internally, if not
* the MSClient will have to provide the async capability
* @return
*/
//virtual bool supportAsync() = 0;
/**
* the create/post of CRUD
* @param p_cmd_params
* @param p_response
......@@ -468,6 +462,12 @@ namespace nsMicroservice_Iface
virtual void Init() {}
};
using TestFunction = std::function<MSRetStat(std::stringstream& output,DequeStringMap& queryParams)>;
using TestsMap = std::map<std::string,TestFunction>;
struct ITest
{
virtual void getAllTests(TestsMap & testsMap) = 0;
};
}
......
......@@ -18,7 +18,6 @@
#include <common/Microservice_Iface.h>
typedef rapidjson::Writer<rapidjson::StringBuffer> JsonStringWriter;
typedef std::map<std::string, std::deque<std::string> > DequeStringMap;
typedef cMicroservice_Enums::eCrudMethod eCrudMethod;
/**
*
......
......@@ -35,6 +35,7 @@ class Microservice_App;
*/
class cMicroservice_MonitorHandler: public virtual Microservice_RestHandler {
public:
static constexpr const char* PREFIX = "/_mon";
cMicroservice_MonitorHandler();
cMicroservice_MonitorHandler(const cMicroservice_MonitorHandler& orig);
virtual ~cMicroservice_MonitorHandler();
......
//
// Created by amir on 19/04/17.
//
#include <Microservice_BaseRestResponse.h>
#include "Microservice_TestHandler.h"
void Microservice_TestHandler::DoCreate(cMicroservice_RequestContext *pc_reqCtx) {
SendErrorResp(pc_reqCtx,nsMicroservice_Constants::NOT_IMPLEMENTED);
}
void Microservice_TestHandler::DoRead(cMicroservice_RequestContext *pc_reqCtx) {
cMicroservice_BaseRestResponse brr;
if(pc_reqCtx->mc_Params.empty()) {
/**
* return all test and names
*/
if (!testsMap_.empty()){
rapidjson::Document& doc = brr.GetObjectNode();
rapidjson::Document::AllocatorType& rpj_Alloc = doc.GetAllocator();
doc.SetArray();
for (auto entry : testsMap_){
doc.PushBack(rapidjson::StringRef(entry.first.c_str()),rpj_Alloc);
}
} else {
brr.SetError("NO TESTS FOR YOU (;-)");
}
} else {
/**
* running specific test
*/
auto funcIterator = testsMap_.find(pc_reqCtx->mc_Params[0]);
if (funcIterator != testsMap_.end()){
std::stringstream ss;
MSRetStat retStat = funcIterator->second(ss,pc_reqCtx->mc_QueryParameters);
if (retStat.IsSuccess()){
rapidjson::Document& doc = brr.GetObjectNode();
rapidjson::Document::AllocatorType& rpj_Alloc = doc.GetAllocator();
doc.SetObject();
doc.AddMember(rapidjson::StringRef(funcIterator->first.c_str()),rapidjson::StringRef(ss.str().c_str()),rpj_Alloc);
} else {
ss.clear();
ss << "Test Failed: " << retStat.GetError().c_str();
brr.SetError(ss.str().c_str());
}
}
}
WriteObjectToResponse(pc_reqCtx,brr);
}
void Microservice_TestHandler::DoUpdate(cMicroservice_RequestContext *pc_reqCtx) {
SendErrorResp(pc_reqCtx,nsMicroservice_Constants::NOT_IMPLEMENTED);
}
void Microservice_TestHandler::DoDelete(cMicroservice_RequestContext *pc_reqCtx) {
SendErrorResp(pc_reqCtx,nsMicroservice_Constants::NOT_IMPLEMENTED);
}
void Microservice_TestHandler::Init() {
}
void Microservice_TestHandler::addTest(nsMicroservice_Iface::ITest *p_testClass) {
if (p_testClass)
p_testClass->getAllTests(testsMap_);
}
void Microservice_TestHandler::addTest(std::string testName, nsMicroservice_Iface::TestFunction &testFunction) {
if (!testName.empty() && testFunction != nullptr)
testsMap_[testName] = testFunction;
}
//
// Created by amir on 19/04/17.
//
#ifndef MICROSERVICE_MICROSERVICE_TESTHANDLER_H
#define MICROSERVICE_MICROSERVICE_TESTHANDLER_H
#include "Microservice_RestHandler.h"
/**
* @author amir
* @brief handler used to perform test when the microservice is running with
* it's rest interface
*/
class Microservice_TestHandler : public virtual Microservice_RestHandler{
public:
static constexpr const char* PREFIX = "/_tests";
void DoCreate(cMicroservice_RequestContext *pc_reqCtx) override;
void DoRead(cMicroservice_RequestContext *pc_reqCtx) override;
void DoUpdate(cMicroservice_RequestContext *pc_reqCtx) override;
void DoDelete(cMicroservice_RequestContext *pc_reqCtx) override;
void Init() override;
void addTest(nsMicroservice_Iface::ITest* p_testClass);
void addTest(std::string testName,nsMicroservice_Iface::TestFunction& testFunction);
private:
nsMicroservice_Iface::TestsMap testsMap_;
};
#endif //MICROSERVICE_MICROSERVICE_TESTHANDLER_H
......@@ -21,7 +21,15 @@ using namespace nsMicroservice_Iface;
using OnResponseFunc = std::function<void(const char* p_response, int len, std::uint32_t cmndId)>;
/**
* @brief RestCleient over ZMQ:
* Impelmenting by using 2 zmq sockets, one for send and one for receive
* also using a cache for storing the callbacks for the requests
* because the async mechanism of the microservice client is build upon an
* async task over a blocking operation.
* to achieve that i used a conditional with mutex to create a blocking operation
* that orchestrate the send/receive sockets
*/
class MSICommandClientZmqImpl : public ICommandClient {
struct RcidParts {
......@@ -85,8 +93,6 @@ private:
void DelegateRestResponse(cMicroservice_BaseRestResponse *p_RestResponse, uint32_t cmndId);
void HandleCommandAndCallback(ICommandClient::HttpCommandDataPtr &cmdDataPtr,common::context::CrudMethod crudMethod);
//public:
// bool supportAsync() override { return true; }
};
......
......@@ -191,7 +191,7 @@ void Microservice_IRestServerZmqImpl::HandleNewRequest(Microservice_IRestServerZ
void Microservice_IRestServerZmqImpl::SendNotImplemented(Microservice_IRestServerZmqImpl::RequestWorkParams *p_rwp) {
SendErrorResp(&p_rwp->restResponseImpl_,"Not Implemented");
SendErrorResp(&p_rwp->restResponseImpl_, nsMicroservice_Constants::NOT_IMPLEMENTED);
}
MSRetStat Microservice_IRestServerZmqImpl::ParseRequest(Microservice_IRestServerZmqImpl::RequestWorkParams *p_rwp,
......
......@@ -8,6 +8,7 @@
static const int HIGH_WATER_MARK = 10000;
#include <common/Microservice_Iface.h>
#include <zmqpp/socket.hpp>
#include <params/Microservice_Params.h>
......
......@@ -335,7 +335,6 @@ void runRestZmqTest(){
std::string appName("myZmqService");
Microservice_App msApp(appName.c_str());
/**
* Start server
*/
......@@ -344,19 +343,25 @@ void runRestZmqTest(){
.withMonitoring() // need to add reload
.withPubSub(NULL)
.withServiceDiscovery(NULL)
.addServer(ServerFactory::createIRestServerCivetWebImpl("", 50010, 1))
.addServer(ServerFactory::createIRestServerZmqImpl("serverApp",0,Microservice_ZMQServerParams::eProtocol::eIpc))
.addTest("SendZmqRestRequests", [&msApp,&appName](std::stringstream& output,DequeStringMap& queryParams) -> MSRetStat {
auto p_zmqClient = ClientFactory::createZmqCommandImpl(appName,"clientApp", 0,"serverApp", 0,Microservice_ZMQServerParams::eProtocol::eIpc);
output <<" Testing " << ITERATIONS << " SendZmqRestRequests took: " << CommonUtils::measureFunc<>(SendZmqRestRequests,msApp, p_zmqClient) << "msec" << '\n';
return MSRetStat();
})
.addTest("testCaches",[&msApp,&appName](std::stringstream& output,DequeStringMap& queryParams) -> MSRetStat {
Poco::ExpireCache<uint64_t , string> cache;
output<<" Testing " << ITERATIONS << " testCaches took: " << CommonUtils::measureFunc<>(testPoco,cache) << "msec" << '\n';
output <<" Testing " << ITERATIONS << " testMap took: " << CommonUtils::measureFunc<>(testMap) << "msec" << '\n';
return MSRetStat();
})
.build();
/**
* start client
*/
msApp.GetLogger()->setLevel(cMicroservice_Enums::eError);
auto p_zmqClient = ClientFactory::createZmqCommandImpl(appName,"clientApp", 0,"serverApp", 0,Microservice_ZMQServerParams::eProtocol::eIpc);
auto p_clientSendThread_ = new std::thread(std::bind([p_zmqClient,&msApp](){
std::cout <<" Testing " << ITERATIONS << " testCaches took: " << CommonUtils::measureFunc<>(SendZmqRestRequests,msApp, p_zmqClient) << "msec" << '\n';
}));
msApp.run();
getchar();
}
......@@ -402,7 +407,7 @@ void SendZmqRestRequests(const Microservice_App &msApp, cMicroservice_Client *p_
int main(int argc, char *argv[])
{
runRestZmqTest();
//testCaches();
// testCaches();
// testJsons();
//runTest();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment