Refactored and cleaned implementation for rm()

Unrelated tests are commented out firsts
temporary method, such as getV3, are done to be able to do the original UT replication.
This commit is contained in:
lampayan 2016-06-08 11:11:50 +02:00
parent 98e2b57ed4
commit 62d4984e71
12 changed files with 429 additions and 364 deletions

View File

@ -0,0 +1,26 @@
/*
* AsyncDeleteResponse.h
*
* Created on: Jun 7, 2016
* Author: ubuntu
*/
#ifndef SRC_ASYNCDELETERESPONSE_H_
#define SRC_ASYNCDELETERESPONSE_H_
#include "etcd/BaseResponse.h"
namespace etcd {
class AsyncDeleteResponse : public etcd::BaseResponse {
public:
AsyncDeleteResponse();
virtual ~AsyncDeleteResponse();
void fillUpV2ResponseValues(etcdserverpb::RangeResponse);
etcdserverpb::DeleteRangeResponse deleteResponse;
std::unique_ptr<grpc::ClientAsyncResponseReader<etcdserverpb::DeleteRangeResponse>> rpcInstance;
};
}
#endif /* SRC_ASYNCDELETERESPONSE_H_ */

26
etcd/BaseResponse.h Normal file
View File

@ -0,0 +1,26 @@
/*
* BaseResponse.h
*
* Created on: Jun 7, 2016
* Author: ubuntu
*/
#ifndef SRC_BASERESPONSE_H_
#define SRC_BASERESPONSE_H_
#include "etcd/Response.hpp"
#include "proto/rpc.grpc.pb.h"
namespace etcd {
class BaseResponse : public etcd::Response {
public:
//TODO: turn into a abstract class
BaseResponse();
virtual ~BaseResponse();
grpc::Status status;
grpc::ClientContext context;
grpc::CompletionQueue cq_;
};
}
#endif /* SRC_BASERESPONSE_H_ */

View File

@ -8,6 +8,8 @@
#include <grpc++/grpc++.h> #include <grpc++/grpc++.h>
#include "proto/rpc.grpc.pb.h" #include "proto/rpc.grpc.pb.h"
#include "etcd/DeleteRpcResponse.h"
#include "etcd/AsyncDeleteResponse.h"
using grpc::Channel; using grpc::Channel;
using grpc::ClientAsyncResponseReader; using grpc::ClientAsyncResponseReader;
@ -159,7 +161,10 @@ namespace etcd
std::unique_ptr<Watch::Stub> watchServiceStub; std::unique_ptr<Watch::Stub> watchServiceStub;
pplx::task<etcd::Response> send_put(const std::string& key, const std::string& value); pplx::task<etcd::Response> send_put(const std::string& key, const std::string& value);
pplx::task<etcd::Response> send_get(std::string const & key); pplx::task<etcd::Response> send_get(std::string const & key);
};
private:
void getEntryForPreviousValue(const std::string& entryKey, etcd::AsyncDeleteResponse* drp);
};
class AsyncPutResponse class AsyncPutResponse
{ {

View File

@ -5,24 +5,26 @@
* Author: ubuntu * Author: ubuntu
*/ */
#ifndef SRC_DELETERPCRESPONSE_H_ //#ifndef SRC_DELETERPCRESPONSE_H_
#define SRC_DELETERPCRESPONSE_H_ //#define SRC_DELETERPCRESPONSE_H_
//
#include "etcd/Response.hpp" //#include "etcd/Response.hpp"
#include "proto/rpc.grpc.pb.h" //#include "proto/rpc.grpc.pb.h"
//
namespace etcd { //namespace etcd {
class DeleteRpcResponse : public etcd::Response, public etcd::Value { //class DeleteRpcResponse : public etcd::Response, public etcd::Value {
public: //public:
DeleteRpcResponse(); // DeleteRpcResponse();
virtual ~DeleteRpcResponse(); // virtual ~DeleteRpcResponse();
void fillUpV2ResponseValues(etcdserverpb::RangeResponse); // void fillUpV2ResponseValues(etcdserverpb::RangeResponse);
//
etcdserverpb::DeleteRangeResponse deleteResponse; // etcdserverpb::DeleteRangeResponse deleteResponse;
grpc::Status status; //
grpc::ClientContext context; // grpc::Status status;
grpc::CompletionQueue cq_; // grpc::ClientContext context;
std::unique_ptr<grpc::ClientAsyncResponseReader<etcdserverpb::DeleteRangeResponse>> rpcInstance; // grpc::CompletionQueue cq_;
}; //
} // std::unique_ptr<grpc::ClientAsyncResponseReader<etcdserverpb::DeleteRangeResponse>> rpcInstance;
#endif /* SRC_DELETERPCRESPONSE_H_ */ //};
//}
//#endif /* SRC_DELETERPCRESPONSE_H_ */

View File

@ -20,9 +20,7 @@ namespace etcd
public: public:
static pplx::task<Response> create(pplx::task<web::http::http_response> response_task); static pplx::task<Response> create(pplx::task<web::http::http_response> response_task);
//parang mas magandang ilagay ito sa baseclass imbis na here ooorrr template<typename T>static pplx::task<etcd::Response> createV2Response(T call)
//talagang response v2 lang talaga dito
template<typename T>static pplx::task<etcd::Response> create(T call)
{ {
return pplx::task<etcd::Response>([call]() return pplx::task<etcd::Response>([call]()
{ {
@ -39,7 +37,7 @@ namespace etcd
if(call->status.ok()) if(call->status.ok())
{ {
// auto v3resp = call->ParseResponse(); // auto v3resp = call->ParseResponse();
resp = *call;// stripping off instead of creating a new response class resp = *call;// stripping off instead of creating a new response class object
} }
else else
{ {

View File

@ -41,7 +41,9 @@ namespace etcd
protected: protected:
friend class Response; friend class Response;
friend class BaseResponse; //deliberately done since Value class will be removed during full V3
friend class DeleteRpcResponse; friend class DeleteRpcResponse;
friend class AsyncDeleteResponse;
Value(); Value();
Value(web::json::value const & json_value); Value(web::json::value const & json_value);
std::string _key; std::string _key;

View File

@ -0,0 +1,21 @@
/*
* AsyncDeleteResponse.cpp
*
* Created on: Jun 7, 2016
* Author: ubuntu
*/
#include "etcd/AsyncDeleteResponse.h"
etcd::AsyncDeleteResponse::AsyncDeleteResponse() {
// TODO Auto-generated constructor stub
}
etcd::AsyncDeleteResponse::~AsyncDeleteResponse() {
// TODO Auto-generated destructor stub
}
void etcd::AsyncDeleteResponse::fillUpV2ResponseValues(etcdserverpb::RangeResponse getResponse) {
_prev_value.value = getResponse.kvs().Get(0).value();
_action = "delete";
}

17
src/BaseResponse.cpp Normal file
View File

@ -0,0 +1,17 @@
/*
* BaseResponse.cpp
*
* Created on: Jun 7, 2016
* Author: ubuntu
*/
#include "etcd/BaseResponse.h"
etcd::BaseResponse::BaseResponse() {
// TODO Auto-generated constructor stub
}
etcd::BaseResponse::~BaseResponse() {
// TODO Auto-generated destructor stub
}

View File

@ -1,4 +1,4 @@
add_library(etcd-cpp-api SHARED ../proto/kv.pb.cc ../proto/auth.pb.cc ../proto/rpc.pb.cc ../proto/rpc.grpc.pb.cc Client.cpp Response.cpp Value.cpp json_constants.cpp DeleteRpcResponse.cpp) add_library(etcd-cpp-api SHARED ../proto/kv.pb.cc ../proto/auth.pb.cc ../proto/rpc.pb.cc ../proto/rpc.grpc.pb.cc Client.cpp Response.cpp Value.cpp json_constants.cpp BaseResponse.cpp AsyncDeleteResponse.cpp)
set_property(TARGET etcd-cpp-api PROPERTY CXX_STANDARD 11) set_property(TARGET etcd-cpp-api PROPERTY CXX_STANDARD 11)
target_link_libraries(etcd-cpp-api ${CPPREST_LIB} boost_system ssl crypto protobuf grpc++) target_link_libraries(etcd-cpp-api ${CPPREST_LIB} boost_system ssl crypto protobuf grpc++)

View File

@ -2,6 +2,7 @@
#include <iostream> #include <iostream>
#include "etcd/DeleteRpcResponse.h" #include "etcd/DeleteRpcResponse.h"
#include "etcd/AsyncDeleteResponse.h"
etcd::Client::Client(std::string const & address) etcd::Client::Client(std::string const & address)
: client(address) : client(address)
@ -45,9 +46,9 @@ pplx::task<etcd::Response> etcd::Client::set(std::string const & key, std::strin
return send_put(key,value); return send_put(key,value);
} }
//TODO: a temporary set, until set version 3 is implemented
void etcd::Client::setv3(std::string const &key, std::string const &value) void etcd::Client::setv3(std::string const &key, std::string const &value)
{ {
std::cout << "FBDL setv3" << std::endl;
etcdserverpb::PutRequest putRequest; etcdserverpb::PutRequest putRequest;
putRequest.set_key(key); putRequest.set_key(key);
putRequest.set_value(value); putRequest.set_value(value);
@ -93,31 +94,25 @@ pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std:
return send_put_request(uri, "value", value); return send_put_request(uri, "value", value);
} }
pplx::task<etcd::Response> etcd::Client::removeEntry(std::string const & entryKey) { void etcd::Client::getEntryForPreviousValue(const std::string& entryKey, etcd::AsyncDeleteResponse* drp)
{
etcd::DeleteRpcResponse *drp = new etcd::DeleteRpcResponse();
//get muna
std::cout<<"blocking call for get rpc first " << entryKey << std::endl;
etcdserverpb::RangeRequest rangeRequest; etcdserverpb::RangeRequest rangeRequest;
rangeRequest.set_key(entryKey); rangeRequest.set_key(entryKey);
etcdserverpb::RangeResponse rangeResponse; etcdserverpb::RangeResponse rangeResponse;
grpc::ClientContext context; grpc::ClientContext context;
grpc::Status status = stub_->Range(&context, rangeRequest, &rangeResponse); grpc::Status status = stub_->Range(&context, rangeRequest, &rangeResponse);
if (status.ok()) {
if(status.ok()) {
std::cout << "get OK" << std::endl; std::cout << "get OK" << std::endl;
drp->fillUpV2ResponseValues(rangeResponse); drp->fillUpV2ResponseValues(rangeResponse);
} } else {
else {
std::cout << "get NOK" << std::endl; std::cout << "get NOK" << std::endl;
} }
}
pplx::task<etcd::Response> etcd::Client::removeEntry(std::string const & entryKey) {
//then delete etcd::AsyncDeleteResponse *drp = new etcd::AsyncDeleteResponse();
std::cout << "removing etcd v3 entry naman with template na" << std::endl; getEntryForPreviousValue(entryKey, drp); //TODO: failure case scenario handling
etcdserverpb::DeleteRangeRequest deleteRangeRequest; etcdserverpb::DeleteRangeRequest deleteRangeRequest;
deleteRangeRequest.set_key(entryKey); deleteRangeRequest.set_key(entryKey);
@ -125,32 +120,7 @@ pplx::task<etcd::Response> etcd::Client::removeEntry(std::string const & entryKe
drp->rpcInstance = stub_->AsyncDeleteRange(&drp->context, deleteRangeRequest, &drp->cq_); drp->rpcInstance = stub_->AsyncDeleteRange(&drp->context, deleteRangeRequest, &drp->cq_);
drp->rpcInstance->Finish(&drp->deleteResponse, &drp->status, (void*)drp); drp->rpcInstance->Finish(&drp->deleteResponse, &drp->status, (void*)drp);
return Response::create(drp); return Response::createV2Response(drp);
// return pplx::task<etcd::Response>([drp]()
// {
// std::cout << "doing delete v3 entry task" << std::endl;
// void* got_tag;
// bool ok = false;
// etcd::Response resp;
//
// drp->completionQueue.Next(&got_tag, &ok);
// GPR_ASSERT(got_tag == (void*)drp);
// GPR_ASSERT(ok);
//
// etcd::DeleteRpcResponse* deleteResponse = static_cast<etcd::DeleteRpcResponse*>(got_tag);
//
// if (deleteResponse->status.ok()){
// std::cout << "doing delete v3 entry task OK" << std::endl;
// resp = *drp; //simply stripping off the response part
// }
// else
// std::cout << "doing delete v3 entry task NOK" << std::endl;
// delete deleteResponse;
// std::cout << "delete done, returning" << std::endl;
// return resp;
// }
// );
} }
@ -173,7 +143,7 @@ void etcd::Client::getv3(std::string const & key) {
std::cout << "kvs 0 value: " << rangeResponse.kvs(0).value() << std::endl; std::cout << "kvs 0 value: " << rangeResponse.kvs(0).value() << std::endl;
std::cout << "kvs.Get 0 value: " << rangeResponse.kvs().Get(0).value() << std::endl; std::cout << "kvs.Get 0 value: " << rangeResponse.kvs().Get(0).value() << std::endl;
DeleteRpcResponse drp; AsyncDeleteResponse drp;
drp.fillUpV2ResponseValues(rangeResponse); drp.fillUpV2ResponseValues(rangeResponse);
} }
else { else {

View File

@ -5,35 +5,34 @@
* Author: ubuntu * Author: ubuntu
*/ */
#include "etcd/DeleteRpcResponse.h" //#include "etcd/DeleteRpcResponse.h"
#include <iostream> //#include <iostream>
etcd::DeleteRpcResponse::DeleteRpcResponse() {
// TODO Auto-generated constructor stub
}
etcd::DeleteRpcResponse::~DeleteRpcResponse() {
// TODO Auto-generated destructor stub
}
//prototype in handling the response object
void etcd::DeleteRpcResponse::fillUpV2ResponseValues(etcdserverpb::RangeResponse getResponse) {
std::cout << "inside fillup attempting fillupv2 response values" << std::endl;
std::cout << "setting the value of: " << getResponse.kvs().Get(0).value() << std::endl;
_prev_value.value = getResponse.kvs().Get(0).value();
_action = "delete";
// //the experiments done on how to fill up the field of this object.
// //access the fields na protected sa Value
// this->Value::value = "yeah";
// std::cout << "pre contents: " << this->_value.as_string() << std::endl;
// //
// //or create an instance here and return it filled up //etcd::DeleteRpcResponse::DeleteRpcResponse() {
// DeleteRpcResponse r; // // TODO Auto-generated constructor stub
// r.Value::value = "yo!";
// this->_value = r; //strip off value part
// //
// std::cout << "contents: " << this->_value.as_string() << std::endl; //}
} //
//etcd::DeleteRpcResponse::~DeleteRpcResponse() {
// // TODO Auto-generated destructor stub
//}
//
//void etcd::DeleteRpcResponse::fillUpV2ResponseValues(etcdserverpb::RangeResponse getResponse) {
// std::cout << "inside fillup attempting fillupv2 response values" << std::endl;
//
// std::cout << "setting the value of: " << getResponse.kvs().Get(0).value() << std::endl;
// _prev_value.value = getResponse.kvs().Get(0).value();
// _action = "delete";
//
//// //the experiments done on how to fill up the field of this object.
//// //access the fields na protected sa Value
//// this->Value::value = "yeah";
//// std::cout << "pre contents: " << this->_value.as_string() << std::endl;
////
//// //or create an instance here and return it filled up
//// DeleteRpcResponse r;
//// r.Value::value = "yo!";
//// this->_value = r; //strip off value part
////
//// std::cout << "contents: " << this->_value.as_string() << std::endl;
//}

View File

@ -3,287 +3,286 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
TEST_CASE("setup") //TEST_CASE("setup")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd.rmdir("/test", true).wait();
}
TEST_CASE("add a new key")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd::Response resp = etcd.add("/test/key1", "42").get();
REQUIRE(0 == resp.error_code());
CHECK("create" == resp.action());
etcd::Value const & val = resp.value();
CHECK("42" == val.as_string());
CHECK("/test/key1" == val.key());
CHECK(!val.is_dir());
CHECK(0 < val.created_index());
CHECK(0 < val.modified_index());
CHECK(0 < resp.index()); // X-Etcd-Index header value
CHECK(105 == etcd.add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(105 == etcd.add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd.add("/test/key1", "42").get().error_message());
}
TEST_CASE("read a value from etcd")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd::Response resp = etcd.get("/test/key1").get();
CHECK("get" == resp.action());
REQUIRE(resp.is_ok());
REQUIRE(0 == resp.error_code());
CHECK("42" == resp.value().as_string());
CHECK("" == etcd.get("/test").get().value().as_string()); // key points to a directory
}
TEST_CASE("simplified read")
{
etcd::Client etcd("http://127.0.0.1:4001");
CHECK("42" == etcd.get("/test/key1").get().value().as_string());
std::cout << "get error code kahit success: " << etcd.get("/test/key1").get().error_code() << std::endl;
CHECK(100 == etcd.get("/test/key2").get().error_code()); // Key not found
}
TEST_CASE("modify a key")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd::Response resp = etcd.modify("/test/key1", "43").get();
REQUIRE(0 == resp.error_code()); // overwrite
CHECK("update" == resp.action());
CHECK(100 == etcd.modify("/test/key2", "43").get().error_code()); // Key not found
CHECK("43" == etcd.modify("/test/key1", "42").get().prev_value().as_string());
}
//TEST_CASE("set a key")
//{ //{
// etcd::Client etcd("http://127.0.0.1:4001"); // etcd::Client etcd("http://127.0.0.1:4001");
// etcd::Response resp = etcd.set("/test/key1", "43").get(); // etcd.rmdir("/test", true).wait();
// REQUIRE(0 == resp.error_code()); // overwrite
// CHECK("set" == resp.action());
// CHECK(0 == etcd.set("/test/key2", "43").get().error_code()); // create new
// CHECK("43" == etcd.set("/test/key2", "44").get().prev_value().as_string());
// CHECK("" == etcd.set("/test/key3", "44").get().prev_value().as_string());
// CHECK(102 == etcd.set("/test", "42").get().error_code()); // Not a file
//} //}
// //
//FBDL rm naman //TEST_CASE("add a new key")
//TEST_CASE("delete a value")
//{ //{
// std::cout << "FBDL do a delete via rm only" <<std::endl;
// etcd::Client etcd("http://127.0.0.1:4001"); // etcd::Client etcd("http://127.0.0.1:4001");
// CHECK(3 == etcd.ls("/test").get().keys().size()); // etcd::Response resp = etcd.add("/test/key1", "42").get();
// // REQUIRE(0 == resp.error_code());
// std::cout << "FBDL invoking rm in test" <<std::endl; // CHECK("create" == resp.action());
// etcd::Response resp = etcd.rm("/test/key1").get(); // etcd::Value const & val = resp.value();
// CHECK("43" == resp.prev_value().as_string()); // CHECK("42" == val.as_string());
// CHECK("delete" == resp.action()); // CHECK("/test/key1" == val.key());
// CHECK(2 == etcd.ls("/test").get().keys().size()); // CHECK(!val.is_dir());
// CHECK(0 < val.created_index());
// CHECK(0 < val.modified_index());
// CHECK(0 < resp.index()); // X-Etcd-Index header value
// CHECK(105 == etcd.add("/test/key1", "43").get().error_code()); // Key already exists
// CHECK(105 == etcd.add("/test/key1", "42").get().error_code()); // Key already exists
// CHECK("Key already exists" == etcd.add("/test/key1", "42").get().error_message());
//} //}
//
//TEST_CASE("read a value from etcd")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// etcd::Response resp = etcd.get("/test/key1").get();
// CHECK("get" == resp.action());
// REQUIRE(resp.is_ok());
// REQUIRE(0 == resp.error_code());
// CHECK("42" == resp.value().as_string());
//
// CHECK("" == etcd.get("/test").get().value().as_string()); // key points to a directory
//}
//
//TEST_CASE("simplified read")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// CHECK("42" == etcd.get("/test/key1").get().value().as_string());
// std::cout << "get error code kahit success: " << etcd.get("/test/key1").get().error_code() << std::endl;
// CHECK(100 == etcd.get("/test/key2").get().error_code()); // Key not found
//}
//
//TEST_CASE("modify a key")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// etcd::Response resp = etcd.modify("/test/key1", "43").get();
// REQUIRE(0 == resp.error_code()); // overwrite
// CHECK("update" == resp.action());
// CHECK(100 == etcd.modify("/test/key2", "43").get().error_code()); // Key not found
// CHECK("43" == etcd.modify("/test/key1", "42").get().prev_value().as_string());
//}
//
////TEST_CASE("set a key")
////{
//// etcd::Client etcd("http://127.0.0.1:4001");
//// etcd::Response resp = etcd.set("/test/key1", "43").get();
//// REQUIRE(0 == resp.error_code()); // overwrite
//// CHECK("set" == resp.action());
//// CHECK(0 == etcd.set("/test/key2", "43").get().error_code()); // create new
//// CHECK("43" == etcd.set("/test/key2", "44").get().prev_value().as_string());
//// CHECK("" == etcd.set("/test/key3", "44").get().prev_value().as_string());
//// CHECK(102 == etcd.set("/test", "42").get().error_code()); // Not a file
////}
////
////FBDL rm naman
////TEST_CASE("delete a value")
////{
//// std::cout << "FBDL do a delete via rm only" <<std::endl;
//// etcd::Client etcd("http://127.0.0.1:4001");
//// CHECK(3 == etcd.ls("/test").get().keys().size());
////
//// std::cout << "FBDL invoking rm in test" <<std::endl;
//// etcd::Response resp = etcd.rm("/test/key1").get();
//// CHECK("43" == resp.prev_value().as_string());
//// CHECK("delete" == resp.action());
//// CHECK(2 == etcd.ls("/test").get().keys().size());
////}
TEST_CASE("delete a value V3") TEST_CASE("delete a value V3 representation")
{ {
std::cout << "FBDL do a delete via rm only V3" <<std::endl;
etcd::Client etcd("http://127.0.0.1:4001"); etcd::Client etcd("http://127.0.0.1:4001");
etcd.setv3("test/key1", "42"); //temporary get etcd.setv3("test/key1", "42");
etcd::Response resp = etcd.rm("test/key1").get(); etcd::Response resp = etcd.rm("test/key1").get();
CHECK("42" == resp.prev_value().as_string()); CHECK("42" == resp.prev_value().as_string());
CHECK("delete" == resp.action()); CHECK("delete" == resp.action());
} }
TEST_CASE("create a directory") //TEST_CASE("create a directory")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd::Response resp = etcd.mkdir("/test/new_dir").get();
CHECK("set" == resp.action());
CHECK(resp.value().is_dir());
}
TEST_CASE("list a directory")
{
etcd::Client etcd("http://127.0.0.1:4001");
CHECK(0 == etcd.ls("/test/new_dir").get().keys().size());
etcd.set("/test/new_dir/key1", "value1").wait();
etcd.set("/test/new_dir/key2", "value2").wait();
etcd.mkdir("/test/new_dir/sub_dir").wait();
etcd::Response resp = etcd.ls("/test/new_dir").get();
CHECK("get" == resp.action());
REQUIRE(3 == resp.keys().size());
CHECK("key1" == resp.key(0));
CHECK("key2" == resp.key(1));
CHECK("sub_dir" == resp.key(2));
CHECK("value1" == resp.value(0).as_string());
CHECK("value2" == resp.value(1).as_string());
CHECK(resp.values()[2].is_dir());
CHECK(0 == etcd.ls("/test/new_dir/key1").get().error_code());
}
TEST_CASE("delete a directory")
{
etcd::Client etcd("http://127.0.0.1:4001");
CHECK(108 == etcd.rmdir("/test/new_dir").get().error_code()); // Directory not empty
CHECK(0 == etcd.rmdir("/test/new_dir", true).get().error_code());
}
TEST_CASE("wait for a value change")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd.set("/test/key1", "42").wait();
pplx::task<etcd::Response> res = etcd.watch("/test/key1");
CHECK(!res.is_done());
sleep(1);
CHECK(!res.is_done());
etcd.set("/test/key1", "43").get();
sleep(1);
REQUIRE(res.is_done());
REQUIRE("set" == res.get().action());
CHECK("43" == res.get().value().as_string());
}
//FBDL: first watch
//TEST_CASE("FBDL wait for a value change")
//{ //{
// std::cout << "FBDL wait for a value change" << std::endl;
// etcd::Client etcd("http://127.0.0.1:4001"); // etcd::Client etcd("http://127.0.0.1:4001");
//// etcd.set("/test/key1", "42").wait(); // etcd::Response resp = etcd.mkdir("/test/new_dir").get();
// etcd.setv3("test/key1", "42"); // CHECK("set" == resp.action());
// // CHECK(resp.value().is_dir());
//// pplx::task<etcd::Response> res = etcd.watch("/test/key1"); //}
//// CHECK(!res.is_done()); //
//// sleep(1); //TEST_CASE("list a directory")
//// CHECK(!res.is_done()); //{
//// CHECK("42" == etcd.get("/test/key1").get().value().as_string()); // etcd::Client etcd("http://127.0.0.1:4001");
//// // CHECK(0 == etcd.ls("/test/new_dir").get().keys().size());
//// etcd.set("/test/key1", "43").get(); //
//// sleep(1); // etcd.set("/test/new_dir/key1", "value1").wait();
//// REQUIRE(res.is_done()); // etcd.set("/test/new_dir/key2", "value2").wait();
//// REQUIRE("set" == res.get().action()); // etcd.mkdir("/test/new_dir/sub_dir").wait();
//// CHECK("43" == res.get().value().as_string()); //
//// CHECK("43" == etcd.get("/test/key1").get().value().as_string()); // etcd::Response resp = etcd.ls("/test/new_dir").get();
// CHECK("get" == resp.action());
// REQUIRE(3 == resp.keys().size());
// CHECK("key1" == resp.key(0));
// CHECK("key2" == resp.key(1));
// CHECK("sub_dir" == resp.key(2));
// CHECK("value1" == resp.value(0).as_string());
// CHECK("value2" == resp.value(1).as_string());
// CHECK(resp.values()[2].is_dir());
//
// CHECK(0 == etcd.ls("/test/new_dir/key1").get().error_code());
//}
//
//TEST_CASE("delete a directory")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// CHECK(108 == etcd.rmdir("/test/new_dir").get().error_code()); // Directory not empty
// CHECK(0 == etcd.rmdir("/test/new_dir", true).get().error_code());
//}
//
//TEST_CASE("wait for a value change")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// etcd.set("/test/key1", "42").wait();
//
// pplx::task<etcd::Response> res = etcd.watch("/test/key1");
// CHECK(!res.is_done());
// sleep(1);
// CHECK(!res.is_done());
//
// etcd.set("/test/key1", "43").get();
// sleep(1);
// REQUIRE(res.is_done());
// REQUIRE("set" == res.get().action());
// CHECK("43" == res.get().value().as_string());
//}
//
////FBDL: first watch
////TEST_CASE("FBDL wait for a value change")
////{
//// std::cout << "FBDL wait for a value change" << std::endl;
//// etcd::Client etcd("http://127.0.0.1:4001");
////// etcd.set("/test/key1", "42").wait();
//// etcd.setv3("test/key1", "42");
////
////// pplx::task<etcd::Response> res = etcd.watch("/test/key1");
////// CHECK(!res.is_done());
////// sleep(1);
////// CHECK(!res.is_done());
////// CHECK("42" == etcd.get("/test/key1").get().value().as_string());
//////
////// etcd.set("/test/key1", "43").get();
////// sleep(1);
////// REQUIRE(res.is_done());
////// REQUIRE("set" == res.get().action());
////// CHECK("43" == res.get().value().as_string());
////// CHECK("43" == etcd.get("/test/key1").get().value().as_string());
////}
//
//TEST_CASE("wait for a directory change")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
//
// pplx::task<etcd::Response> res = etcd.watch("/test", true);
// CHECK(!res.is_done());
// sleep(1);
// CHECK(!res.is_done());
//
// etcd.add("/test/key4", "44").wait();
// sleep(1);
// REQUIRE(res.is_done());
// CHECK("create" == res.get().action());
// CHECK("44" == res.get().value().as_string());
//
// pplx::task<etcd::Response> res2 = etcd.watch("/test", true);
// CHECK(!res2.is_done());
// sleep(1);
// CHECK(!res2.is_done());
//
// etcd.set("/test/key4", "45").wait();
// REQUIRE(res2.is_done());
// CHECK("set" == res2.get().action());
// CHECK("45" == res2.get().value().as_string());
//}
//
//TEST_CASE("watch changes in the past")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
//
// int index = etcd.set("/test/key1", "42").get().index();
//
// etcd.set("/test/key1", "43").wait();
// etcd.set("/test/key1", "44").wait();
// etcd.set("/test/key1", "45").wait();
//
// etcd::Response res = etcd.watch("/test/key1", ++index).get();
// CHECK("set" == res.action());
// CHECK("43" == res.value().as_string());
//
// res = etcd.watch("/test/key1", ++index).get();
// CHECK("set" == res.action());
// CHECK("44" == res.value().as_string());
//
// res = etcd.watch("/test", ++index, true).get();
// CHECK("set" == res.action());
// CHECK("45" == res.value().as_string());
//}
//
//TEST_CASE("atomic compare-and-swap")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// etcd.set("/test/key1", "42").wait();
//
// // modify success
// etcd::Response res = etcd.modify_if("/test/key1", "43", "42").get();
// int index = res.index();
// REQUIRE(res.is_ok());
// CHECK("compareAndSwap" == res.action());
// CHECK("43" == res.value().as_string());
//
// // modify fails the second time
// res = etcd.modify_if("/test/key1", "44", "42").get();
// CHECK(!res.is_ok());
// CHECK(101 == res.error_code());
// CHECK("Compare failed" == res.error_message());
//
// // succes with the correct index
// res = etcd.modify_if("/test/key1", "44", index).get();
// REQUIRE(res.is_ok());
// CHECK("compareAndSwap" == res.action());
// CHECK("44" == res.value().as_string());
//
// // index changes so second modify fails
// res = etcd.modify_if("/test/key1", "45", index).get();
// CHECK(!res.is_ok());
// CHECK(101 == res.error_code());
// CHECK("Compare failed" == res.error_message());
//}
//
//TEST_CASE("atomic compare-and-delete based on prevValue")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// etcd.set("/test/key1", "42").wait();
//
// etcd::Response res = etcd.rm_if("/test/key1", "43").get();
// CHECK(!res.is_ok());
// CHECK(101 == res.error_code());
// CHECK("Compare failed" == res.error_message());
//
// res = etcd.rm_if("/test/key1", "42").get();
// REQUIRE(res.is_ok());
// CHECK("compareAndDelete" == res.action());
// CHECK("42" == res.prev_value().as_string());
//}
//
//TEST_CASE("atomic compare-and-delete based on prevIndex")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// int index = etcd.set("/test/key1", "42").get().index();
//
// etcd::Response res = etcd.rm_if("/test/key1", index - 1).get();
// CHECK(!res.is_ok());
// CHECK(101 == res.error_code());
// CHECK("Compare failed" == res.error_message());
//
// res = etcd.rm_if("/test/key1", index).get();
// REQUIRE(res.is_ok());
// CHECK("compareAndDelete" == res.action());
// CHECK("42" == res.prev_value().as_string());
//}
//
//TEST_CASE("cleanup")
//{
// etcd::Client etcd("http://127.0.0.1:4001");
// REQUIRE(0 == etcd.rmdir("/test", true).get().error_code());
//} //}
TEST_CASE("wait for a directory change")
{
etcd::Client etcd("http://127.0.0.1:4001");
pplx::task<etcd::Response> res = etcd.watch("/test", true);
CHECK(!res.is_done());
sleep(1);
CHECK(!res.is_done());
etcd.add("/test/key4", "44").wait();
sleep(1);
REQUIRE(res.is_done());
CHECK("create" == res.get().action());
CHECK("44" == res.get().value().as_string());
pplx::task<etcd::Response> res2 = etcd.watch("/test", true);
CHECK(!res2.is_done());
sleep(1);
CHECK(!res2.is_done());
etcd.set("/test/key4", "45").wait();
REQUIRE(res2.is_done());
CHECK("set" == res2.get().action());
CHECK("45" == res2.get().value().as_string());
}
TEST_CASE("watch changes in the past")
{
etcd::Client etcd("http://127.0.0.1:4001");
int index = etcd.set("/test/key1", "42").get().index();
etcd.set("/test/key1", "43").wait();
etcd.set("/test/key1", "44").wait();
etcd.set("/test/key1", "45").wait();
etcd::Response res = etcd.watch("/test/key1", ++index).get();
CHECK("set" == res.action());
CHECK("43" == res.value().as_string());
res = etcd.watch("/test/key1", ++index).get();
CHECK("set" == res.action());
CHECK("44" == res.value().as_string());
res = etcd.watch("/test", ++index, true).get();
CHECK("set" == res.action());
CHECK("45" == res.value().as_string());
}
TEST_CASE("atomic compare-and-swap")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd.set("/test/key1", "42").wait();
// modify success
etcd::Response res = etcd.modify_if("/test/key1", "43", "42").get();
int index = res.index();
REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action());
CHECK("43" == res.value().as_string());
// modify fails the second time
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
// succes with the correct index
res = etcd.modify_if("/test/key1", "44", index).get();
REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action());
CHECK("44" == res.value().as_string());
// index changes so second modify fails
res = etcd.modify_if("/test/key1", "45", index).get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
}
TEST_CASE("atomic compare-and-delete based on prevValue")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd.set("/test/key1", "42").wait();
etcd::Response res = etcd.rm_if("/test/key1", "43").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", "42").get();
REQUIRE(res.is_ok());
CHECK("compareAndDelete" == res.action());
CHECK("42" == res.prev_value().as_string());
}
TEST_CASE("atomic compare-and-delete based on prevIndex")
{
etcd::Client etcd("http://127.0.0.1:4001");
int index = etcd.set("/test/key1", "42").get().index();
etcd::Response res = etcd.rm_if("/test/key1", index - 1).get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", index).get();
REQUIRE(res.is_ok());
CHECK("compareAndDelete" == res.action());
CHECK("42" == res.prev_value().as_string());
}
TEST_CASE("cleanup")
{
etcd::Client etcd("http://127.0.0.1:4001");
REQUIRE(0 == etcd.rmdir("/test", true).get().error_code());
}