diff --git a/etcd/AsyncDeleteResponse.h b/etcd/AsyncDeleteResponse.h new file mode 100644 index 0000000..3c7c6c2 --- /dev/null +++ b/etcd/AsyncDeleteResponse.h @@ -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> rpcInstance; + +}; +} +#endif /* SRC_ASYNCDELETERESPONSE_H_ */ diff --git a/etcd/BaseResponse.h b/etcd/BaseResponse.h new file mode 100644 index 0000000..b4751b1 --- /dev/null +++ b/etcd/BaseResponse.h @@ -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_ */ diff --git a/etcd/Client.hpp b/etcd/Client.hpp index bebfff2..7f5ab6c 100644 --- a/etcd/Client.hpp +++ b/etcd/Client.hpp @@ -8,6 +8,8 @@ #include #include "proto/rpc.grpc.pb.h" +#include "etcd/DeleteRpcResponse.h" +#include "etcd/AsyncDeleteResponse.h" using grpc::Channel; using grpc::ClientAsyncResponseReader; @@ -159,7 +161,10 @@ namespace etcd std::unique_ptr watchServiceStub; pplx::task send_put(const std::string& key, const std::string& value); pplx::task send_get(std::string const & key); - }; + +private: + void getEntryForPreviousValue(const std::string& entryKey, etcd::AsyncDeleteResponse* drp); +}; class AsyncPutResponse { diff --git a/etcd/DeleteRpcResponse.h b/etcd/DeleteRpcResponse.h index bcd0be1..77aaffe 100644 --- a/etcd/DeleteRpcResponse.h +++ b/etcd/DeleteRpcResponse.h @@ -5,24 +5,26 @@ * Author: ubuntu */ -#ifndef SRC_DELETERPCRESPONSE_H_ -#define SRC_DELETERPCRESPONSE_H_ - -#include "etcd/Response.hpp" -#include "proto/rpc.grpc.pb.h" - -namespace etcd { -class DeleteRpcResponse : public etcd::Response, public etcd::Value { -public: - DeleteRpcResponse(); - virtual ~DeleteRpcResponse(); - void fillUpV2ResponseValues(etcdserverpb::RangeResponse); - - etcdserverpb::DeleteRangeResponse deleteResponse; - grpc::Status status; - grpc::ClientContext context; - grpc::CompletionQueue cq_; - std::unique_ptr> rpcInstance; -}; -} -#endif /* SRC_DELETERPCRESPONSE_H_ */ +//#ifndef SRC_DELETERPCRESPONSE_H_ +//#define SRC_DELETERPCRESPONSE_H_ +// +//#include "etcd/Response.hpp" +//#include "proto/rpc.grpc.pb.h" +// +//namespace etcd { +//class DeleteRpcResponse : public etcd::Response, public etcd::Value { +//public: +// DeleteRpcResponse(); +// virtual ~DeleteRpcResponse(); +// void fillUpV2ResponseValues(etcdserverpb::RangeResponse); +// +// etcdserverpb::DeleteRangeResponse deleteResponse; +// +// grpc::Status status; +// grpc::ClientContext context; +// grpc::CompletionQueue cq_; +// +// std::unique_ptr> rpcInstance; +//}; +//} +//#endif /* SRC_DELETERPCRESPONSE_H_ */ diff --git a/etcd/Response.hpp b/etcd/Response.hpp index d31f32a..5d466fa 100644 --- a/etcd/Response.hpp +++ b/etcd/Response.hpp @@ -20,9 +20,7 @@ namespace etcd public: static pplx::task create(pplx::task response_task); - //parang mas magandang ilagay ito sa baseclass imbis na here ooorrr - //talagang response v2 lang talaga dito - templatestatic pplx::task create(T call) + templatestatic pplx::task createV2Response(T call) { return pplx::task([call]() { @@ -39,7 +37,7 @@ namespace etcd if(call->status.ok()) { // 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 { diff --git a/etcd/Value.hpp b/etcd/Value.hpp index c39a4f3..899b8b3 100644 --- a/etcd/Value.hpp +++ b/etcd/Value.hpp @@ -41,7 +41,9 @@ namespace etcd protected: friend class Response; + friend class BaseResponse; //deliberately done since Value class will be removed during full V3 friend class DeleteRpcResponse; + friend class AsyncDeleteResponse; Value(); Value(web::json::value const & json_value); std::string _key; diff --git a/src/AsyncDeleteResponse.cpp b/src/AsyncDeleteResponse.cpp new file mode 100644 index 0000000..661ad7a --- /dev/null +++ b/src/AsyncDeleteResponse.cpp @@ -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"; +} diff --git a/src/BaseResponse.cpp b/src/BaseResponse.cpp new file mode 100644 index 0000000..d0ed8ba --- /dev/null +++ b/src/BaseResponse.cpp @@ -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 +} + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24468d3..52e2400 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) target_link_libraries(etcd-cpp-api ${CPPREST_LIB} boost_system ssl crypto protobuf grpc++) diff --git a/src/Client.cpp b/src/Client.cpp index 550bc8b..7e70271 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -2,6 +2,7 @@ #include #include "etcd/DeleteRpcResponse.h" +#include "etcd/AsyncDeleteResponse.h" etcd::Client::Client(std::string const & address) : client(address) @@ -45,9 +46,9 @@ pplx::task etcd::Client::set(std::string const & key, std::strin 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) { - std::cout << "FBDL setv3" << std::endl; etcdserverpb::PutRequest putRequest; putRequest.set_key(key); putRequest.set_value(value); @@ -93,31 +94,25 @@ pplx::task etcd::Client::modify_if(std::string const & key, std: return send_put_request(uri, "value", value); } -pplx::task etcd::Client::removeEntry(std::string const & entryKey) { - - etcd::DeleteRpcResponse *drp = new etcd::DeleteRpcResponse(); - - //get muna - std::cout<<"blocking call for get rpc first " << entryKey << std::endl; +void etcd::Client::getEntryForPreviousValue(const std::string& entryKey, etcd::AsyncDeleteResponse* drp) +{ etcdserverpb::RangeRequest rangeRequest; rangeRequest.set_key(entryKey); - etcdserverpb::RangeResponse rangeResponse; grpc::ClientContext context; - grpc::Status status = stub_->Range(&context, rangeRequest, &rangeResponse); - - if(status.ok()) { + if (status.ok()) { std::cout << "get OK" << std::endl; drp->fillUpV2ResponseValues(rangeResponse); - } - else { + } else { std::cout << "get NOK" << std::endl; } +} +pplx::task etcd::Client::removeEntry(std::string const & entryKey) { - //then delete - std::cout << "removing etcd v3 entry naman with template na" << std::endl; + etcd::AsyncDeleteResponse *drp = new etcd::AsyncDeleteResponse(); + getEntryForPreviousValue(entryKey, drp); //TODO: failure case scenario handling etcdserverpb::DeleteRangeRequest deleteRangeRequest; deleteRangeRequest.set_key(entryKey); @@ -125,32 +120,7 @@ pplx::task etcd::Client::removeEntry(std::string const & entryKe drp->rpcInstance = stub_->AsyncDeleteRange(&drp->context, deleteRangeRequest, &drp->cq_); drp->rpcInstance->Finish(&drp->deleteResponse, &drp->status, (void*)drp); - return Response::create(drp); - -// return pplx::task([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(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; -// } -// ); + return Response::createV2Response(drp); } @@ -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.Get 0 value: " << rangeResponse.kvs().Get(0).value() << std::endl; - DeleteRpcResponse drp; + AsyncDeleteResponse drp; drp.fillUpV2ResponseValues(rangeResponse); } else { diff --git a/src/DeleteRpcResponse.cpp b/src/DeleteRpcResponse.cpp index 36d473d..0f33f96 100644 --- a/src/DeleteRpcResponse.cpp +++ b/src/DeleteRpcResponse.cpp @@ -5,35 +5,34 @@ * Author: ubuntu */ -#include "etcd/DeleteRpcResponse.h" -#include - -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; +//#include "etcd/DeleteRpcResponse.h" +//#include // -// //or create an instance here and return it filled up -// DeleteRpcResponse r; -// r.Value::value = "yo!"; -// this->_value = r; //strip off value part +//etcd::DeleteRpcResponse::DeleteRpcResponse() { +// // TODO Auto-generated constructor stub // -// 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; +//} diff --git a/tst/EtcdTest.cpp b/tst/EtcdTest.cpp index 514d909..f6f8e8e 100644 --- a/tst/EtcdTest.cpp +++ b/tst/EtcdTest.cpp @@ -3,287 +3,286 @@ #include "etcd/Client.hpp" -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") +//TEST_CASE("setup") //{ // 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 +// etcd.rmdir("/test", true).wait(); //} // -//FBDL rm naman -//TEST_CASE("delete a value") +//TEST_CASE("add a new key") //{ -// std::cout << "FBDL do a delete via rm only" < 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") +//TEST_CASE("create a directory") //{ -// 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 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()); +// 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 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 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 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 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 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 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()); -}