You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rc...@apache.org on 2020/06/10 04:10:38 UTC

[james-project] 02/08: JAMES-3170 Add Grafana board for CachedLatencyMetric, CachedHitMetric, CachedMissMetric.

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

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit b80b772ead580304a12de6c644e819dd6db22f0d
Author: duc91 <du...@gmail.com>
AuthorDate: Thu Jun 4 15:56:06 2020 +0700

    JAMES-3170 Add Grafana board for CachedLatencyMetric, CachedHitMetric,CachedMissMetric.
---
 .../CacheBlobStore-15911761170000-dashboard.json   | 346 +++++++++++++++++++++
 .../blob/cassandra/cache/CachedBlobStore.java      |  56 ++--
 .../cassandra/cache/CassandraBlobStoreCache.java   |   9 +-
 .../blob/cassandra/cache/CachedBlobStoreTest.java  | 296 +++++++++++++-----
 .../cache/CassandraBlobStoreCacheTest.java         |   2 +-
 5 files changed, 606 insertions(+), 103 deletions(-)

diff --git a/grafana-reporting/CacheBlobStore-15911761170000-dashboard.json b/grafana-reporting/CacheBlobStore-15911761170000-dashboard.json
new file mode 100644
index 0000000..c51b0bb
--- /dev/null
+++ b/grafana-reporting/CacheBlobStore-15911761170000-dashboard.json
@@ -0,0 +1,346 @@
+{
+  "annotations": {
+    "list": [
+      {
+        "builtIn": 1,
+        "datasource": "-- Grafana --",
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "name": "Annotations & Alerts",
+        "type": "dashboard"
+      }
+    ]
+  },
+  "description": "",
+  "editable": true,
+  "gnetId": null,
+  "graphTooltip": 0,
+  "id": 4,
+  "links": [],
+  "panels": [
+    {
+      "collapsed": false,
+      "datasource": null,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 0
+      },
+      "id": 4,
+      "panels": [],
+      "title": "CachedBlobStore_Metric",
+      "type": "row"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fieldConfig": {
+        "defaults": {
+          "custom": {}
+        },
+        "overrides": []
+      },
+      "fill": 1,
+      "fillGradient": 0,
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 0,
+        "y": 1
+      },
+      "hiddenSeries": false,
+      "id": 2,
+      "legend": {
+        "avg": false,
+        "current": false,
+        "max": false,
+        "min": false,
+        "show": true,
+        "total": false,
+        "values": false
+      },
+      "lines": true,
+      "linewidth": 1,
+      "nullPointMode": "connected",
+      "options": {
+        "dataLinks": []
+      },
+      "percentage": false,
+      "pointradius": 2,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "bucketAggs": [
+            {
+              "field": "@timestamp",
+              "id": "2",
+              "settings": {
+                "interval": "auto",
+                "min_doc_count": 0,
+                "trimEdges": 0
+              },
+              "type": "date_histogram"
+            }
+          ],
+          "metrics": [
+            {
+              "field": "p50",
+              "id": "1",
+              "meta": {},
+              "settings": {},
+              "type": "avg"
+            },
+            {
+              "field": "p75",
+              "id": "3",
+              "meta": {},
+              "settings": {},
+              "type": "avg"
+            },
+            {
+              "field": "p95",
+              "id": "4",
+              "meta": {},
+              "settings": {},
+              "type": "avg"
+            },
+            {
+              "field": "p99",
+              "id": "5",
+              "meta": {},
+              "settings": {},
+              "type": "avg"
+            }
+          ],
+          "query": "name:\"blobstoreCacheLatency\"",
+          "refId": "A",
+          "timeField": "@timestamp"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeRegions": [],
+      "timeShift": null,
+      "title": "Latency",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "ms",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fieldConfig": {
+        "defaults": {
+          "custom": {}
+        },
+        "overrides": []
+      },
+      "fill": 1,
+      "fillGradient": 0,
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 12,
+        "y": 1
+      },
+      "hiddenSeries": false,
+      "id": 8,
+      "legend": {
+        "avg": false,
+        "current": false,
+        "max": false,
+        "min": false,
+        "show": true,
+        "total": false,
+        "values": false
+      },
+      "lines": true,
+      "linewidth": 1,
+      "nullPointMode": "connected",
+      "options": {
+        "dataLinks": []
+      },
+      "percentage": false,
+      "pointradius": 2,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "alias": "miss",
+          "bucketAggs": [
+            {
+              "field": "@timestamp",
+              "id": "2",
+              "settings": {
+                "interval": "auto",
+                "min_doc_count": 0,
+                "trimEdges": 0
+              },
+              "type": "date_histogram"
+            }
+          ],
+          "metrics": [
+            {
+              "field": "1",
+              "id": "3",
+              "meta": {},
+              "pipelineAgg": "1",
+              "settings": {},
+              "type": "derivative"
+            }
+          ],
+          "query": "name:\"blobstoreCacheMisses\"",
+          "refId": "A",
+          "timeField": "@timestamp"
+        },
+        {
+          "alias": "hit",
+          "bucketAggs": [
+            {
+              "field": "@timestamp",
+              "id": "2",
+              "settings": {
+                "interval": "auto",
+                "min_doc_count": 0,
+                "trimEdges": 0
+              },
+              "type": "date_histogram"
+            }
+          ],
+          "metrics": [
+            {
+              "field": "1",
+              "id": "3",
+              "meta": {},
+              "pipelineAgg": "1",
+              "settings": {},
+              "type": "derivative"
+            }
+          ],
+          "query": "name:\"blobstoreCacheHits\"",
+          "refId": "B",
+          "timeField": "@timestamp"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeRegions": [],
+      "timeShift": null,
+      "title": "CachedHits/CachedMisses",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "decimals": 0,
+          "format": "locale",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "decimals": 0,
+          "format": "locale",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    }
+  ],
+  "refresh": "30s",
+  "schemaVersion": 25,
+  "style": "dark",
+  "tags": [],
+  "templating": {
+    "list": []
+  },
+  "time": {
+    "from": "now-5m",
+    "to": "now"
+  },
+  "timepicker": {
+    "refresh_intervals": [
+      "10s",
+      "30s",
+      "1m",
+      "5m",
+      "15m",
+      "30m",
+      "1h",
+      "2h",
+      "1d"
+    ]
+  },
+  "timezone": "",
+  "title": "CachedBlobstore",
+  "uid": "XbLcT6zMz",
+  "version": 5
+}
\ No newline at end of file
diff --git a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CachedBlobStore.java b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CachedBlobStore.java
index d33c52f..9acbbed 100644
--- a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CachedBlobStore.java
+++ b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CachedBlobStore.java
@@ -98,20 +98,22 @@ public class CachedBlobStore implements BlobStore {
             this.firstBytes = firstBytes;
             this.hasMore = hasMore;
         }
+
     }
 
     public static final String BACKEND = "blobStoreBackend";
-    public static final String BLOBSTORE_CACHED_LATENCY_METRIC_NAME = "blobstoreCachedLatency";
-    public static final String BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME = "blobstoreCachedHit";
-    public static final String BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME = "blobstoreCachedMiss";
 
+    public static final String BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME = "blobStoreCacheMisses";
+    public static final String BLOBSTORE_CACHED_LATENCY_METRIC_NAME = "blobStoreCacheLatency";
+    public static final String BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME = "blobStoreCacheHits";
+
+    private final MetricFactory metricFactory;
     private final Metric metricRetrieveHitCount;
     private final Metric metricRetrieveMissCount;
 
     private final BlobStoreCache cache;
     private final BlobStore backend;
     private final Integer sizeThresholdInBytes;
-    private final MetricFactory metricFactory;
 
     @Inject
     public CachedBlobStore(BlobStoreCache cache,
@@ -121,37 +123,48 @@ public class CachedBlobStore implements BlobStore {
         this.cache = cache;
         this.backend = backend;
         this.sizeThresholdInBytes = cacheConfiguration.getSizeThresholdInBytes();
+
         this.metricFactory = metricFactory;
-        metricRetrieveHitCount = metricFactory.generate(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME);
-        metricRetrieveMissCount = metricFactory.generate(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME);
+        this.metricRetrieveMissCount = metricFactory.generate(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME);
+        this.metricRetrieveHitCount = metricFactory.generate(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME);
     }
 
     @Override
     public InputStream read(BucketName bucketName, BlobId blobId) throws ObjectStoreIOException, ObjectNotFoundException {
         return Mono.just(bucketName)
             .filter(getDefaultBucketName()::equals)
-            .flatMap(ignored -> readFromCache(blobId)
-                .flatMap(this::toInputStream))
+            .flatMap(defaultBucket -> readInDefaultBucket(bucketName, blobId))
+            .switchIfEmpty(readFromBackend(bucketName, blobId))
+            .blockOptional()
+            .orElseThrow(() -> new ObjectNotFoundException(String.format("Could not retrieve blob metadata for %s", blobId.asString())));
+    }
+
+    private Mono<InputStream> readInDefaultBucket(BucketName bucketName, BlobId blobId) {
+        return readFromCache(blobId)
+            .flatMap(this::toInputStream)
             .switchIfEmpty(readFromBackend(bucketName, blobId)
                 .flatMap(inputStream ->
                     Mono.fromCallable(() -> ReadAheadInputStream.eager().of(inputStream).length(sizeThresholdInBytes))
                         .flatMap(readAheadInputStream -> putInCacheIfNeeded(bucketName, readAheadInputStream, blobId)
-                            .thenReturn(readAheadInputStream.in))))
-            .blockOptional()
-            .orElseThrow(() -> new ObjectNotFoundException(String.format("Could not retrieve blob metadata for %s", blobId)));
+                            .thenReturn(readAheadInputStream.in))));
     }
 
     @Override
     public Mono<byte[]> readBytes(BucketName bucketName, BlobId blobId) {
         return Mono.just(bucketName)
             .filter(getDefaultBucketName()::equals)
-            .flatMap(ignored -> readFromCache(blobId)
-                .switchIfEmpty(readBytesFromBackend(bucketName, blobId)
-                    .filter(this::isAbleToCache)
-                    .flatMap(bytes -> saveInCache(blobId, bytes).then(Mono.just(bytes)))))
+            .flatMap(deleteBucket -> readBytesInDefaultBucket(bucketName, blobId))
             .switchIfEmpty(readBytesFromBackend(bucketName, blobId));
     }
 
+    private Mono<byte[]> readBytesInDefaultBucket(BucketName bucketName, BlobId blobId) {
+        return readFromCache(blobId)
+            .switchIfEmpty(readBytesFromBackend(bucketName, blobId)
+                .filter(this::isAbleToCache)
+                .doOnNext(any -> metricRetrieveMissCount.increment())
+                .flatMap(bytes -> saveInCache(blobId, bytes).then(Mono.just(bytes))));
+    }
+
     @Override
     public Mono<BlobId> save(BucketName bucketName, byte[] bytes, StoragePolicy storagePolicy) {
         return Mono.from(backend.save(bucketName, bytes, storagePolicy))
@@ -213,6 +226,7 @@ public class CachedBlobStore implements BlobStore {
     private Mono<Void> putInCacheIfNeeded(BucketName bucketName, ReadAheadInputStream readAhead, BlobId blobId) {
         return Mono.justOrEmpty(readAhead.firstBytes)
             .filter(bytes -> isAbleToCache(readAhead, bucketName))
+            .doOnNext(any -> metricRetrieveMissCount.increment())
             .flatMap(bytes -> Mono.from(cache.cache(blobId, bytes)));
     }
 
@@ -244,16 +258,16 @@ public class CachedBlobStore implements BlobStore {
         return Mono.fromCallable(() -> new ByteArrayInputStream(bytes));
     }
 
-    private Mono<InputStream> readFromBackend(BucketName bucketName, BlobId blobId) {
-        return Mono.fromCallable(() -> backend.read(bucketName, blobId));
-    }
-
     private Mono<byte[]> readFromCache(BlobId blobId) {
         return Mono.from(metricFactory.runPublishingTimerMetric(BLOBSTORE_CACHED_LATENCY_METRIC_NAME, cache.read(blobId)))
-            .doOnNext(bytes -> metricRetrieveHitCount.increment());
+            .doOnNext(any -> metricRetrieveHitCount.increment());
+    }
+
+    private Mono<InputStream> readFromBackend(BucketName bucketName, BlobId blobId) {
+        return Mono.fromCallable(() -> backend.read(bucketName, blobId));
     }
 
     private Mono<byte[]> readBytesFromBackend(BucketName bucketName, BlobId blobId) {
-        return Mono.from(backend.readBytes(bucketName, blobId)).doOnNext(bytes -> metricRetrieveMissCount.increment());
+        return Mono.from(backend.readBytes(bucketName, blobId));
     }
 }
diff --git a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCache.java b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCache.java
index f2211a5..5584a6c 100644
--- a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCache.java
+++ b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCache.java
@@ -64,7 +64,8 @@ public class CassandraBlobStoreCache implements BlobStoreCache {
 
     @Inject
     @VisibleForTesting
-    CassandraBlobStoreCache(@Named(InjectionNames.CACHE) Session session, CassandraCacheConfiguration cacheConfiguration) {
+    CassandraBlobStoreCache(@Named(InjectionNames.CACHE) Session session,
+                            CassandraCacheConfiguration cacheConfiguration) {
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
         this.insertStatement = prepareInsert(session);
         this.selectStatement = prepareSelect(session);
@@ -81,13 +82,11 @@ public class CassandraBlobStoreCache implements BlobStoreCache {
 
     @Override
     public Mono<byte[]> read(BlobId blobId) {
-        return cassandraAsyncExecutor
-            .executeSingleRow(
+        return cassandraAsyncExecutor.executeSingleRow(
                 selectStatement.bind()
                     .setString(ID, blobId.asString())
                     .setConsistencyLevel(ONE)
-                    .setReadTimeoutMillis(readTimeOutFromDataBase)
-            )
+                    .setReadTimeoutMillis(readTimeOutFromDataBase))
             .map(this::toByteArray);
     }
 
diff --git a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CachedBlobStoreTest.java b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CachedBlobStoreTest.java
index 884f14d..ad6c3d3 100644
--- a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CachedBlobStoreTest.java
+++ b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CachedBlobStoreTest.java
@@ -25,9 +25,8 @@ import static org.apache.james.blob.api.BucketName.DEFAULT;
 import static org.apache.james.blob.cassandra.cache.BlobStoreCacheContract.EIGHT_KILOBYTES;
 import static org.apache.james.blob.cassandra.cache.CachedBlobStore.BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME;
 import static org.apache.james.blob.cassandra.cache.CachedBlobStore.BLOBSTORE_CACHED_LATENCY_METRIC_NAME;
+import static org.apache.james.blob.cassandra.cache.CachedBlobStore.BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
@@ -42,11 +41,13 @@ import org.apache.james.blob.api.BlobStoreContract;
 import org.apache.james.blob.api.BucketName;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.api.ObjectNotFoundException;
+import org.apache.james.blob.api.TestBlobId;
 import org.apache.james.blob.cassandra.CassandraBlobModule;
 import org.apache.james.blob.cassandra.CassandraBlobStore;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
 import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
@@ -76,8 +77,8 @@ public class CachedBlobStoreTest implements BlobStoreContract {
             .sizeThresholdInBytes(EIGHT_KILOBYTES.length + 1)
             .timeOut(Duration.ofSeconds(60))
             .build();
-        cache = new CassandraBlobStoreCache(cassandra.getConf(), cacheConfig);
         metricFactory = new RecordingMetricFactory();
+        cache = new CassandraBlobStoreCache(cassandra.getConf(), cacheConfig);
         testee = new CachedBlobStore(cache, backend, cacheConfig, metricFactory);
     }
 
@@ -103,9 +104,9 @@ public class CachedBlobStoreTest implements BlobStoreContract {
     public void shouldNotCacheWhenNotDefaultBucketName() {
         BlobId blobId = Mono.from(testee().save(TEST_BUCKETNAME, EIGHT_KILOBYTES, SIZE_BASED)).block();
 
-        SoftAssertions.assertSoftly(ignored -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(Mono.from(backend.readBytes(TEST_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
+        SoftAssertions.assertSoftly(soflty -> {
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(backend.readBytes(TEST_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
         });
     }
 
@@ -113,9 +114,9 @@ public class CachedBlobStoreTest implements BlobStoreContract {
     public void shouldNotCacheWhenDefaultBucketNameAndBigByteDataAndSizeBase() {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, TWELVE_MEGABYTES, SIZE_BASED)).block();
 
-        SoftAssertions.assertSoftly(ignored -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(TWELVE_MEGABYTES);
+        SoftAssertions.assertSoftly(soflty -> {
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(TWELVE_MEGABYTES);
         });
     }
 
@@ -124,8 +125,8 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, EIGHT_KILOBYTES, SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).block()).containsExactly(EIGHT_KILOBYTES);
-            assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
+            soflty.assertThat(Mono.from(cache.read(blobId)).block()).containsExactly(EIGHT_KILOBYTES);
+            soflty.assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
         });
     }
 
@@ -134,8 +135,8 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, EIGHT_KILOBYTES, HIGH_PERFORMANCE)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).block()).containsExactly(EIGHT_KILOBYTES);
-            assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
+            soflty.assertThat(Mono.from(cache.read(blobId)).block()).containsExactly(EIGHT_KILOBYTES);
+            soflty.assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
         });
     }
 
@@ -144,8 +145,8 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, EIGHT_KILOBYTES, LOW_COST)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EIGHT_KILOBYTES);
         });
     }
 
@@ -154,8 +155,8 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, new ByteArrayInputStream(EMPTY_BYTEARRAY), SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block())).hasSameContentAs(new ByteArrayInputStream(EMPTY_BYTEARRAY));
-            assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EMPTY_BYTEARRAY);
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block())).hasSameContentAs(new ByteArrayInputStream(EMPTY_BYTEARRAY));
+            soflty.assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EMPTY_BYTEARRAY);
         });
     }
 
@@ -164,8 +165,8 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, EMPTY_BYTEARRAY, SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block())).hasSameContentAs(new ByteArrayInputStream(EMPTY_BYTEARRAY));
-            assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EMPTY_BYTEARRAY);
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block())).hasSameContentAs(new ByteArrayInputStream(EMPTY_BYTEARRAY));
+            soflty.assertThat(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()).containsExactly(EMPTY_BYTEARRAY);
         });
     }
 
@@ -174,9 +175,9 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES), SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
-            assertThat(new ByteArrayInputStream(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
         });
     }
@@ -186,9 +187,9 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
-            assertThat(new ByteArrayInputStream(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
         });
     }
@@ -197,11 +198,11 @@ public class CachedBlobStoreTest implements BlobStoreContract {
     public void shouldRemoveBothInCacheAndBackendWhenDefaultBucketName() {
         BlobId blobId = Mono.from(testee().save(DEFAULT_BUCKETNAME, EIGHT_KILOBYTES, SIZE_BASED)).block();
 
-        SoftAssertions.assertSoftly(ignored -> {
-            assertThatCode(Mono.from(testee().delete(DEFAULT_BUCKETNAME, blobId))::block)
+        SoftAssertions.assertSoftly(soflty -> {
+            soflty.assertThatCode(Mono.from(testee().delete(DEFAULT_BUCKETNAME, blobId))::block)
                 .doesNotThrowAnyException();
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThatThrownBy(() -> Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block())
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThatThrownBy(() -> Mono.from(backend.readBytes(DEFAULT_BUCKETNAME, blobId)).block())
                 .isInstanceOf(ObjectNotFoundException.class);
         });
     }
@@ -211,10 +212,10 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(new ByteArrayInputStream(Mono.from(testee().readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(testee().readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
-            assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
         });
     }
@@ -224,10 +225,10 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(testee().read(DEFAULT_BUCKETNAME, blobId))
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(testee().read(DEFAULT_BUCKETNAME, blobId))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
-            assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(cache.read(blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
         });
     }
@@ -237,10 +238,10 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(backend.save(TEST_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(new ByteArrayInputStream(Mono.from(testee().readBytes(TEST_BUCKETNAME, blobId)).block()))
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(testee().readBytes(TEST_BUCKETNAME, blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
         });
     }
 
@@ -249,10 +250,10 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(backend.save(TEST_BUCKETNAME, new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES), SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(testee().read(TEST_BUCKETNAME, blobId))
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(testee().read(TEST_BUCKETNAME, blobId))
                 .hasSameContentAs(new ByteArrayInputStream(APPROXIMATELY_FIVE_KILOBYTES));
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
         });
     }
 
@@ -261,10 +262,10 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, new ByteArrayInputStream(TWELVE_MEGABYTES), SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(new ByteArrayInputStream(Mono.from(testee().readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(new ByteArrayInputStream(Mono.from(testee().readBytes(DEFAULT_BUCKETNAME, blobId)).block()))
                 .hasSameContentAs(new ByteArrayInputStream(TWELVE_MEGABYTES));
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
         });
     }
 
@@ -273,43 +274,186 @@ public class CachedBlobStoreTest implements BlobStoreContract {
         BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, new ByteArrayInputStream(TWELVE_MEGABYTES), SIZE_BASED)).block();
 
         SoftAssertions.assertSoftly(soflty -> {
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
-            assertThat(testee().read(DEFAULT_BUCKETNAME, blobId))
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(testee().read(DEFAULT_BUCKETNAME, blobId))
                 .hasSameContentAs(new ByteArrayInputStream(TWELVE_MEGABYTES));
-            assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
+            soflty.assertThat(Mono.from(cache.read(blobId)).blockOptional()).isEmpty();
         });
     }
 
-    @Test
-    public void readBlobstoreCachedShouldPublishTimerMetrics() {
-        BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
-
-        testee.read(DEFAULT_BUCKETNAME, blobId);
-        testee.read(DEFAULT_BUCKETNAME, blobId);
-
-        assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME))
-            .hasSize(2);
-    }
-
-    @Test
-    public void readBlobstoreCachedShouldCountWhenHit() {
-        BlobId blobId = Mono.from(testee.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
-
-        testee.read(DEFAULT_BUCKETNAME, blobId);
-        testee.read(DEFAULT_BUCKETNAME, blobId);
-
-        assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
-            .isEqualTo(2);
-    }
-
-    @Test
-    public void readBlobstoreCachedShouldCountWhenMissed() {
-        BlobId blobId = Mono.from(testee.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
-
-        testee.read(DEFAULT_BUCKETNAME, blobId);
-        testee.read(DEFAULT_BUCKETNAME, blobId);
-
-        assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
-            .isEqualTo(2);
+    @Nested
+    class MetricsTest {
+        @Test
+        public void readBlobStoreCacheWithNoneDefaultBucketNameShouldNotImpact() {
+            BlobId blobId = Mono.from(backend.save(TEST_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+
+            testee.read(TEST_BUCKETNAME, blobId);
+            testee.read(TEST_BUCKETNAME, blobId);
+
+            SoftAssertions.assertSoftly(soflty -> {
+                assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_LATENCY_METRIC_NAME)
+                    .hasSize(0);
+            });
+        }
+
+        @Test
+        public void readBytesWithNoneDefaultBucketNameShouldNotImpact() {
+            BlobId blobId = Mono.from(backend.save(TEST_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+
+            Mono.from(testee.readBytes(TEST_BUCKETNAME, blobId)).block();
+            Mono.from(testee.readBytes(TEST_BUCKETNAME, blobId)).block();
+
+
+            SoftAssertions.assertSoftly(soflty -> {
+                assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_LATENCY_METRIC_NAME)
+                    .hasSize(0);
+            });
+        }
+
+        @Test
+        public void readBlobStoreCacheShouldPublishTimerMetrics() {
+            BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+
+            assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME)).hasSize(2);
+        }
+
+        @Test
+        public void readBytesCacheShouldPublishTimerMetrics() {
+            BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+
+            assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME)).hasSize(2);
+        }
+
+        @Test
+        public void readBytesShouldNotIncreaseCacheCounterForBigBlobs() {
+            BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, ELEVEN_KILOBYTES, SIZE_BASED)).block();
+
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+
+            SoftAssertions.assertSoftly(soflty -> {
+                assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+            });
+        }
+
+        @Test
+        public void readInputStreamShouldNotIncreaseCacheCounterForBigBlobs() {
+            BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, ELEVEN_KILOBYTES, SIZE_BASED)).block();
+
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+
+            SoftAssertions.assertSoftly(soflty -> {
+                assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+            });
+        }
+
+
+        @Test
+        public void readBlobStoreCacheShouldCountWhenHit() {
+            BlobId blobId = Mono.from(testee.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+
+            assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)).isEqualTo(2);
+        }
+
+        @Test
+        public void readBytesCacheShouldCountWhenHit() {
+            BlobId blobId = Mono.from(testee.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+
+            assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)).isEqualTo(2);
+        }
+
+
+        @Test
+        public void readBlobStoreCacheShouldCountWhenMissed() {
+            BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+            Mono.from(cache.remove(blobId)).block();
+
+            testee.read(DEFAULT_BUCKETNAME, blobId);
+
+            assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)).isEqualTo(1);
+        }
+
+        @Test
+        public void readBytesCacheShouldCountWhenMissed() {
+            BlobId blobId = Mono.from(backend.save(DEFAULT_BUCKETNAME, APPROXIMATELY_FIVE_KILOBYTES, SIZE_BASED)).block();
+            Mono.from(cache.remove(blobId)).block();
+
+            Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, blobId)).block();
+
+            assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)).isEqualTo(1);
+        }
+
+        @Test
+        public void metricsShouldNotWorkExceptLatencyWhenReadNonExistingBlob() {
+            SoftAssertions.assertSoftly(soflty -> {
+                soflty.assertThatThrownBy(() -> testee.read(DEFAULT_BUCKETNAME, new TestBlobId.Factory().randomId()))
+                    .isInstanceOf(ObjectNotFoundException.class);
+
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_LATENCY_METRIC_NAME)
+                    .hasSize(1);
+            });
+        }
+
+        @Test
+        public void metricsShouldNotWorkExceptLatencyWhenReadNonExistingBlobAsBytes() {
+            SoftAssertions.assertSoftly(soflty -> {
+                soflty.assertThatThrownBy(() -> Mono.from(testee.readBytes(DEFAULT_BUCKETNAME, new TestBlobId.Factory().randomId())).blockOptional())
+                    .isInstanceOf(ObjectNotFoundException.class);
+
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_MISS_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.countFor(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_HIT_COUNT_METRIC_NAME)
+                    .isEqualTo(0);
+                soflty.assertThat(metricFactory.executionTimesFor(BLOBSTORE_CACHED_LATENCY_METRIC_NAME))
+                    .describedAs(BLOBSTORE_CACHED_LATENCY_METRIC_NAME)
+                    .hasSize(1);
+            });
+        }
     }
 }
diff --git a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCacheTest.java b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCacheTest.java
index 10c1feb..9841853 100644
--- a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCacheTest.java
+++ b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/cache/CassandraBlobStoreCacheTest.java
@@ -27,8 +27,8 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.blob.api.BlobId;
 import org.apache.james.blob.api.HashBlobId;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 import reactor.core.publisher.Mono;


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org