diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 81b554416..6010218e0 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -11,7 +11,7 @@ dependencies {
implementation(project(":module:crypto-demo"))
implementation(project(":module:request-demo"))
implementation(project(":module:store-demo"))
- implementation(project(":module:store-inmemory"))
+ implementation(project(":module:store-redis"))
implementation(project(":service"))
implementation(project(":service:module"))
implementation(libs.dagger.dagger)
@@ -20,7 +20,9 @@ dependencies {
implementation(libs.jackson.databind)
implementation(libs.jakartaInject.api)
implementation(libs.jakartaValidation.api)
+ implementation(libs.jedis.jedis) // for Dagger
implementation(libs.okhttp.okhttp)
+ implementation(libs.redisEmbedded.redis) // for demo
implementation(libs.retrofit.retrofit)
testImplementation(project(":testing"))
diff --git a/app/src/main/java/org/example/age/app/AvsApp.java b/app/src/main/java/org/example/age/app/AvsApp.java
index c253d3bd3..e31fc7c2a 100644
--- a/app/src/main/java/org/example/age/app/AvsApp.java
+++ b/app/src/main/java/org/example/age/app/AvsApp.java
@@ -14,7 +14,7 @@
import org.example.age.module.crypto.demo.DemoAvsCryptoModule;
import org.example.age.module.request.demo.DemoAccountIdModule;
import org.example.age.module.store.demo.DemoAvsAccountStoreModule;
-import org.example.age.module.store.inmemory.InMemoryPendingStoreModule;
+import org.example.age.module.store.redis.RedisPendingStoreModule;
import org.example.age.service.AvsServiceModule;
import org.example.age.service.module.request.RequestContextProvider;
@@ -52,7 +52,7 @@ public void run(AvsAppConfig appConfig, Environment env) {
DemoAccountIdModule.class,
AvsClientModule.class,
DemoAvsAccountStoreModule.class,
- InMemoryPendingStoreModule.class,
+ RedisPendingStoreModule.class,
DemoAvsCryptoModule.class,
AvsConfigModule.class,
EnvModule.class,
diff --git a/app/src/main/java/org/example/age/app/SiteApp.java b/app/src/main/java/org/example/age/app/SiteApp.java
index ea7863059..addfc033b 100644
--- a/app/src/main/java/org/example/age/app/SiteApp.java
+++ b/app/src/main/java/org/example/age/app/SiteApp.java
@@ -14,7 +14,7 @@
import org.example.age.module.crypto.demo.DemoSiteCryptoModule;
import org.example.age.module.request.demo.DemoAccountIdModule;
import org.example.age.module.store.demo.DemoSiteAccountStoreModule;
-import org.example.age.module.store.inmemory.InMemoryPendingStoreModule;
+import org.example.age.module.store.redis.RedisPendingStoreModule;
import org.example.age.service.SiteServiceModule;
import org.example.age.service.module.request.RequestContextProvider;
@@ -52,7 +52,7 @@ public void run(SiteAppConfig appConfig, Environment env) {
DemoAccountIdModule.class,
SiteClientModule.class,
DemoSiteAccountStoreModule.class,
- InMemoryPendingStoreModule.class,
+ RedisPendingStoreModule.class,
DemoSiteCryptoModule.class,
SiteConfigModule.class,
EnvModule.class,
diff --git a/app/src/main/java/org/example/age/app/config/AvsAppConfig.java b/app/src/main/java/org/example/age/app/config/AvsAppConfig.java
index 5b74a70d8..15180ee30 100644
--- a/app/src/main/java/org/example/age/app/config/AvsAppConfig.java
+++ b/app/src/main/java/org/example/age/app/config/AvsAppConfig.java
@@ -7,6 +7,7 @@
import org.example.age.module.client.AvsClientsConfig;
import org.example.age.module.crypto.demo.AvsKeysConfig;
import org.example.age.module.store.demo.AvsStoresConfig;
+import org.example.age.module.store.redis.RedisConfig;
import org.example.age.service.AvsServiceConfig;
/** Configuration for the application. */
@@ -20,6 +21,10 @@ public final class AvsAppConfig extends Configuration {
@NotNull
private AvsClientsConfig clients;
+ @Valid
+ @NotNull
+ private RedisConfig redis;
+
@Valid
@NotNull
private AvsStoresConfig stores;
@@ -48,6 +53,16 @@ public void setClients(AvsClientsConfig clients) {
this.clients = clients;
}
+ @JsonProperty
+ public RedisConfig getRedis() {
+ return redis;
+ }
+
+ @JsonProperty
+ public void setRedis(RedisConfig redis) {
+ this.redis = redis;
+ }
+
@JsonProperty
public AvsStoresConfig getStores() {
return stores;
diff --git a/app/src/main/java/org/example/age/app/config/AvsConfigModule.java b/app/src/main/java/org/example/age/app/config/AvsConfigModule.java
index 96ebfe8d7..73f70d230 100644
--- a/app/src/main/java/org/example/age/app/config/AvsConfigModule.java
+++ b/app/src/main/java/org/example/age/app/config/AvsConfigModule.java
@@ -5,6 +5,7 @@
import org.example.age.module.client.AvsClientsConfig;
import org.example.age.module.crypto.demo.AvsKeysConfig;
import org.example.age.module.store.demo.AvsStoresConfig;
+import org.example.age.module.store.redis.RedisConfig;
import org.example.age.service.AvsServiceConfig;
/**
@@ -12,6 +13,7 @@
*
* - {@link AvsServiceConfig}
*
- {@link AvsClientsConfig}
+ *
- {@link RedisConfig}
*
- {@link AvsStoresConfig}
*
- {@link AvsKeysConfig}
*
@@ -31,6 +33,11 @@ static AvsClientsConfig provieAvsClientsConfig(AvsAppConfig appConfig) {
return appConfig.getClients();
}
+ @Provides
+ static RedisConfig provideRedisConfig(AvsAppConfig appConfig) {
+ return appConfig.getRedis();
+ }
+
@Provides
static AvsStoresConfig provideAvsStoresConfig(AvsAppConfig appConfig) {
return appConfig.getStores();
diff --git a/app/src/main/java/org/example/age/app/config/SiteAppConfig.java b/app/src/main/java/org/example/age/app/config/SiteAppConfig.java
index 10341bbd2..c074d90d2 100644
--- a/app/src/main/java/org/example/age/app/config/SiteAppConfig.java
+++ b/app/src/main/java/org/example/age/app/config/SiteAppConfig.java
@@ -6,6 +6,7 @@
import jakarta.validation.constraints.NotNull;
import org.example.age.module.client.SiteClientsConfig;
import org.example.age.module.crypto.demo.SiteKeysConfig;
+import org.example.age.module.store.redis.RedisConfig;
import org.example.age.service.SiteServiceConfig;
/** Configuration for the application. */
@@ -19,6 +20,10 @@ public final class SiteAppConfig extends Configuration {
@NotNull
private SiteClientsConfig clients;
+ @Valid
+ @NotNull
+ private RedisConfig redis;
+
@Valid
@NotNull
private SiteKeysConfig keys;
@@ -43,6 +48,16 @@ public void setClients(SiteClientsConfig clients) {
this.clients = clients;
}
+ @JsonProperty
+ public RedisConfig getRedis() {
+ return redis;
+ }
+
+ @JsonProperty
+ public void setRedis(RedisConfig redis) {
+ this.redis = redis;
+ }
+
@JsonProperty
public SiteKeysConfig getKeys() {
return keys;
diff --git a/app/src/main/java/org/example/age/app/config/SiteConfigModule.java b/app/src/main/java/org/example/age/app/config/SiteConfigModule.java
index f469180c0..eaccb54cf 100644
--- a/app/src/main/java/org/example/age/app/config/SiteConfigModule.java
+++ b/app/src/main/java/org/example/age/app/config/SiteConfigModule.java
@@ -4,6 +4,7 @@
import dagger.Provides;
import org.example.age.module.client.SiteClientsConfig;
import org.example.age.module.crypto.demo.SiteKeysConfig;
+import org.example.age.module.store.redis.RedisConfig;
import org.example.age.service.SiteServiceConfig;
/**
@@ -11,6 +12,7 @@
*
* - {@link SiteServiceConfig}
*
- {@link SiteClientsConfig}
+ *
- {@link RedisConfig}
*
- {@link SiteKeysConfig}
*
*
@@ -29,6 +31,11 @@ static SiteClientsConfig provieSiteClientsConfig(SiteAppConfig appConfig) {
return appConfig.getClients();
}
+ @Provides
+ static RedisConfig provideRedisConfig(SiteAppConfig appConfig) {
+ return appConfig.getRedis();
+ }
+
@Provides
static SiteKeysConfig provideSiteKeysConfig(SiteAppConfig appConfig) {
return appConfig.getKeys();
diff --git a/app/src/main/java/org/example/age/demo/Demo.java b/app/src/main/java/org/example/age/demo/Demo.java
index da0a2b200..352cb605f 100644
--- a/app/src/main/java/org/example/age/demo/Demo.java
+++ b/app/src/main/java/org/example/age/demo/Demo.java
@@ -28,8 +28,9 @@ public final class Demo {
/** Main method. */
@SuppressWarnings("CatchAndPrintStackTrace")
- public static void main(String[] args) {
+ public static void main(String[] args) throws IOException {
try {
+ DemoInfra.startRedis();
DemoInfra.startServer(checkMyAge, "config-check-my-age.yaml");
DemoInfra.startServer(crackle, "config-crackle.yaml");
DemoInfra.startServer(pop, "config-pop.yaml");
@@ -41,7 +42,7 @@ public static void main(String[] args) {
} catch (Exception e) {
e.printStackTrace();
} finally {
- System.exit(0);
+ DemoInfra.stop();
}
}
diff --git a/app/src/main/java/org/example/age/demo/DemoInfra.java b/app/src/main/java/org/example/age/demo/DemoInfra.java
index 530e93320..f6a13dbfe 100644
--- a/app/src/main/java/org/example/age/demo/DemoInfra.java
+++ b/app/src/main/java/org/example/age/demo/DemoInfra.java
@@ -5,20 +5,30 @@
import io.dropwizard.core.Application;
import io.dropwizard.jackson.Jackson;
import java.io.File;
+import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.example.age.api.client.retrofit.ApiClient;
+import redis.embedded.RedisServer;
/** Client/server infrastructure for the demo. */
public final class DemoInfra {
+ private static RedisServer redis;
+
private static final OkHttpClient httpClient = new OkHttpClient();
private static final ObjectWriter objectWriter = Jackson.newObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.writerWithDefaultPrettyPrinter();
+ /** Starts Redis. */
+ public static void startRedis() throws IOException {
+ redis = new RedisServer(6379);
+ redis.start();
+ }
+
/** Starts an application. */
public static void startServer(Application> app, String configPath) throws Exception {
app.run("server", getResourcePath(configPath));
@@ -41,6 +51,12 @@ public static ObjectWriter getObjectWriter() {
return objectWriter;
}
+ /** Stops everything (and terminates the application). */
+ public static void stop() throws IOException {
+ redis.stop();
+ System.exit(0);
+ }
+
/** Get the absolute path of a resource file. */
private static String getResourcePath(String relativePath) throws URISyntaxException {
ClassLoader classLoader = DemoInfra.class.getClassLoader();
diff --git a/app/src/main/resources/config-check-my-age.yaml b/app/src/main/resources/config-check-my-age.yaml
index fdddae698..55e4facdf 100644
--- a/app/src/main/resources/config-check-my-age.yaml
+++ b/app/src/main/resources/config-check-my-age.yaml
@@ -9,6 +9,9 @@ clients:
crackle: http://localhost:8080
pop: http://localhost:8081
+redis:
+ url: http://localhost:6379
+
stores:
verifiedAccounts:
John Smith:
diff --git a/app/src/main/resources/config-crackle.yaml b/app/src/main/resources/config-crackle.yaml
index 89b87641d..08c8b27f5 100644
--- a/app/src/main/resources/config-crackle.yaml
+++ b/app/src/main/resources/config-crackle.yaml
@@ -5,6 +5,9 @@ service:
clients:
avsUrl: http://localhost:9090
+redis:
+ url: http://localhost:6379
+
keys:
signing:
wX: 61340499596180719707288738669477306360190613239883629564918816825111167687915
diff --git a/app/src/main/resources/config-pop.yaml b/app/src/main/resources/config-pop.yaml
index c56d09fc5..3f925e001 100644
--- a/app/src/main/resources/config-pop.yaml
+++ b/app/src/main/resources/config-pop.yaml
@@ -5,6 +5,9 @@ service:
clients:
avsUrl: http://localhost:9090
+redis:
+ url: http://localhost:6379
+
keys:
signing:
wX: 61340499596180719707288738669477306360190613239883629564918816825111167687915
diff --git a/app/src/test/java/org/example/age/app/AppVerificationTest.java b/app/src/test/java/org/example/age/app/AppVerificationTest.java
index a36f40230..931f3d3a2 100644
--- a/app/src/test/java/org/example/age/app/AppVerificationTest.java
+++ b/app/src/test/java/org/example/age/app/AppVerificationTest.java
@@ -15,6 +15,7 @@
import org.example.age.app.config.AvsAppConfig;
import org.example.age.app.config.SiteAppConfig;
import org.example.age.app.testing.TestServiceClient;
+import org.example.age.testing.RedisExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import retrofit2.Response;
@@ -29,6 +30,9 @@ public final class AppVerificationTest {
private static final DropwizardAppExtension avsApp =
new DropwizardAppExtension<>(AvsApp.class, ResourceHelpers.resourceFilePath("config-avs.yaml"));
+ @RegisterExtension
+ private static final RedisExtension redis = new RedisExtension(6379);
+
@RegisterExtension
private static final TestServiceClient siteClient =
new TestServiceClient<>(8080, "username", SiteApi.class);
diff --git a/app/src/test/resources/config-avs.yaml b/app/src/test/resources/config-avs.yaml
index f9f90144c..a8e3e3eac 100644
--- a/app/src/test/resources/config-avs.yaml
+++ b/app/src/test/resources/config-avs.yaml
@@ -7,6 +7,9 @@ clients:
siteUrls:
site: http://localhost:8080
+redis:
+ url: http://localhost:6379
+
stores:
verifiedAccounts:
person:
diff --git a/app/src/test/resources/config-site.yaml b/app/src/test/resources/config-site.yaml
index a0d705f32..006046882 100644
--- a/app/src/test/resources/config-site.yaml
+++ b/app/src/test/resources/config-site.yaml
@@ -5,6 +5,9 @@ service:
clients:
avsUrl: http://localhost:9090
+redis:
+ url: http://localhost:6379
+
keys:
signing:
wX: 61340499596180719707288738669477306360190613239883629564918816825111167687915
diff --git a/module/store-inmemory/build.gradle.kts b/module/store-inmemory/build.gradle.kts
deleted file mode 100644
index 3f5d93925..000000000
--- a/module/store-inmemory/build.gradle.kts
+++ /dev/null
@@ -1,18 +0,0 @@
-plugins {
- `java-library`
- id("org.example.age.java-conventions")
-}
-
-dependencies {
- annotationProcessor(libs.dagger.compiler)
-
- api(project(":service:module"))
- api(libs.dagger.dagger)
- api(libs.jackson.databind)
- implementation(libs.guava.guava)
- implementation(libs.jakartaInject.api)
-
- testAnnotationProcessor(libs.dagger.compiler)
-
- testImplementation(project(":testing"))
-}
diff --git a/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStore.java b/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStore.java
deleted file mode 100644
index ccd67133f..000000000
--- a/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStore.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.example.age.module.store.inmemory;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import com.google.common.collect.Maps;
-import java.io.IOException;
-import java.time.Duration;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import org.example.age.service.module.store.PendingStore;
-
-/** Implementation of {@link PendingStore}. Requires sticky sessions to work in a distributed environment. */
-final class InMemoryPendingStore implements PendingStore {
-
- private final BiMap store = Maps.synchronizedBiMap(HashBiMap.create());
- private final ObjectMapper mapper;
- private final Class valueType;
- private final ScheduledExecutorService scheduledExecutor;
-
- public InMemoryPendingStore(ObjectMapper mapper, Class valueType, ScheduledExecutorService scheduledExecutor) {
- this.mapper = mapper;
- this.valueType = valueType;
- this.scheduledExecutor = scheduledExecutor;
- }
-
- @SuppressWarnings("FutureReturnValueIgnored")
- @Override
- public CompletionStage put(String key, V value, OffsetDateTime expiration) {
- Duration expiresIn = Duration.between(OffsetDateTime.now(ZoneOffset.UTC), expiration);
- if (expiresIn.isNegative() || expiresIn.isZero()) {
- return CompletableFuture.completedFuture(null);
- }
-
- JsonHolder jsonHolder = serialize(value);
- store.put(key, jsonHolder);
- Runnable expirationTask = () -> store.inverse().remove(jsonHolder);
- scheduledExecutor.schedule(expirationTask, expiresIn.toMillis(), TimeUnit.MILLISECONDS);
- return CompletableFuture.completedFuture(null);
- }
-
- @Override
- public CompletionStage> tryGet(String key) {
- Optional maybeValue = Optional.ofNullable(store.get(key)).map(this::deserialize);
- return CompletableFuture.completedFuture(maybeValue);
- }
-
- @Override
- public CompletionStage> tryRemove(String key) {
- Optional maybeValue = Optional.ofNullable(store.remove(key)).map(this::deserialize);
- return CompletableFuture.completedFuture(maybeValue);
- }
-
- /** Serializes the value to JSON. */
- private JsonHolder serialize(V value) {
- try {
- return new JsonHolder(mapper.writeValueAsString(value));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Deserializes a value from JSON. */
- private V deserialize(JsonHolder jsonHolder) {
- try {
- return mapper.readValue(jsonHolder.value, valueType);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Holder for a JSON value. {@link #equals(Object)} behaves like {@code ==}. */
- private static final class JsonHolder {
-
- public final String value;
-
- public JsonHolder(String value) {
- this.value = value;
- }
- }
-}
diff --git a/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStoreModule.java b/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStoreModule.java
deleted file mode 100644
index 64cd7c90f..000000000
--- a/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStoreModule.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.example.age.module.store.inmemory;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import dagger.Binds;
-import dagger.Module;
-import java.util.concurrent.ScheduledExecutorService;
-import org.example.age.service.module.store.PendingStoreRepository;
-
-/**
- * Dagger module that binds {@link PendingStoreRepository}.
- *
- * Depends on an unbound...
- *
- * - {@link ObjectMapper}
- *
- {@link ScheduledExecutorService}
- *
- *
- * Requires sticky sessions to work in a distributed environment.
- */
-@Module
-public interface InMemoryPendingStoreModule {
-
- @Binds
- PendingStoreRepository bindPendingStoreRepository(InMemoryPendingStoreRepository impl);
-}
diff --git a/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStoreRepository.java b/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStoreRepository.java
deleted file mode 100644
index cc0a2c382..000000000
--- a/module/store-inmemory/src/main/java/org/example/age/module/store/inmemory/InMemoryPendingStoreRepository.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.example.age.module.store.inmemory;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ScheduledExecutorService;
-import org.example.age.service.module.store.PendingStore;
-import org.example.age.service.module.store.PendingStoreRepository;
-
-/** Implementation of {@link PendingStoreRepository}. Requires sticky sessions to work in a distributed environment. */
-@Singleton
-final class InMemoryPendingStoreRepository implements PendingStoreRepository {
-
- private final Map> stores = Collections.synchronizedMap(new HashMap<>());
- private final ObjectMapper mapper;
- private final ScheduledExecutorService scheduledExecutor;
-
- @Inject
- public InMemoryPendingStoreRepository(ObjectMapper mapper, ScheduledExecutorService scheduledExecutor) {
- this.mapper = mapper;
- this.scheduledExecutor = scheduledExecutor;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public PendingStore get(String name, Class valueType) {
- return (PendingStore) stores.computeIfAbsent(name, n -> createPendingStore(valueType));
- }
-
- /** Creates a {@link PendingStore}. */
- private PendingStore createPendingStore(Class valueType) {
- return new InMemoryPendingStore<>(mapper, valueType, scheduledExecutor);
- }
-}
diff --git a/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/InMemoryPendingStoreTest.java b/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/InMemoryPendingStoreTest.java
deleted file mode 100644
index 05e835d29..000000000
--- a/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/InMemoryPendingStoreTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.example.age.module.store.inmemory;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.example.age.testing.CompletionStageTesting.getCompleted;
-
-import dagger.Component;
-import jakarta.inject.Singleton;
-import java.time.Duration;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
-import java.util.Optional;
-import org.example.age.module.store.inmemory.testing.FakeScheduledExecutorService;
-import org.example.age.module.store.inmemory.testing.TestDependenciesModule;
-import org.example.age.service.module.store.PendingStore;
-import org.example.age.service.module.store.PendingStoreRepository;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-public final class InMemoryPendingStoreTest {
-
- private PendingStore store;
- private FakeScheduledExecutorService scheduledExecutor;
-
- @BeforeEach
- public void createPendingStoreEtAl() {
- TestComponent component = TestComponent.create();
- PendingStoreRepository stores = component.pendingStoreRepository();
- store = stores.get("name", Integer.class);
- scheduledExecutor = component.fakeScheduledExecutorService();
- }
-
- @Test
- public void putThenRemove() {
- getCompleted(store.put("key", 1, expiresIn(5)));
- Optional maybeValue1 = getCompleted(store.tryRemove("key"));
- assertThat(maybeValue1).hasValue(1);
- Optional maybeValue2 = getCompleted(store.tryGet("key"));
- assertThat(maybeValue2).isEmpty();
- }
-
- @Test
- public void expire() {
- getCompleted(store.put("key", 1, expiresIn(5)));
- scheduledExecutor.runScheduledTask();
- Optional maybeValue = getCompleted(store.tryGet("key"));
- assertThat(maybeValue).isEmpty();
- }
-
- @Test
- public void putExpiredValue() {
- getCompleted(store.put("key", 1, expiresIn(-5)));
- Optional maybeValue = getCompleted(store.tryGet("key"));
- assertThat(maybeValue).isEmpty();
- }
-
- @Test
- public void expireOldValue() {
- getCompleted(store.put("key", 1, expiresIn(5)));
- getCompleted(store.put("key", 1, expiresIn(5)));
- scheduledExecutor.runScheduledTask();
- Optional maybeValue = getCompleted(store.tryGet("key"));
- assertThat(maybeValue).hasValue(1);
- }
-
- @Test
- public void putSameValue() {
- getCompleted(store.put("key1", 1, expiresIn(5)));
- getCompleted(store.put("key2", 1, expiresIn(5)));
- Optional maybeValue1 = getCompleted(store.tryGet("key1"));
- assertThat(maybeValue1).hasValue(1);
- Optional maybeValue2 = getCompleted(store.tryGet("key2"));
- assertThat(maybeValue2).hasValue(1);
- }
-
- private static OffsetDateTime expiresIn(int minutes) {
- return OffsetDateTime.now(ZoneOffset.UTC).plus(Duration.ofMinutes(minutes));
- }
-
- /** Dagger component for the stores. */
- @Component(modules = {InMemoryPendingStoreModule.class, TestDependenciesModule.class})
- @Singleton
- interface TestComponent {
-
- static TestComponent create() {
- return DaggerInMemoryPendingStoreTest_TestComponent.create();
- }
-
- PendingStoreRepository pendingStoreRepository();
-
- FakeScheduledExecutorService fakeScheduledExecutorService();
- }
-}
diff --git a/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/testing/FakeScheduledExecutorService.java b/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/testing/FakeScheduledExecutorService.java
deleted file mode 100644
index 015388fc8..000000000
--- a/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/testing/FakeScheduledExecutorService.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.example.age.module.store.inmemory.testing;
-
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.ArrayDeque;
-import java.util.Collection;
-import java.util.List;
-import java.util.Queue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-/** Fake implementation of {@link ScheduledExecutorService}. Scheduled tasks are manually run in FIFO order. */
-@Singleton
-public final class FakeScheduledExecutorService implements ScheduledExecutorService {
-
- private final Queue scheduledTasks = new ArrayDeque<>();
-
- @Inject
- public FakeScheduledExecutorService() {}
-
- @Override
- public ScheduledFuture> schedule(Runnable task, long delay, TimeUnit unit) {
- scheduledTasks.add(task);
- return null;
- }
-
- /** Runs a single scheduled task. */
- public void runScheduledTask() {
- scheduledTasks.remove().run();
- }
-
- // unsupported operations
-
- @Override
- public ScheduledFuture schedule(Callable task, long delay, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ScheduledFuture> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ScheduledFuture> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean awaitTermination(long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List> invokeAll(Collection extends Callable> tasks) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List> invokeAll(Collection extends Callable> tasks, long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public T invokeAny(Collection extends Callable> tasks) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public T invokeAny(Collection extends Callable> tasks, long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isShutdown() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isTerminated() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void shutdown() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List shutdownNow() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Future> submit(Runnable task) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Future submit(Runnable task, T result) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Future submit(Callable task) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void execute(Runnable task) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/testing/TestDependenciesModule.java b/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/testing/TestDependenciesModule.java
deleted file mode 100644
index 03ccb53ec..000000000
--- a/module/store-inmemory/src/test/java/org/example/age/module/store/inmemory/testing/TestDependenciesModule.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.example.age.module.store.inmemory.testing;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import dagger.Binds;
-import dagger.Module;
-import java.util.concurrent.ScheduledExecutorService;
-import org.example.age.testing.TestEnvModule;
-
-/**
- * Dagger module that binds...
- *
- * - {@link ObjectMapper}
- *
- {@link ScheduledExecutorService} (with {@link FakeScheduledExecutorService})
- *
- */
-@Module(includes = TestEnvModule.class)
-public interface TestDependenciesModule {
-
- @Binds
- ScheduledExecutorService bindScheduledExecutorService(FakeScheduledExecutorService impl);
-}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 8f581e860..44f37f82c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -7,7 +7,6 @@ include(
"module:request-demo",
"module:client",
"module:store-redis",
- "module:store-inmemory",
"module:store-demo",
"module:crypto-demo",
"app",