diff --git a/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheConfiguration.java b/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheConfiguration.java
index 031e8b445..9c883684a 100644
--- a/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheConfiguration.java
+++ b/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheConfiguration.java
@@ -65,6 +65,7 @@ public static CouchbaseCacheConfiguration defaultCacheConfig() {
*
{@link String} to {@link byte byte[]} using UTF-8 encoding.
* {@link SimpleKey} to {@link String}
*
+ *
* @param registry must not be {@literal null}.
*/
public static void registerDefaultConverters(final ConverterRegistry registry) {
@@ -85,6 +86,18 @@ public CouchbaseCacheConfiguration entryExpiry(final Duration expiry) {
valueTranscoder, collectionName);
}
+ /**
+ * Set the expiry to apply for cache entries. Use {@link Duration#ZERO} to declare an eternal cache.
+ *
+ * @param collectionName must not be {@literal null}.
+ * @return new {@link CouchbaseCacheConfiguration}.
+ */
+ public CouchbaseCacheConfiguration collection(final String collectionName) {
+ Assert.notNull(collectionName, "collectionName must not be null!");
+ return new CouchbaseCacheConfiguration(expiry, cacheNullValues, usePrefix, keyPrefix, conversionService,
+ valueTranscoder, collectionName);
+ }
+
/**
* Sets a custom transcoder to use for reads and writes.
*
diff --git a/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheCollectionIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheCollectionIntegrationTests.java
new file mode 100644
index 000000000..f434f9ca2
--- /dev/null
+++ b/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheCollectionIntegrationTests.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2022 the original author or authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.couchbase.cache;
+
+import com.couchbase.client.java.query.QueryOptions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.data.couchbase.util.Capabilities;
+import org.springframework.data.couchbase.util.ClusterType;
+import org.springframework.data.couchbase.util.CollectionAwareIntegrationTests;
+import org.springframework.data.couchbase.util.IgnoreWhen;
+
+import java.util.UUID;
+
+import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * CouchbaseCache tests Theses tests rely on a cb server running.
+ *
+ * @author Michael Reiche
+ */
+@IgnoreWhen(clusterTypes = ClusterType.MOCKED, missesCapabilities = { Capabilities.COLLECTIONS })
+class CouchbaseCacheCollectionIntegrationTests extends CollectionAwareIntegrationTests {
+
+ volatile CouchbaseCache cache;
+
+ @BeforeEach
+ @Override
+ public void beforeEach() {
+ super.beforeEach();
+ cache = CouchbaseCacheManager.create(couchbaseTemplate.getCouchbaseClientFactory()).createCouchbaseCache("myCache",
+ CouchbaseCacheConfiguration.defaultCacheConfig().collection("my_collection"));
+ clear(cache);
+ }
+
+ private void clear(CouchbaseCache c) {
+ couchbaseTemplate.getCouchbaseClientFactory().getCluster().query("SELECT count(*) from `" + bucketName() + "`",
+ QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS));
+ c.clear();
+ couchbaseTemplate.getCouchbaseClientFactory().getCluster().query("SELECT count(*) from `" + bucketName() + "`",
+ QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS));
+ }
+
+
+ @Test
+ void cachePutGet() {
+ CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
+ CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
+ assertNull(cache.get(user1.getId())); // was not put -> cacheMiss
+ cache.put(user1.getId(), user1); // put user1
+ cache.put(user2.getId(), user2); // put user2
+ assertEquals(user1, cache.get(user1.getId()).get()); // get user1
+ assertEquals(user2, cache.get(user2.getId()).get()); // get user2
+ }
+
+ @Test
+ void cacheEvict() {
+ CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
+ CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
+ cache.put(user1.getId(), user1); // put user1
+ cache.put(user2.getId(), user2); // put user2
+ cache.evict(user1.getId()); // evict user1
+ assertEquals(user2, cache.get(user2.getId()).get()); // get user2 -> present
+ }
+
+ @Test
+ void cacheHitMiss() {
+ CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
+ CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
+ assertNull(cache.get(user2.getId())); // get user2 -> cacheMiss
+ cache.put(user1.getId(), null); // cache a null
+ assertNotNull(cache.get(user1.getId())); // cacheHit null
+ assertNull(cache.get(user1.getId()).get()); // fetch cached null
+ }
+
+ @Test
+ void cachePutIfAbsent() {
+ CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
+ CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
+ assertNull(cache.putIfAbsent(user1.getId(), user1)); // should put user1, return null
+ assertEquals(user1, cache.putIfAbsent(user1.getId(), user2).get()); // should not put user2, should return user1
+ assertEquals(user1, cache.get(user1.getId()).get()); // user1.getId() is still user1
+ }
+
+}