From 1e72df7ca3fdeecee98b554656f6bf0870ffe410 Mon Sep 17 00:00:00 2001 From: Tao He Date: Tue, 18 Oct 2022 00:51:19 +0800 Subject: [PATCH] Add test cases and documentation to show that binary data as key/value works well. Signed-off-by: Tao He --- README.md | 25 +++++++++++++++++++++++ tst/EtcdTest.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/README.md b/README.md index eb3cb62..c5578b5 100644 --- a/README.md +++ b/README.md @@ -438,6 +438,16 @@ the `created_index()` and the `modified_index()` methods. } ``` +### Put a value + +You can put a key-value pair to etcd with the the `put()` method of the client instance. The only +parameter is the key and value to be put + +```c++ + etcd::Client etcd("http://127.0.0.1:2379"); + pplx::task response_task = etcd.put("foo", "bar"); +``` + ### Modifying a value Setting the value of a key can be done with the `set()` method of the client. You simply pass @@ -570,6 +580,21 @@ prefix will be deleted. All deleted keys will be placed in `response.values()` a However, if recursive parameter is false, functionality will be the same as just deleting a key. The key supplied will NOT be treated as a prefix and will be treated as a normal key name. +### Using binary data as key and value + +Etcd itself support using arbitrary binary data as the key and value, i.e., the key and value +can contain `\NUL` (`\0`) and not necessary NUL-terminated strings. `std::string` in C++ supports +embed `\0` as well, but please note that when constructing `std::string` from a C-style string +the string will be terminated by the first `\0` character. Rather, you need to use the constructor +with the `count` parameter explicitly. When unpack a `std::string` that contains `\0`, you need +`.data()`, and `.c_str()` won't work. + +```c++ + std::string key = "key-foo\0bar"; + std::string value = "value-foo\0bar"; + etcd.put(key, value).wait(); +``` + ### Lock Etcd lock has been supported as follows: diff --git a/tst/EtcdTest.cpp b/tst/EtcdTest.cpp index 3607378..5b9f403 100644 --- a/tst/EtcdTest.cpp +++ b/tst/EtcdTest.cpp @@ -46,6 +46,59 @@ TEST_CASE("read a value from etcd") CHECK("" == etcd.get("/test").get().value().as_string()); // key points to a directory } +TEST_CASE("using binary keys and values, raw char pointer doesn't work") +{ + etcd::Client etcd(etcd_url); + etcd.rmdir("/test", true).wait(); + { + etcd::Response resp = etcd.put("/test/key1\0xyz", "42\0foo").get(); + REQUIRE(resp.is_ok()); + } + { + // should not exist + etcd::Response resp = etcd.get(std::string("/test/key1\0xyz", 14)).get(); + CHECK(!resp.is_ok()); + CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code()); + } + { + // should exist + etcd::Response resp = etcd.get(std::string("/test/key1", 10)).get(); + REQUIRE(resp.is_ok()); + CHECK(std::string("42") == resp.value().as_string()); + CHECK(std::string("42\0foo", 6) != resp.value().as_string()); + } + { + // should exist + etcd::Response resp = etcd.get("/test/key1\0xyz").get(); + REQUIRE(resp.is_ok()); + CHECK(std::string("42") == resp.value().as_string()); + CHECK(std::string("42\0foo", 6) != resp.value().as_string()); + } +} + +TEST_CASE("using binary keys and values, std::string is ok for \\0") +{ + etcd::Client etcd(etcd_url); + etcd.rmdir("/test", true).wait(); + { + etcd::Response resp = etcd.put(std::string("/test/key1\0xyz", 14), std::string("42\0foo", 6)).get(); + REQUIRE(resp.is_ok()); + } + { + // should not exist + etcd::Response resp = etcd.get("/test/key1").get(); + CHECK(!resp.is_ok()); + CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code()); + } + { + // should exist + etcd::Response resp = etcd.get(std::string("/test/key1\0xyz", 14)).get(); + REQUIRE(resp.is_ok()); + CHECK(std::string("42") != resp.value().as_string()); + CHECK(std::string("42\0foo", 6) == resp.value().as_string()); + } +} + TEST_CASE("simplified read") { etcd::Client etcd(etcd_url);