This is an automated email from the ASF dual-hosted git repository.

slbotbm pushed a commit to branch cpp-high-level-client-4
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/cpp-high-level-client-4 by 
this push:
     new 277aa1e90 fixes
277aa1e90 is described below

commit 277aa1e90a30b36b494827f328e9b675fc2da1d2
Author: Rimuksh Kansal <[email protected]>
AuthorDate: Tue Nov 3 01:44:32 2026 +0900

    fixes
---
 .github/actions/cpp-bazel/pre-merge/action.yml |  1 -
 .pre-commit-config.yaml                        | 11 +++++
 foreign/cpp/.bazelrc                           |  4 ++
 foreign/cpp/.bazelversion                      |  2 +-
 foreign/cpp/BUILD.bazel                        | 29 +++++++++++--
 foreign/cpp/MODULE.bazel                       |  3 ++
 foreign/cpp/MODULE.bazel.lock                  | 10 +++--
 foreign/cpp/README.md                          |  7 +--
 foreign/cpp/build.rs                           |  2 +-
 foreign/cpp/include/iggy.hpp                   | 41 +++++++++++++++---
 foreign/cpp/src/client.cpp                     | 29 +++----------
 foreign/cpp/src/type_conversions.cpp           |  5 ++-
 foreign/cpp/tests/e2e/client.cpp               |  8 +++-
 foreign/cpp/tests/e2e/partition.cpp            | 60 --------------------------
 scripts/ci/cpp-coverage.sh                     |  3 +-
 15 files changed, 105 insertions(+), 110 deletions(-)

diff --git a/.github/actions/cpp-bazel/pre-merge/action.yml 
b/.github/actions/cpp-bazel/pre-merge/action.yml
index 8913da1c3..0e7044473 100644
--- a/.github/actions/cpp-bazel/pre-merge/action.yml
+++ b/.github/actions/cpp-bazel/pre-merge/action.yml
@@ -96,7 +96,6 @@ runs:
       shell: bash
       run: |
         cd foreign/cpp
-        cargo test
         ../../scripts/ci/cpp-coverage.sh
 
     - name: Stop server after tests
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 92da570fb..694841131 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -208,6 +208,17 @@ repos:
         pass_filenames: false
         stages: [pre-push]
 
+  # C++ SDK formatting
+  - repo: local
+    hooks:
+      - id: clang-format
+        name: clang-format (foreign/cpp)
+        entry: clang-format-18
+        args: ["--style=file", "--dry-run", "--Werror"]
+        language: system
+        files: ^foreign/cpp/.*\.(h|hpp|cc|cpp|cxx)$
+        pass_filenames: true
+
   # Go SDK formatting
   - repo: local
     hooks:
diff --git a/foreign/cpp/.bazelrc b/foreign/cpp/.bazelrc
index 880712c20..81b51b249 100644
--- a/foreign/cpp/.bazelrc
+++ b/foreign/cpp/.bazelrc
@@ -20,6 +20,10 @@
 # Enable BzlMod
 common --enable_bzlmod
 
+# C++ standard
+build --cxxopt=-std=c++20
+build --host_cxxopt=-std=c++20
+
 # Default test behavior
 test --test_output=errors
 test --cache_test_results=no
diff --git a/foreign/cpp/.bazelversion b/foreign/cpp/.bazelversion
index deeb3d66e..3b7404213 100644
--- a/foreign/cpp/.bazelversion
+++ b/foreign/cpp/.bazelversion
@@ -1 +1 @@
-9.2.0
+9.3.1
diff --git a/foreign/cpp/BUILD.bazel b/foreign/cpp/BUILD.bazel
index 6175a1daf..d99393f78 100644
--- a/foreign/cpp/BUILD.bazel
+++ b/foreign/cpp/BUILD.bazel
@@ -15,6 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
+load("@bazel_skylib//rules:native_binary.bzl", "native_test")
 load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library", 
"cc_test")
 
 config_setting(
@@ -34,6 +35,7 @@ genrule(
         "include/lib.rs.h",
         "cxxbridge/rust/cxx.h",
         "cxxbridge/sources/lib.rs.cc",
+        "rust_unit_tests",
     ],
     cmd = """
         set -euo pipefail
@@ -46,6 +48,7 @@ genrule(
         OUT_RS="$$EXECROOT/$(location include/lib.rs.h)"
         OUT_CXX="$$EXECROOT/$(location cxxbridge/rust/cxx.h)"
         OUT_CC="$$EXECROOT/$(location cxxbridge/sources/lib.rs.cc)"
+        OUT_TESTS="$$EXECROOT/$(location rust_unit_tests)"
 
         PROJECT_ROOT="$$(dirname $$(readlink -f $(location Cargo.toml)))"
         cd "$$PROJECT_ROOT"
@@ -61,7 +64,12 @@ genrule(
         env -u PWD \
             CARGO_TARGET_DIR="$$CARGO_TARGET_DIR" \
             RUSTC="$$RUSTC" \
-            "$$CARGO" build --quiet $$FLAGS
+            "$$CARGO" build --quiet --lib $$FLAGS
+
+        env -u PWD \
+            CARGO_TARGET_DIR="$$CARGO_TARGET_DIR" \
+            RUSTC="$$RUSTC" \
+            "$$CARGO" rustc --quiet --tests $$FLAGS -- 
--emit="link=$$OUT_TESTS"
 
         cp "$$CARGO_TARGET_DIR/$$PROFILE/libiggy_cpp.a" "$$OUT_LIB"
 
@@ -94,6 +102,11 @@ genrule(
     ],
 )
 
+native_test(
+    name = "rust_unit",
+    src = ":rust_unit_tests",
+)
+
 genrule(
     name = "extract_profiler_runtime",
     outs = ["libprofiler_builtins.a"],
@@ -226,7 +239,7 @@ cc_binary(
 )
 
 cc_test(
-    name = "unit",
+    name = "cpp_unit",
     srcs = glob([
         "tests/unit/*.cpp",
     ]),
@@ -253,8 +266,18 @@ cc_test(
     ],
 )
 
+test_suite(
+    name = "unit",
+    tests = [
+        ":cpp_unit",
+        ":rust_unit",
+    ],
+)
+
 cc_test(
     name = "e2e",
+    # The suite already takes about four of the default five minutes.
+    timeout = "long",
     srcs = glob([
         "tests/e2e/*.cpp",
     ]) + [
@@ -278,8 +301,6 @@ cc_test(
     tags = [
         "e2e",
     ],
-    # The suite already takes about four of the default five minutes.
-    timeout = "long",
     deps = [
         ":iggy-cpp",
         "@googletest//:gtest_main",
diff --git a/foreign/cpp/MODULE.bazel b/foreign/cpp/MODULE.bazel
index 9ea7c4d9b..4a562e42d 100644
--- a/foreign/cpp/MODULE.bazel
+++ b/foreign/cpp/MODULE.bazel
@@ -21,14 +21,17 @@ module(
 )
 
 bazel_dep(name = "rules_cc", version = "0.2.26")
+bazel_dep(name = "bazel_skylib", version = "1.9.0")
 bazel_dep(name = "platforms", version = "1.1.0")
 bazel_dep(name = "googletest", version = "1.18.0.bcr.1")
 bazel_dep(name = "cucumber-cpp", version = "0.9.0")
 bazel_dep(name = "rules_rust", version = "0.74.0")
 bazel_dep(name = "abseil-cpp", version = "20260526.0")
+
 bazel_dep(name = "nlohmann_json", version = "3.12.0.bcr.1", dev_dependency = 
True)
 
 iggy_source = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", 
"new_local_repository")
+
 iggy_source(
     name = "iggy_source",
     build_file_content = """
diff --git a/foreign/cpp/MODULE.bazel.lock b/foreign/cpp/MODULE.bazel.lock
index 4175f8cbe..53daab76f 100644
--- a/foreign/cpp/MODULE.bazel.lock
+++ b/foreign/cpp/MODULE.bazel.lock
@@ -22,6 +22,7 @@
     "https://bcr.bazel.build/modules/apple_support/1.22.1/MODULE.bazel": 
"90bd1a660590f3ceffbdf524e37483094b29352d85317060b2327fff8f3f4458",
     "https://bcr.bazel.build/modules/apple_support/1.24.1/MODULE.bazel": 
"f46e8ddad60aef170ee92b2f3d00ef66c147ceafea68b6877cb45bd91737f5f8",
     "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": 
"0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4",
+    "https://bcr.bazel.build/modules/apple_support/2.5.2/MODULE.bazel": 
"bb1b7081e390a8d3885f642cb0073dfcf8e7a36525e079fa8f5835af7079c0fe",
     "https://bcr.bazel.build/modules/apple_support/2.8.0/MODULE.bazel": 
"c45f5176057092afba0be6c48a9ea02101666802f8be536947e099e94757f8ed",
     "https://bcr.bazel.build/modules/apple_support/2.9.1/MODULE.bazel": 
"fb209b83ed172af587419acb3340389cfe3260669e5f1c05e1ac3974aca614e0",
     "https://bcr.bazel.build/modules/apple_support/2.9.1/source.json": 
"247d9f86d94c546533fb01e6e18b018486f9a6dff5faccae8838ef12e659b2a7",
@@ -143,6 +144,7 @@
     "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": 
"b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c",
     "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": 
"eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37",
     "https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": 
"353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
+    "https://bcr.bazel.build/modules/rules_cc/0.2.15/MODULE.bazel": 
"6a0a4a75a57aa6dc888300d848053a58c6b12a29f89d4304e1c41448514ec6e8",
     "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": 
"1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84",
     "https://bcr.bazel.build/modules/rules_cc/0.2.18/MODULE.bazel": 
"4460ec36adc8f722a6a2a4ac9374cb91f2acebadaa93fc37966129afb3dece87",
     "https://bcr.bazel.build/modules/rules_cc/0.2.20/MODULE.bazel": 
"f5c07bce5ddcb99be21a0812ff5aadb439e688b7449c6542152363b2fd859c1a",
@@ -236,7 +238,7 @@
   "moduleExtensions": {
     
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions":
 {
       "general": {
-        "bzlTransitiveDigest": "+Kp6j204mBZ3mxlIDDR0gBoP45BZ4jYRhRAcB8sU0qc=",
+        "bzlTransitiveDigest": "WDuVCwqV73DvcHB5Of+02lhUZgPxr9MqtpvMRyUi0eQ=",
         "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=",
         "recordedInputs": [
           "REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools"
@@ -293,7 +295,7 @@
     },
     "@@rules_python+//python/extensions:config.bzl%config": {
       "general": {
-        "bzlTransitiveDigest": "dzD8Q2YmrP3fz8saWLHPmlwPLO91ImtTmP/c9JKTStM=",
+        "bzlTransitiveDigest": "L+2ZCpb7GIJqvWaXpzkfk/80d916sIFVmSPzrSm6of8=",
         "usagesDigest": "ZVSXMAGpD+xzVNPuvF1IoLBkty7TROO0+akMapt1pAg=",
         "recordedInputs": [
           "REPO_MAPPING:rules_python+,bazel_tools bazel_tools",
@@ -461,7 +463,7 @@
     },
     "@@rules_python+//python/uv:uv.bzl%uv": {
       "general": {
-        "bzlTransitiveDigest": "ijW9KS7qsIY+yBVvJ+Nr1mzwQox09j13DnE3iIwaeTM=",
+        "bzlTransitiveDigest": "IgkgxNrtlAec7OnaFrWoCC5NQhHcY/aIz4jsqcNMm8Y=",
         "usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=",
         "recordedInputs": [
           "REPO_MAPPING:rules_python+,bazel_tools bazel_tools",
@@ -491,7 +493,7 @@
     },
     "@@rules_rust+//crate_universe/private:internal_extensions.bzl%cu_nr": {
       "general": {
-        "bzlTransitiveDigest": "jgiBS2gw1sTr1ow6fBIqZGzVF1eoi/X+wOnyPnzLxY4=",
+        "bzlTransitiveDigest": "KfVJcoV1nQgI+xL0z3SDxi0TwUOqg22b/BAiyUtmt3U=",
         "usagesDigest": "McimNXAztVHDzspa1Kng94T+YeyY/44zx9FkNqIMn2s=",
         "recordedInputs": [
           "REPO_MAPPING:apple_support+,bazel_skylib bazel_skylib+",
diff --git a/foreign/cpp/README.md b/foreign/cpp/README.md
index 3de19cd2b..dfc1d5be7 100644
--- a/foreign/cpp/README.md
+++ b/foreign/cpp/README.md
@@ -10,7 +10,7 @@
 
 C++ client for [Apache Iggy](https://iggy.apache.org) message streaming.
 
-Bazel uses the Cargo and Rust toolchain provisioned by `rules_rust`. The Rust 
bridge builds locally into a separate target directory in the Bazel output 
tree. Use the Bazel version pinned in `.bazelversion` with a compatible Java 
runtime (Java 21 or newer for Bazel 9.2.0).
+Bazel uses the Cargo and Rust toolchain provisioned by `rules_rust`. The Rust 
bridge builds locally into a separate target directory in the Bazel output 
tree. Use the Bazel version pinned in `.bazelversion` with a compatible Java 
runtime (Java 21 or newer for Bazel 9.3.1).
 
 Build commands
 
@@ -18,7 +18,7 @@ Build commands
 # Build library
 bazel build //:iggy-cpp
 
-# Unit tests
+# C++ and Rust unit tests
 bazel test //:unit
 
 # Low-level integration tests (require a running server)
@@ -99,7 +99,7 @@ The blocking wrapper populates `IggyException::Code()` and 
`Kind()` for Rust SDK
 errors from these methods:
 
 - `Login`, `Logout`, `ResolveOperation`, and `AbandonOperation`.
-- `CreateUser`, `UpdateUser`, and `DeleteUser`.
+- `CreateUser`, `UpdateUser`, `DeleteUser`, `UpdatePermissions`, and 
`ChangePassword`.
 - `CreateStream`, `UpdateStream`, and `DeleteStream`.
 - `CreateTopic`, `UpdateTopic`, and `DeleteTopic`.
 - `CreatePartitions`, `DeletePartitions`, and `DeleteSegments`.
@@ -107,6 +107,7 @@ errors from these methods:
 - `StoreConsumerOffset`, `StoreConsumerPosition`, `DeleteConsumerOffset`, and 
`DeleteConsumerPosition`.
 - `PollMessages`, `PendingPoll::Wait`, `Reader`, and the calls of 
`PartitionReader`.
 - `GetMetadataChanges`.
+- `SendMessages`, `SendBinaryRequest`, and `SendBinaryRequestToReplica`.
 
 Other methods, including `Connect`, `Disconnect`, and `Shutdown`, report 
errors through the exception message only. C++ and bridge-local argument errors 
also leave `Code()` and `OperationId()` empty and `Kind()` empty, including for 
the methods listed above. `GetMetadataChanges` is the exception: it reports 
every invalid query as `invalid_command`, including one the bridge refuses.
 
diff --git a/foreign/cpp/build.rs b/foreign/cpp/build.rs
index 33b30dd2f..8511b10b7 100644
--- a/foreign/cpp/build.rs
+++ b/foreign/cpp/build.rs
@@ -17,7 +17,7 @@
 
 fn main() {
     cxx_build::bridge("src/lib.rs")
-        .std("c++17")
+        .std("c++20")
         .compile("iggy-cpp-bridge");
 
     println!("cargo:rerun-if-changed=src/client.rs");
diff --git a/foreign/cpp/include/iggy.hpp b/foreign/cpp/include/iggy.hpp
index 1301f002c..ba463e11a 100644
--- a/foreign/cpp/include/iggy.hpp
+++ b/foreign/cpp/include/iggy.hpp
@@ -796,7 +796,7 @@ class Permissions final {
  *
  * @code{.cpp}
  * const auto polled{client.PollMessages(
- *     stream, topic, std::nullopt,
+ *     stream, topic, 0,
  *     iggy::Consumer::Group(iggy::Identifier::String("my-group")),
  *     iggy::PollingStrategy::Next(), 10, true)};
  * @endcode
@@ -1041,8 +1041,21 @@ class IggyMessageToSend final {
     static IggyMessageToSend Create(std::string_view payload,
                                     std::vector<HeaderEntry> user_headers = {},
                                     absl::uint128 id                      = 0) 
{
-        return IggyMessageToSend(id, 
std::vector<std::uint8_t>(payload.begin(), payload.end()),
-                                 std::move(user_headers));
+        return Create(std::vector<std::uint8_t>(payload.begin(), 
payload.end()), std::move(user_headers), id);
+    }
+
+    /**
+     * @brief Creates a message, taking ownership of the payload and headers.
+     * @param payload Binary message payload. Move it to avoid a copy.
+     * @param user_headers Optional typed user headers. Keys must be unique.
+     * @param id Application-defined message ID.
+     * @return Message owning @p payload and @p user_headers.
+     * @note Payload and header constraints are validated when the message is 
sent.
+     */
+    static IggyMessageToSend Create(std::vector<std::uint8_t> payload,
+                                    std::vector<HeaderEntry> user_headers = {},
+                                    absl::uint128 id                      = 0) 
{
+        return IggyMessageToSend(id, std::move(payload), 
std::move(user_headers));
     }
 
     /**
@@ -5973,6 +5986,12 @@ class TransportEndpoints final {
  */
 class ClusterNode final {
   public:
+    /**
+     * @brief Returns the replica ID used by SendBinaryRequestToReplica().
+     * @return Replica ID advertised by the server.
+     */
+    [[nodiscard]] std::uint8_t ReplicaId() const noexcept { return 
replica_id_; }
+
     /**
      * @brief Returns the configured node name.
      * @return Node name owned by this value.
@@ -6004,8 +6023,14 @@ class ClusterNode final {
     [[nodiscard]] const std::string &Status() const noexcept { return status_; 
}
 
   private:
-    ClusterNode(std::string name, std::string ip, TransportEndpoints 
endpoints, std::string role, std::string status)
-        : name_(std::move(name)),
+    ClusterNode(std::uint8_t replica_id,
+                std::string name,
+                std::string ip,
+                TransportEndpoints endpoints,
+                std::string role,
+                std::string status)
+        : replica_id_(replica_id),
+          name_(std::move(name)),
           ip_(std::move(ip)),
           endpoints_(endpoints),
           role_(std::move(role)),
@@ -6015,6 +6040,7 @@ class ClusterNode final {
 
     friend class ClusterMetadata;
 
+    std::uint8_t replica_id_;
     std::string name_;
     std::string ip_;
     TransportEndpoints endpoints_;
@@ -6704,7 +6730,7 @@ class IggyConsumer final {
  * Rust SDK errors populate IggyException::Code() and IggyException::Kind() 
for:
  *
  * - Login(), Logout(), ResolveOperation(), and AbandonOperation().
- * - CreateUser(), UpdateUser(), and DeleteUser().
+ * - CreateUser(), UpdateUser(), DeleteUser(), UpdatePermissions(), and 
ChangePassword().
  * - EncryptionKeyFingerprint() and invalid keys passed to CreateStream().
  * - CreateStream(), UpdateStream(), and DeleteStream().
  * - CreateTopic(), UpdateTopic(), and DeleteTopic().
@@ -6716,6 +6742,7 @@ class IggyConsumer final {
  * - PollMessages(), Reader(), StandaloneConsumer(), GroupConsumer(),
  *   PendingPoll::Wait(), and the calls of PartitionReader and IggyConsumer.
  * - GetMetadataChanges().
+ * - SendMessages(), SendBinaryRequest(), and SendBinaryRequestToReplica().
  *
  * Other methods report errors through the exception message only. C++ and
  * bridge-local argument validation failures also have no structured error
@@ -7781,7 +7808,7 @@ class IggyBlockingClient final {
      */
     PolledMessages PollMessages(const Identifier &stream,
                                 const Identifier &topic,
-                                std::optional<std::uint32_t> partition_id,
+                                std::uint32_t partition_id,
                                 const Consumer &consumer,
                                 const PollingStrategy &strategy,
                                 std::uint32_t count,
diff --git a/foreign/cpp/src/client.cpp b/foreign/cpp/src/client.cpp
index d10fb0fd4..8dac26dde 100644
--- a/foreign/cpp/src/client.cpp
+++ b/foreign/cpp/src/client.cpp
@@ -580,31 +580,23 @@ SendMessagesResponse 
IggyBlockingClient::SendMessages(const Identifier &stream,
         for (const auto &message : messages) {
             ffi_messages.push_back(message.ToFfi());
         }
-        rust::Vec<std::uint8_t> ffi_partitioning_value;
-        ffi_partitioning_value.reserve(partitioning.Value().size());
-        for (const auto byte : partitioning.Value()) {
-            ffi_partitioning_value.push_back(byte);
-        }
         return SendMessagesResponse::FromFfi(
             Handle()->send_messages(stream.ToFfi(), topic.ToFfi(), 
std::string(partitioning.Kind()),
-                                    std::move(ffi_partitioning_value), 
std::move(ffi_messages), error_info));
+                                    ToFfiBytes(partitioning.Value()), 
std::move(ffi_messages), error_info));
     });
 }
 
 PolledMessages IggyBlockingClient::PollMessages(const Identifier &stream,
                                                 const Identifier &topic,
-                                                const 
std::optional<std::uint32_t> partition_id,
+                                                const std::uint32_t 
partition_id,
                                                 const Consumer &consumer,
                                                 const PollingStrategy 
&strategy,
                                                 const std::uint32_t count,
                                                 const bool auto_commit) {
     return RethrowAsIggyException([&] {
-        if (!partition_id) {
-            throw std::invalid_argument("partition_id is required");
-        }
         const auto options =
             PollOptions().SetCount(count).SetCommit(auto_commit ? 
CommitPolicy::OnRead : CommitPolicy::Manual);
-        return PollMessages(consumer, stream, topic, *partition_id, strategy, 
options);
+        return PollMessages(consumer, stream, topic, partition_id, strategy, 
options);
     });
 }
 
@@ -644,12 +636,7 @@ std::vector<std::uint8_t> 
IggyBlockingClient::Snapshot(const SnapshotCompression
 std::vector<std::uint8_t> IggyBlockingClient::SendBinaryRequest(std::uint32_t 
code,
                                                                 const 
std::vector<std::uint8_t> &payload) {
     return RethrowAsIggyException([this, code, &payload](ffi::ErrorInfo 
&error_info) {
-        rust::Vec<std::uint8_t> ffi_payload;
-        ffi_payload.reserve(payload.size());
-        for (const auto byte : payload) {
-            ffi_payload.push_back(byte);
-        }
-        auto ffi_response = Handle()->send_binary_request(code, 
std::move(ffi_payload), error_info);
+        auto ffi_response = Handle()->send_binary_request(code, 
ToFfiBytes(payload), error_info);
         return std::vector<std::uint8_t>(ffi_response.begin(), 
ffi_response.end());
     });
 }
@@ -658,13 +645,7 @@ std::vector<std::uint8_t> 
IggyBlockingClient::SendBinaryRequestToReplica(std::ui
                                                                          const 
std::vector<std::uint8_t> &payload,
                                                                          
std::uint8_t replica_id) {
     return RethrowAsIggyException([this, code, &payload, 
replica_id](ffi::ErrorInfo &error_info) {
-        rust::Vec<std::uint8_t> ffi_payload;
-        ffi_payload.reserve(payload.size());
-        for (const auto byte : payload) {
-            ffi_payload.push_back(byte);
-        }
-        auto ffi_response =
-            Handle()->send_binary_request_to_replica(code, 
std::move(ffi_payload), replica_id, error_info);
+        auto ffi_response = Handle()->send_binary_request_to_replica(code, 
ToFfiBytes(payload), replica_id, error_info);
         return std::vector<std::uint8_t>(ffi_response.begin(), 
ffi_response.end());
     });
 }
diff --git a/foreign/cpp/src/type_conversions.cpp 
b/foreign/cpp/src/type_conversions.cpp
index b9546703a..52207b659 100644
--- a/foreign/cpp/src/type_conversions.cpp
+++ b/foreign/cpp/src/type_conversions.cpp
@@ -868,8 +868,9 @@ TransportEndpoints 
TransportEndpoints::FromFfi(ffi::TransportEndpoints endpoints
 }
 
 ClusterNode ClusterNode::FromFfi(ffi::ClusterNode node) {
-    return ClusterNode(std::string(node.name.c_str(), node.name.size()), 
std::string(node.ip.c_str(), node.ip.size()),
-                       TransportEndpoints::FromFfi(node.endpoints), 
std::string(node.role.c_str(), node.role.size()),
+    return ClusterNode(node.replica_id, std::string(node.name.c_str(), 
node.name.size()),
+                       std::string(node.ip.c_str(), node.ip.size()), 
TransportEndpoints::FromFfi(node.endpoints),
+                       std::string(node.role.c_str(), node.role.size()),
                        std::string(node.status.c_str(), node.status.size()));
 }
 
diff --git a/foreign/cpp/tests/e2e/client.cpp b/foreign/cpp/tests/e2e/client.cpp
index 64cb62296..fdce78eea 100644
--- a/foreign/cpp/tests/e2e/client.cpp
+++ b/foreign/cpp/tests/e2e/client.cpp
@@ -2762,6 +2762,7 @@ TEST_F(E2E_Client, 
GetClusterMetadataReturnsSingleNodeMetadata) {
     ASSERT_EQ(metadata.Nodes().size(), 1u);
 
     const auto &node = metadata.Nodes()[0];
+    EXPECT_EQ(node.ReplicaId(), 0u);
     EXPECT_FALSE(node.Name().empty());
     EXPECT_FALSE(node.Ip().empty());
     EXPECT_EQ(node.Role(), "leader");
@@ -2783,6 +2784,7 @@ TEST_F(E2E_Client, 
GetClusterMetadataIsStableAcrossBackToBackCalls) {
 
     const auto &first_node  = first_metadata.Nodes()[0];
     const auto &second_node = second_metadata.Nodes()[0];
+    EXPECT_EQ(first_node.ReplicaId(), second_node.ReplicaId());
     EXPECT_EQ(first_node.Name(), second_node.Name());
     EXPECT_EQ(first_node.Ip(), second_node.Ip());
     EXPECT_EQ(first_node.Role(), second_node.Role());
@@ -3001,11 +3003,13 @@ TEST_F(E2E_Client, 
SendBinaryRequestToReplicaGetStatsReturnsNonEmptyBytes) {
     RecordProperty("description",
                    "Returns a non-empty response body for a raw get-stats 
command sent to the server's own replica.");
     constexpr std::uint32_t get_stats_command_code = 10;
-    constexpr std::uint8_t server_replica_id       = 0;
     auto client                                    = 
GetLoggedInHighLevelClient();
+    const auto metadata                            = 
client.GetClusterMetadata();
+    ASSERT_EQ(metadata.Nodes().size(), 1u);
 
     std::vector<std::uint8_t> response;
-    ASSERT_NO_THROW(response = 
client.SendBinaryRequestToReplica(get_stats_command_code, {}, 
server_replica_id));
+    ASSERT_NO_THROW(response =
+                        
client.SendBinaryRequestToReplica(get_stats_command_code, {}, 
metadata.Nodes()[0].ReplicaId()));
     EXPECT_FALSE(response.empty());
 }
 
diff --git a/foreign/cpp/tests/e2e/partition.cpp 
b/foreign/cpp/tests/e2e/partition.cpp
index c0ee41b0e..b271b750d 100644
--- a/foreign/cpp/tests/e2e/partition.cpp
+++ b/foreign/cpp/tests/e2e/partition.cpp
@@ -119,66 +119,6 @@ TEST_F(E2E_Partition, 
CreatePartitionsWithUnknownNumericIdentifiersThrows) {
         iggy::IggyException);
 }
 
-TEST_F(E2E_Partition, CreatePartitionsWithBoundaryPartitionsCountValues) {
-    RecordProperty("description",
-                   "Accepts supported create_partitions counts and rejects 
values outside the allowed range.");
-    const std::string stream_name = GetRandomName();
-
-    auto client = GetLoggedInHighLevelClient();
-
-    ASSERT_NO_THROW(client.CreateStream(stream_name));
-    TrackStream(stream_name);
-
-    struct TestCase {
-        std::string topic_name;
-        std::uint32_t partitions_count;
-        bool should_succeed;
-        std::uint32_t expected_total_partitions;
-    };
-
-    const std::vector<TestCase> test_cases = {
-        {GetRandomName(), static_cast<std::uint32_t>(-1), false, 1},
-        {GetRandomName(), 0, false, 1},
-        {GetRandomName(), 1, true, 2},
-        {GetRandomName(), 43, true, 44},
-        {GetRandomName(), 1000, true, 1001},
-        {GetRandomName(), 1001, false, 1},
-    };
-
-    for (const auto &test_case : test_cases) {
-        SCOPED_TRACE(test_case.topic_name);
-        
ASSERT_NO_THROW(client.CreateTopic(iggy::Identifier::String(stream_name), 
test_case.topic_name,
-                                           
iggy::TopicCreateOptions().SetPartitionsCount(1)));
-
-        if (test_case.should_succeed) {
-            
ASSERT_NO_THROW(client.CreatePartitions(iggy::Identifier::String(stream_name),
-                                                    
iggy::Identifier::String(test_case.topic_name),
-                                                    
test_case.partitions_count));
-        } else {
-            ASSERT_THROW(
-                client.CreatePartitions(iggy::Identifier::String(stream_name),
-                                        
iggy::Identifier::String(test_case.topic_name), test_case.partitions_count),
-                iggy::IggyException);
-        }
-    }
-
-    ASSERT_NO_THROW({
-        const auto stream_details = 
client.GetStream(iggy::Identifier::String(stream_name));
-        ASSERT_EQ(stream_details.Topics().size(), test_cases.size());
-        for (const auto &test_case : test_cases) {
-            bool found = false;
-            for (const auto &topic : stream_details.Topics()) {
-                if (topic.Name() == test_case.topic_name) {
-                    EXPECT_EQ(topic.PartitionsCount(), 
test_case.expected_total_partitions);
-                    found = true;
-                    break;
-                }
-            }
-            EXPECT_TRUE(found) << "Missing topic " << test_case.topic_name;
-        }
-    });
-}
-
 TEST_F(E2E_Partition, CreatePartitionsWithNumericIdentifiersSucceeds) {
     RecordProperty("description",
                    "Creates partitions successfully when valid numeric stream 
and topic identifiers are used.");
diff --git a/scripts/ci/cpp-coverage.sh b/scripts/ci/cpp-coverage.sh
index bb5525c12..6e512b689 100755
--- a/scripts/ci/cpp-coverage.sh
+++ b/scripts/ci/cpp-coverage.sh
@@ -66,8 +66,9 @@ bazel coverage \
 sed 's|^SF:|SF:foreign/cpp/|' "$CPP_RAW" >"$OUTPUT"
 
 "$LLVM_COV" export \
-  --object bazel-bin/unit \
+  --object bazel-bin/cpp_unit \
   --object bazel-bin/e2e \
+  --object bazel-bin/rust_unit_tests \
   -instr-profile="$PROFDATA" \
   -format=lcov \
   -ignore-filename-regex='(\.cargo/|/rustc/|/core/|cxxbridge|/registry/)' |

Reply via email to