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

hgruszecki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new 07c9c7cca feat(java): add new stats fields to match server sysinfo 
updates (#2969)
07c9c7cca is described below

commit 07c9c7cca2c44a65dc4e22f7f4efae9d9f453035
Author: Maciej Modzelewski <[email protected]>
AuthorDate: Fri Mar 20 11:19:38 2026 +0100

    feat(java): add new stats fields to match server sysinfo updates (#2969)
---
 .../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..aa99b292c 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": 620474,
+                          "cpu_usage": 0.46409693,
+                          "total_cpu_usage": 11.344592,
+                          "memory_usage": "147412 KiB",
+                          "total_memory": "65766576 KiB",
+                          "available_memory": "28197044 KiB",
+                          "run_time": 300000000,
+                          "start_time": 1773843141000000,
+                          "read_bytes": "255156 KiB",
+                          "written_bytes": "1027432 KiB",
+                          "messages_size_bytes": "69.092 KB",
+                          "streams_count": 1,
+                          "topics_count": 2,
+                          "partitions_count": 2,
+                          "segments_count": 2,
+                          "messages_count": 521,
+                          "clients_count": 2,
+                          "consumer_groups_count": 0,
+                          "hostname": "localhost",
+                          "os_name": "Ubuntu",
+                          "os_version": "Linux (Ubuntu 24.04)",
+                          "kernel_version": "6.18.7-76061807-generic",
+                          "iggy_server_version": "0.7.2-edge.1",
+                          "iggy_server_semver": 7002,
+                          "cache_metrics": {
+                            "1-1-1": {"hits": 100, "misses": 10, "hit_ratio": 
0.91}
+                          },
+                          "threads_count": 13,
+                          "free_disk_space": "150073704 KiB",
+                          "total_disk_space": "959392552 KiB"
+                        }
+                        """;
+
+                // when
+                var stats = objectMapper.readValue(json, Stats.class);
+
+                // then
+                assertThat(stats.processId()).isEqualTo(620474L);
+                assertThat(stats.cpuUsage()).isCloseTo(0.46409693f, 
Offset.offset(0.0001f));
+                assertThat(stats.totalCpuUsage()).isCloseTo(11.344592f, 
Offset.offset(0.0001f));
+                assertThat(stats.memoryUsage()).isEqualTo("147412 KiB");
+                assertThat(stats.streamsCount()).isEqualTo(1L);
+                assertThat(stats.hostname()).isEqualTo("localhost");
+                assertThat(stats.osName()).isEqualTo("Ubuntu");
+                
assertThat(stats.iggyServerVersion()).isEqualTo("0.7.2-edge.1");
+                
assertThat(stats.iggyServerSemver()).isPresent().hasValue(7002L);
+                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(13L);
+                assertThat(stats.freeDiskSpace()).isEqualTo("150073704 KiB");
+                assertThat(stats.totalDiskSpace()).isEqualTo("959392552 KiB");
+            }
+
+            @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