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

maciej pushed a commit to branch java-stats-update
in repository https://gitbox.apache.org/repos/asf/iggy.git

commit b1d6d80e54343c3af92db14f964c3848d01d2091
Author: Maciej Modzelewski <[email protected]>
AuthorDate: Wed Mar 18 13:17:34 2026 +0100

    feat(java): add new stats fields to match server sysinfo updates
    
    The server recently added iggy_server_version, semver,
    cache_metrics, threads_count, and disk space fields to
    the sysinfo stats response. The Java SDK was missing
    support for these fields, causing deserialization to
    fail with the updated server.
    
    Add CacheMetrics record and extend Stats with the new
    fields. Update both binary and JSON deserialization
    paths with corresponding test coverage.
---
 .../blocking/http/CacheMetricsKeyMixin.java}       |  42 +++-----
 .../client/blocking/http/ObjectMapperFactory.java  |   2 +
 .../org/apache/iggy/serde/BytesDeserializer.java   |  34 +++++-
 .../iggy/system/{Stats.java => CacheMetrics.java}  |  24 +----
 .../system/{Stats.java => CacheMetricsKey.java}    |  38 +++----
 .../main/java/org/apache/iggy/system/Stats.java    |  10 +-
 .../iggy/client/blocking/SystemClientBaseTest.java |   5 +
 .../client/blocking/http/ObjectMapperTest.java     | 119 +++++++++++++++++++++
 .../apache/iggy/serde/BytesDeserializerTest.java   | 116 +++++++++++++++++++-
 9 files changed, 312 insertions(+), 78 deletions(-)

diff --git 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/CacheMetricsKeyMixin.java
similarity index 53%
copy from foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
copy to 
foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/CacheMetricsKeyMixin.java
index 906e37c9d..35fd0fb70 100644
--- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
+++ 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/CacheMetricsKeyMixin.java
@@ -17,30 +17,22 @@
  * under the License.
  */
 
-package org.apache.iggy.system;
+package org.apache.iggy.client.blocking.http;
 
-import java.math.BigInteger;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import org.apache.iggy.system.CacheMetricsKey;
 
-public record Stats(
-        Long processId,
-        Float cpuUsage,
-        Float totalCpuUsage,
-        String memoryUsage,
-        String totalMemory,
-        String availableMemory,
-        BigInteger runTime,
-        BigInteger startTime,
-        String readBytes,
-        String writtenBytes,
-        String messagesSizeBytes,
-        Long streamsCount,
-        Long topicsCount,
-        Long partitionsCount,
-        Long segmentsCount,
-        BigInteger messagesCount,
-        Long clientsCount,
-        Long consumerGroupsCount,
-        String hostname,
-        String osName,
-        String osVersion,
-        String kernelVersion) {}
+/**
+ * Jackson mixin for {@link CacheMetricsKey} to keep the domain object free of 
serialization annotations.
+ */
+abstract class CacheMetricsKeyMixin {
+
+    @JsonCreator
+    static CacheMetricsKey fromString(String key) {
+        throw new UnsupportedOperationException("Mixin method should not be 
called directly");
+    }
+
+    @JsonValue
+    public abstract String toString();
+}
diff --git 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/ObjectMapperFactory.java
 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/ObjectMapperFactory.java
index 167db5d36..cdc2a7584 100644
--- 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/ObjectMapperFactory.java
+++ 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/client/blocking/http/ObjectMapperFactory.java
@@ -22,6 +22,7 @@ package org.apache.iggy.client.blocking.http;
 import com.fasterxml.jackson.annotation.JsonSetter;
 import com.fasterxml.jackson.annotation.Nulls;
 import org.apache.iggy.message.Message;
+import org.apache.iggy.system.CacheMetricsKey;
 import tools.jackson.databind.DeserializationFeature;
 import tools.jackson.databind.EnumNamingStrategies;
 import tools.jackson.databind.MapperFeature;
@@ -43,6 +44,7 @@ final class ObjectMapperFactory {
             .withConfigOverride(
                     List.class, list -> 
list.setNullHandling(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)))
             .addMixIn(Message.class, MessageMixin.class)
+            .addMixIn(CacheMetricsKey.class, CacheMetricsKeyMixin.class)
             .build();
 
     private ObjectMapperFactory() {}
diff --git 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java
 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java
index 3fb1c843f..7b4328b0c 100644
--- 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java
+++ 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java
@@ -37,6 +37,8 @@ import 
org.apache.iggy.personalaccesstoken.PersonalAccessTokenInfo;
 import org.apache.iggy.personalaccesstoken.RawPersonalAccessToken;
 import org.apache.iggy.stream.StreamBase;
 import org.apache.iggy.stream.StreamDetails;
+import org.apache.iggy.system.CacheMetrics;
+import org.apache.iggy.system.CacheMetricsKey;
 import org.apache.iggy.system.ClientInfo;
 import org.apache.iggy.system.ClientInfoDetails;
 import org.apache.iggy.system.ConsumerGroupInfo;
@@ -255,6 +257,30 @@ public final class BytesDeserializer {
         var kernelVersion = 
response.readCharSequence(toInt(kernelVersionLength), StandardCharsets.UTF_8)
                 .toString();
 
+        var iggyServerVersionLength = response.readUnsignedIntLE();
+        var iggyServerVersion = 
response.readCharSequence(toInt(iggyServerVersionLength), 
StandardCharsets.UTF_8)
+                .toString();
+
+        var semverValue = response.readUnsignedIntLE();
+        var iggyServerSemver = semverValue != 0 ? Optional.of(semverValue) : 
Optional.<Long>empty();
+
+        var metricsCount = response.readUnsignedIntLE();
+        Map<CacheMetricsKey, CacheMetrics> cacheMetrics = new HashMap<>();
+        for (int i = 0; i < metricsCount; i++) {
+            var streamId = response.readUnsignedIntLE();
+            var topicId = response.readUnsignedIntLE();
+            var partitionId = response.readUnsignedIntLE();
+            var hits = readU64AsBigInteger(response);
+            var misses = readU64AsBigInteger(response);
+            var hitRatio = response.readFloatLE();
+            var key = new CacheMetricsKey(streamId, topicId, partitionId);
+            cacheMetrics.put(key, new CacheMetrics(hits, misses, hitRatio));
+        }
+
+        var threadsCount = response.readUnsignedIntLE();
+        var freeDiskSpace = readU64AsBigInteger(response);
+        var totalDiskSpace = readU64AsBigInteger(response);
+
         return new Stats(
                 processId,
                 cpuUsage,
@@ -277,7 +303,13 @@ public final class BytesDeserializer {
                 hostname,
                 osName,
                 osVersion,
-                kernelVersion);
+                kernelVersion,
+                iggyServerVersion,
+                iggyServerSemver,
+                cacheMetrics,
+                threadsCount,
+                freeDiskSpace.toString(),
+                totalDiskSpace.toString());
     }
 
     public static ClientInfoDetails readClientInfoDetails(ByteBuf response) {
diff --git 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/CacheMetrics.java
similarity index 57%
copy from foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
copy to 
foreign/java/java-sdk/src/main/java/org/apache/iggy/system/CacheMetrics.java
index 906e37c9d..f173d627a 100644
--- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
+++ 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/CacheMetrics.java
@@ -21,26 +21,4 @@ package org.apache.iggy.system;
 
 import java.math.BigInteger;
 
-public record Stats(
-        Long processId,
-        Float cpuUsage,
-        Float totalCpuUsage,
-        String memoryUsage,
-        String totalMemory,
-        String availableMemory,
-        BigInteger runTime,
-        BigInteger startTime,
-        String readBytes,
-        String writtenBytes,
-        String messagesSizeBytes,
-        Long streamsCount,
-        Long topicsCount,
-        Long partitionsCount,
-        Long segmentsCount,
-        BigInteger messagesCount,
-        Long clientsCount,
-        Long consumerGroupsCount,
-        String hostname,
-        String osName,
-        String osVersion,
-        String kernelVersion) {}
+public record CacheMetrics(BigInteger hits, BigInteger misses, Float hitRatio) 
{}
diff --git 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/CacheMetricsKey.java
similarity index 55%
copy from foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
copy to 
foreign/java/java-sdk/src/main/java/org/apache/iggy/system/CacheMetricsKey.java
index 906e37c9d..11be433d3 100644
--- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
+++ 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/CacheMetricsKey.java
@@ -19,28 +19,18 @@
 
 package org.apache.iggy.system;
 
-import java.math.BigInteger;
+public record CacheMetricsKey(Long streamId, Long topicId, Long partitionId) {
 
-public record Stats(
-        Long processId,
-        Float cpuUsage,
-        Float totalCpuUsage,
-        String memoryUsage,
-        String totalMemory,
-        String availableMemory,
-        BigInteger runTime,
-        BigInteger startTime,
-        String readBytes,
-        String writtenBytes,
-        String messagesSizeBytes,
-        Long streamsCount,
-        Long topicsCount,
-        Long partitionsCount,
-        Long segmentsCount,
-        BigInteger messagesCount,
-        Long clientsCount,
-        Long consumerGroupsCount,
-        String hostname,
-        String osName,
-        String osVersion,
-        String kernelVersion) {}
+    public static CacheMetricsKey fromString(String key) {
+        String[] parts = key.split("-");
+        if (parts.length != 3) {
+            throw new IllegalArgumentException("Invalid cache metrics key: " + 
key);
+        }
+        return new CacheMetricsKey(Long.parseLong(parts[0]), 
Long.parseLong(parts[1]), Long.parseLong(parts[2]));
+    }
+
+    @Override
+    public String toString() {
+        return streamId + "-" + topicId + "-" + partitionId;
+    }
+}
diff --git 
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java 
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
index 906e37c9d..8a5f6b52b 100644
--- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
+++ b/foreign/java/java-sdk/src/main/java/org/apache/iggy/system/Stats.java
@@ -20,6 +20,8 @@
 package org.apache.iggy.system;
 
 import java.math.BigInteger;
+import java.util.Map;
+import java.util.Optional;
 
 public record Stats(
         Long processId,
@@ -43,4 +45,10 @@ public record Stats(
         String hostname,
         String osName,
         String osVersion,
-        String kernelVersion) {}
+        String kernelVersion,
+        String iggyServerVersion,
+        Optional<Long> iggyServerSemver,
+        Map<CacheMetricsKey, CacheMetrics> cacheMetrics,
+        Long threadsCount,
+        String freeDiskSpace,
+        String totalDiskSpace) {}
diff --git 
a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/SystemClientBaseTest.java
 
b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/SystemClientBaseTest.java
index 058c84e85..01d55315b 100644
--- 
a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/SystemClientBaseTest.java
+++ 
b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/SystemClientBaseTest.java
@@ -42,6 +42,11 @@ public abstract class SystemClientBaseTest extends 
IntegrationTest {
 
         // then
         assertThat(stats).isNotNull();
+        assertThat(stats.processId()).isNotNull();
+        assertThat(stats.hostname()).isNotEmpty();
+        assertThat(stats.threadsCount()).isNotNull();
+        assertThat(stats.freeDiskSpace()).isNotNull();
+        assertThat(stats.totalDiskSpace()).isNotNull();
     }
 
     @Test
diff --git 
a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java
 
b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java
index 53c8f58bc..320221dab 100644
--- 
a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java
+++ 
b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java
@@ -21,11 +21,15 @@ package org.apache.iggy.client.blocking.http;
 
 import org.apache.iggy.message.Message;
 import org.apache.iggy.message.PolledMessages;
+import org.apache.iggy.system.CacheMetricsKey;
+import org.apache.iggy.system.Stats;
+import org.assertj.core.data.Offset;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import tools.jackson.databind.ObjectMapper;
 
+import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 
@@ -38,6 +42,121 @@ class ObjectMapperTest {
     @Nested
     class Deserialization {
 
+        @Nested
+        @DisplayName("Stats")
+        class StatsDeserialization {
+
+            @Test
+            void shouldDeserializeAllStatsFields() {
+                // given
+                String json = """
+                        {
+                          "process_id": 1234,
+                          "cpu_usage": 12.5,
+                          "total_cpu_usage": 50.0,
+                          "memory_usage": "1000000",
+                          "total_memory": "8000000",
+                          "available_memory": "7000000",
+                          "run_time": 3600,
+                          "start_time": 1000000,
+                          "read_bytes": "500",
+                          "written_bytes": "600",
+                          "messages_size_bytes": "1000",
+                          "streams_count": 5,
+                          "topics_count": 10,
+                          "partitions_count": 20,
+                          "segments_count": 100,
+                          "messages_count": 5000,
+                          "clients_count": 3,
+                          "consumer_groups_count": 2,
+                          "hostname": "localhost",
+                          "os_name": "Linux",
+                          "os_version": "5.4.0",
+                          "kernel_version": "5.4.0-1",
+                          "iggy_server_version": "0.7.1",
+                          "iggy_server_semver": 701000,
+                          "cache_metrics": {
+                            "1-1-1": {"hits": 100, "misses": 10, "hit_ratio": 
0.91}
+                          },
+                          "threads_count": 42,
+                          "free_disk_space": "500000000000",
+                          "total_disk_space": "1000000000000"
+                        }
+                        """;
+
+                // when
+                var stats = objectMapper.readValue(json, Stats.class);
+
+                // then
+                assertThat(stats.processId()).isEqualTo(1234L);
+                assertThat(stats.cpuUsage()).isEqualTo(12.5f);
+                assertThat(stats.totalCpuUsage()).isEqualTo(50.0f);
+                assertThat(stats.memoryUsage()).isEqualTo("1000000");
+                assertThat(stats.streamsCount()).isEqualTo(5L);
+                assertThat(stats.hostname()).isEqualTo("localhost");
+                assertThat(stats.osName()).isEqualTo("Linux");
+                assertThat(stats.iggyServerVersion()).isEqualTo("0.7.1");
+                
assertThat(stats.iggyServerSemver()).isPresent().hasValue(701000L);
+                var key = new CacheMetricsKey(1L, 1L, 1L);
+                assertThat(stats.cacheMetrics()).hasSize(1);
+                assertThat(stats.cacheMetrics()).containsKey(key);
+                
assertThat(stats.cacheMetrics().get(key).hits()).isEqualTo(BigInteger.valueOf(100));
+                
assertThat(stats.cacheMetrics().get(key).misses()).isEqualTo(BigInteger.valueOf(10));
+                
assertThat(stats.cacheMetrics().get(key).hitRatio()).isCloseTo(0.91f, 
Offset.offset(0.01f));
+                assertThat(stats.threadsCount()).isEqualTo(42L);
+                assertThat(stats.freeDiskSpace()).isEqualTo("500000000000");
+                assertThat(stats.totalDiskSpace()).isEqualTo("1000000000000");
+            }
+
+            @Test
+            void shouldDeserializeStatsWithNullSemverAndEmptyCacheMetrics() {
+                // given
+                String json = """
+                        {
+                          "process_id": 1234,
+                          "cpu_usage": 12.5,
+                          "total_cpu_usage": 50.0,
+                          "memory_usage": "1000000",
+                          "total_memory": "8000000",
+                          "available_memory": "7000000",
+                          "run_time": 3600,
+                          "start_time": 1000000,
+                          "read_bytes": "500",
+                          "written_bytes": "600",
+                          "messages_size_bytes": "1000",
+                          "streams_count": 5,
+                          "topics_count": 10,
+                          "partitions_count": 20,
+                          "segments_count": 100,
+                          "messages_count": 5000,
+                          "clients_count": 3,
+                          "consumer_groups_count": 2,
+                          "hostname": "localhost",
+                          "os_name": "Linux",
+                          "os_version": "5.4.0",
+                          "kernel_version": "5.4.0-1",
+                          "iggy_server_version": "0.6.1",
+                          "iggy_server_semver": null,
+                          "cache_metrics": {},
+                          "threads_count": 8,
+                          "free_disk_space": "250000000000",
+                          "total_disk_space": "500000000000"
+                        }
+                        """;
+
+                // when
+                var stats = objectMapper.readValue(json, Stats.class);
+
+                // then
+                assertThat(stats.iggyServerVersion()).isEqualTo("0.6.1");
+                assertThat(stats.iggyServerSemver()).isEmpty();
+                assertThat(stats.cacheMetrics()).isEmpty();
+                assertThat(stats.threadsCount()).isEqualTo(8L);
+                assertThat(stats.freeDiskSpace()).isEqualTo("250000000000");
+                assertThat(stats.totalDiskSpace()).isEqualTo("500000000000");
+            }
+        }
+
         @Nested
         @DisplayName("PolledMessages")
         class PolledMessagesDeserialization {
diff --git 
a/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java
 
b/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java
index 6d8dfa8c4..f592ce5a5 100644
--- 
a/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java
+++ 
b/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java
@@ -24,6 +24,7 @@ import io.netty.buffer.Unpooled;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.iggy.message.HeaderKey;
 import org.apache.iggy.message.HeaderKind;
+import org.apache.iggy.system.CacheMetricsKey;
 import org.apache.iggy.topic.CompressionAlgorithm;
 import org.apache.iggy.user.UserStatus;
 import org.junit.jupiter.api.Nested;
@@ -421,10 +422,7 @@ class BytesDeserializerTest {
     @Nested
     class StatsDeserialization {
 
-        @Test
-        void shouldDeserializeStats() {
-            // given
-            ByteBuf buffer = Unpooled.buffer();
+        private void writeBaseStatsFields(ByteBuf buffer) {
             buffer.writeIntLE(1234); // process ID
             buffer.writeFloatLE(12.5f); // CPU usage
             buffer.writeFloatLE(50.0f); // total CPU usage
@@ -451,6 +449,24 @@ class BytesDeserializerTest {
             buffer.writeBytes("5.4.0".getBytes());
             buffer.writeIntLE(7); // kernel version length
             buffer.writeBytes("5.4.0-1".getBytes());
+        }
+
+        private void writeServerVersionFields(ByteBuf buffer) {
+            buffer.writeIntLE(5); // iggy_server_version length
+            buffer.writeBytes("0.6.1".getBytes());
+            buffer.writeIntLE(601000); // iggy_server_semver
+        }
+
+        @Test
+        void shouldDeserializeStats() {
+            // given
+            ByteBuf buffer = Unpooled.buffer();
+            writeBaseStatsFields(buffer);
+            writeServerVersionFields(buffer);
+            buffer.writeIntLE(0); // cache_metrics (empty)
+            buffer.writeIntLE(42); // threads count
+            writeU64(buffer, BigInteger.valueOf(500_000_000_000L)); // free 
disk space
+            writeU64(buffer, BigInteger.valueOf(1_000_000_000_000L)); // total 
disk space
 
             // when
             var stats = readStats(buffer);
@@ -458,9 +474,101 @@ class BytesDeserializerTest {
             // then
             assertThat(stats.processId()).isEqualTo(1234L);
             assertThat(stats.cpuUsage()).isEqualTo(12.5f);
+            assertThat(stats.totalCpuUsage()).isEqualTo(50.0f);
+            assertThat(stats.memoryUsage()).isEqualTo("1000000");
+            assertThat(stats.totalMemory()).isEqualTo("8000000");
+            assertThat(stats.availableMemory()).isEqualTo("7000000");
+            assertThat(stats.runTime()).isEqualTo(BigInteger.valueOf(3600));
+            
assertThat(stats.startTime()).isEqualTo(BigInteger.valueOf(1000000));
+            assertThat(stats.readBytes()).isEqualTo("500");
+            assertThat(stats.writtenBytes()).isEqualTo("600");
+            assertThat(stats.messagesSizeBytes()).isEqualTo("1000");
             assertThat(stats.streamsCount()).isEqualTo(5L);
+            assertThat(stats.topicsCount()).isEqualTo(10L);
+            assertThat(stats.partitionsCount()).isEqualTo(20L);
+            assertThat(stats.segmentsCount()).isEqualTo(100L);
+            
assertThat(stats.messagesCount()).isEqualTo(BigInteger.valueOf(5000));
+            assertThat(stats.clientsCount()).isEqualTo(3L);
+            assertThat(stats.consumerGroupsCount()).isEqualTo(2L);
             assertThat(stats.hostname()).isEqualTo("localhost");
             assertThat(stats.osName()).isEqualTo("Linux");
+            assertThat(stats.osVersion()).isEqualTo("5.4.0");
+            assertThat(stats.kernelVersion()).isEqualTo("5.4.0-1");
+            assertThat(stats.iggyServerVersion()).isEqualTo("0.6.1");
+            assertThat(stats.iggyServerSemver()).isPresent().hasValue(601000L);
+            assertThat(stats.cacheMetrics()).isEmpty();
+            assertThat(stats.threadsCount()).isEqualTo(42L);
+            assertThat(stats.freeDiskSpace()).isEqualTo("500000000000");
+            assertThat(stats.totalDiskSpace()).isEqualTo("1000000000000");
+        }
+
+        @Test
+        void shouldDeserializeStatsWithNullSemver() {
+            // given
+            ByteBuf buffer = Unpooled.buffer();
+            writeBaseStatsFields(buffer);
+            buffer.writeIntLE(5); // iggy_server_version length
+            buffer.writeBytes("0.6.1".getBytes());
+            buffer.writeIntLE(0); // iggy_server_semver = 0 (None)
+            buffer.writeIntLE(0); // cache_metrics (empty)
+            buffer.writeIntLE(8); // threads count
+            writeU64(buffer, BigInteger.valueOf(100_000_000_000L)); // free 
disk space
+            writeU64(buffer, BigInteger.valueOf(200_000_000_000L)); // total 
disk space
+
+            // when
+            var stats = readStats(buffer);
+
+            // then
+            assertThat(stats.iggyServerVersion()).isEqualTo("0.6.1");
+            assertThat(stats.iggyServerSemver()).isEmpty();
+            assertThat(stats.threadsCount()).isEqualTo(8L);
+        }
+
+        @Test
+        void shouldDeserializeStatsWithCacheMetrics() {
+            // given
+            ByteBuf buffer = Unpooled.buffer();
+            writeBaseStatsFields(buffer);
+            writeServerVersionFields(buffer);
+            // cache_metrics (2 entries)
+            buffer.writeIntLE(2); // count
+            // entry 1: key "1-1-1"
+            buffer.writeIntLE(1); // stream_id
+            buffer.writeIntLE(1); // topic_id
+            buffer.writeIntLE(1); // partition_id
+            writeU64(buffer, BigInteger.valueOf(100)); // hits
+            writeU64(buffer, BigInteger.valueOf(10)); // misses
+            buffer.writeFloatLE(0.91f); // hit_ratio
+            // entry 2: key "1-2-1"
+            buffer.writeIntLE(1); // stream_id
+            buffer.writeIntLE(2); // topic_id
+            buffer.writeIntLE(1); // partition_id
+            writeU64(buffer, BigInteger.valueOf(200)); // hits
+            writeU64(buffer, BigInteger.valueOf(50)); // misses
+            buffer.writeFloatLE(0.80f); // hit_ratio
+            // new fields
+            buffer.writeIntLE(16); // threads count
+            writeU64(buffer, BigInteger.valueOf(250_000_000_000L)); // free 
disk space
+            writeU64(buffer, BigInteger.valueOf(500_000_000_000L)); // total 
disk space
+
+            // when
+            var stats = readStats(buffer);
+
+            // then
+            var key1 = new CacheMetricsKey(1L, 1L, 1L);
+            var key2 = new CacheMetricsKey(1L, 2L, 1L);
+            assertThat(stats.cacheMetrics()).hasSize(2);
+            assertThat(stats.cacheMetrics()).containsKey(key1);
+            assertThat(stats.cacheMetrics()).containsKey(key2);
+            
assertThat(stats.cacheMetrics().get(key1).hits()).isEqualTo(BigInteger.valueOf(100));
+            
assertThat(stats.cacheMetrics().get(key1).misses()).isEqualTo(BigInteger.valueOf(10));
+            assertThat(stats.cacheMetrics().get(key1).hitRatio())
+                    .isCloseTo(0.91f, 
org.assertj.core.data.Offset.offset(0.01f));
+            
assertThat(stats.cacheMetrics().get(key2).hits()).isEqualTo(BigInteger.valueOf(200));
+            
assertThat(stats.cacheMetrics().get(key2).misses()).isEqualTo(BigInteger.valueOf(50));
+            assertThat(stats.threadsCount()).isEqualTo(16L);
+            assertThat(stats.freeDiskSpace()).isEqualTo("250000000000");
+            assertThat(stats.totalDiskSpace()).isEqualTo("500000000000");
         }
     }
 

Reply via email to