Skip to content

Commit 12a6a27

Browse files
authored
Merge pull request #31 from brogowski/main
Include parameters in cache key
2 parents feba268 + e5226c7 commit 12a6a27

5 files changed

Lines changed: 60 additions & 28 deletions

File tree

src/main/java/com/degustudios/bitbucket/repository/validators/IdempotentlyCachedDotnetFormatRefValidatorWrapper.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.degustudios.dotnetformat.DotnetFormatCommandResult;
66
import com.degustudios.executors.IdempotentExecutor;
77
import com.degustudios.executors.IdempotentExecutorBuilder;
8+
import org.apache.commons.lang3.StringUtils;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011
import org.springframework.beans.factory.annotation.Autowired;
@@ -44,7 +45,11 @@ public DotnetFormatCommandResult validate(RepositoryRef ref, List<String> params
4445
}
4546
}
4647

47-
private static String mapToKey(RepositoryRef x) {
48-
return x.getRepository().getId() + "/" + x.getLatestCommit();
48+
private static String mapToKey(RepositoryRef x, List<String> params) {
49+
return x.getRepository().getId()
50+
+ "/"
51+
+ x.getLatestCommit()
52+
+ "/"
53+
+ StringUtils.join(params, ' ');
4954
}
5055
}

src/main/java/com/degustudios/executors/IdempotentExecutor.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ public class IdempotentExecutor<T,R> {
1616
private final ConcurrentHashMap<String, LazyInitializer<Future<R>>> cache = new ConcurrentHashMap<>();
1717
private final ExecutorService executor = Executors.newCachedThreadPool();
1818
private final BiFunction<T, List<String>, R> executeFunc;
19-
private final Function<T, String> mapToKeyFunc;
19+
private final BiFunction<T, List<String>, String> mapToKeyFunc;
2020
private final Function<R, Boolean> shouldCacheFunc;
2121

22-
public IdempotentExecutor(BiFunction<T, List<String>, R> executeFunc, Function<T, String> mapToKeyFunc, Function<R, Boolean> shouldCacheFunc) {
22+
public IdempotentExecutor(BiFunction<T, List<String>, R> executeFunc, BiFunction<T, List<String>, String> mapToKeyFunc, Function<R, Boolean> shouldCacheFunc) {
2323
this.executeFunc = executeFunc;
2424
this.mapToKeyFunc = mapToKeyFunc;
2525
this.shouldCacheFunc = shouldCacheFunc;
@@ -33,7 +33,7 @@ public Future<R> execute(T param1, List<String> param2) throws ConcurrentExcepti
3333
private LazyInitializer<Future<R>> getEarliestScheduledLazyTaskFor(T param1, List<String> param2) {
3434
LazyInitializer<Future<R>> justScheduledLazyTask = wrapWithLazy((() -> scheduleForExecution(param1, param2)));
3535
LazyInitializer<Future<R>> earlierScheduledLazyTask = cache.putIfAbsent(
36-
mapToKeyFunc.apply(param1),
36+
mapToKeyFunc.apply(param1, param2),
3737
justScheduledLazyTask);
3838

3939
if (earlierScheduledLazyTask != null) {
@@ -56,7 +56,7 @@ private Future<R> scheduleForExecution(T param1, List<String> param2) {
5656
return executor.submit(() -> {
5757
R result = executeFunc.apply(param1, param2);
5858
if (!Boolean.TRUE.equals(shouldCacheFunc.apply(result))) {
59-
cache.remove(mapToKeyFunc.apply(param1));
59+
cache.remove(mapToKeyFunc.apply(param1, param2));
6060
}
6161
return result;
6262
});

src/main/java/com/degustudios/executors/IdempotentExecutorBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
public class IdempotentExecutorBuilder {
1111
public <T,R> IdempotentExecutor<T,R> build(
1212
BiFunction<T, List<String>, R> executeFunc,
13-
Function<T, String> mapToKeyFunc,
13+
BiFunction<T, List<String>, String> mapToKeyFunc,
1414
Function<R, Boolean> shouldCacheFunc) {
1515
return new IdempotentExecutor<>(executeFunc, mapToKeyFunc, shouldCacheFunc);
1616
}

src/test/java/ut/com/degustudios/bitbucket/repository/validators/IdempotentlyCachedDotnetFormatRefValidatorWrapperTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.degustudios.dotnetformat.DotnetFormatCommandResult;
88
import com.degustudios.executors.IdempotentExecutor;
99
import com.degustudios.executors.IdempotentExecutorBuilder;
10+
import org.apache.commons.lang3.StringUtils;
1011
import org.apache.commons.lang3.concurrent.ConcurrentException;
1112
import org.junit.Before;
1213
import org.junit.Test;
@@ -19,9 +20,8 @@
1920
import java.util.Arrays;
2021
import java.util.List;
2122
import java.util.concurrent.CompletableFuture;
22-
import java.util.function.Function;
2323
import java.util.function.BiFunction;
24-
import java.util.stream.Collectors;
24+
import java.util.function.Function;
2525

2626
import static org.hamcrest.CoreMatchers.is;
2727
import static org.hamcrest.CoreMatchers.notNullValue;
@@ -46,7 +46,7 @@ public class IdempotentlyCachedDotnetFormatRefValidatorWrapperTest {
4646
@Captor
4747
private ArgumentCaptor<BiFunction<RepositoryRef, List<String>, DotnetFormatCommandResult>> scheduleFuncCaptor;
4848
@Captor
49-
private ArgumentCaptor<Function<RepositoryRef, String>> keyMapFuncCaptor;
49+
private ArgumentCaptor<BiFunction<RepositoryRef, List<String>, String>> keyMapFuncCaptor;
5050
@Captor
5151
private ArgumentCaptor<Function<DotnetFormatCommandResult, Boolean>> shouldCacheFuncCaptor;
5252
@Mock
@@ -57,7 +57,7 @@ public class IdempotentlyCachedDotnetFormatRefValidatorWrapperTest {
5757
@Before
5858
public void initialize(){
5959
when(executorBuilder.<RepositoryRef, DotnetFormatCommandResult>build(any(), any(), any())).thenReturn(executor);
60-
params = Arrays.asList(new String[]{"--check"});
60+
params = Arrays.asList("--check", "-v");
6161
}
6262

6363
@Test
@@ -73,7 +73,7 @@ public void schedulesDotnetFormatValidation() throws ConcurrentException {
7373
}
7474

7575
@Test
76-
public void correctlyMapsRefToKey() throws ConcurrentException {
76+
public void correctlyMapsRefAndParamsToKey() throws ConcurrentException {
7777
String commitId = "19873";
7878
int repositoryId = 124;
7979
when(ref.getLatestCommit()).thenReturn(commitId);
@@ -84,7 +84,9 @@ public void correctlyMapsRefToKey() throws ConcurrentException {
8484
runValidatorWrapper();
8585

8686
verify(executorBuilder).build(any(), keyMapFuncCaptor.capture(), any());
87-
assertThat(keyMapFuncCaptor.getValue().apply(ref), is(repositoryId + "/" + commitId));
87+
assertThat(
88+
keyMapFuncCaptor.getValue().apply(ref, params),
89+
is(repositoryId + "/" + commitId + '/' + StringUtils.join(params, ' ')));
8890
}
8991

9092
@Test
@@ -118,8 +120,6 @@ public void doesNotCacheExecutedCorrectlyUnableToLocateDotNetCliExitCodeDotNetFo
118120
assertDoesNotCacheExecutedCorrectlyDotNetFormatExecutions(UnableToLocateDotNetCliExitCode);
119121
}
120122

121-
122-
123123
@Test
124124
public void doesCacheExecutedCorrectlyZeroExitCodeDotNetFormatExecutions() throws ConcurrentException {
125125
assertDoesCacheExecutedCorrectlyDotNetFormatExecutions(0);

src/test/java/ut/com/degustudios/executors/IdempotentExecutorTest.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ut.com.degustudios.executors;
22

33
import com.degustudios.executors.IdempotentExecutor;
4+
import org.apache.commons.lang3.StringUtils;
45
import org.apache.commons.lang3.concurrent.ConcurrentException;
56
import org.junit.Test;
67
import org.junit.runner.RunWith;
@@ -10,6 +11,7 @@
1011

1112
import java.util.Arrays;
1213
import java.util.Collections;
14+
import java.util.LinkedList;
1315
import java.util.List;
1416
import java.util.concurrent.ExecutionException;
1517
import java.util.concurrent.Future;
@@ -20,13 +22,16 @@
2022
import java.util.stream.Collectors;
2123

2224
import static org.awaitility.Awaitility.await;
25+
import static org.hamcrest.CoreMatchers.hasItem;
2326
import static org.hamcrest.CoreMatchers.is;
2427
import static org.junit.Assert.assertThat;
2528

2629
@RunWith(MockitoJUnitRunner.class)
2730
public class IdempotentExecutorTest {
2831
private static final int TIMEOUT_IN_MS = 1000;
2932
private static final Logger logger = LoggerFactory.getLogger(IdempotentExecutorTest.class);
33+
private static final List<String> params = Arrays.asList("--mockParameter", "--otherParameter");
34+
private static final String input = "INPUT PARAMETER";
3035

3136
@Test
3237
public void executeReturnsFutureValueFromFunction() throws ExecutionException, InterruptedException {
@@ -35,9 +40,19 @@ public void executeReturnsFutureValueFromFunction() throws ExecutionException, I
3540
}
3641

3742
@Test
38-
public void executePassesParameterToFunction() throws ExecutionException, InterruptedException {
39-
String returnValue = "TEST";
40-
assertThat(tryExecute((String x, List<String> y) -> x, returnValue).get(), is(returnValue));
43+
public void executePassesInputParametersToKeyMapFunction() throws ExecutionException, InterruptedException {
44+
String expectedKey = input + StringUtils.join(params);
45+
List<String> mapFuncCalls = new LinkedList<>();
46+
47+
tryExecute(
48+
(String x, List<String> y) -> x,
49+
(String x, List<String> y) -> {
50+
mapFuncCalls.add(x + StringUtils.join(y));
51+
return "STUB";
52+
}).get();
53+
54+
assertThat(mapFuncCalls.stream().distinct().count(), is(1L));
55+
assertThat(mapFuncCalls, hasItem(expectedKey));
4156
}
4257

4358
@Test
@@ -94,31 +109,43 @@ public void willExecuteTheSameParametersAgainIfCacheFunctionReturnsFalse() {
94109
assertThat(invocationCounter.get(), is(2));
95110
}
96111

112+
private <T,R> IdempotentExecutor<T,R> getDefaultKeyCacheAllExecutor(
113+
BiFunction<T, List<String>, R> executeFunc,
114+
BiFunction<T, List<String>, String> mapKeyFunc) {
115+
return new IdempotentExecutor<>(executeFunc, mapKeyFunc, r -> true);
116+
}
117+
97118
private <T,R> IdempotentExecutor<T,R> getDefaultKeyCacheAllExecutor(BiFunction<T, List<String>, R> executeFunc) {
98-
return new IdempotentExecutor<>(executeFunc, Object::toString, r -> true);
119+
return new IdempotentExecutor<>(executeFunc, IdempotentExecutorTest::defaultKeyMapper, r -> true);
99120
}
100121

101122
private <T,R> IdempotentExecutor<T,R> getDefaultKeyCacheNoneExecutor(BiFunction<T, List<String>, R> executeFunc) {
102-
return new IdempotentExecutor<>(executeFunc, Object::toString, r -> false);
123+
return new IdempotentExecutor<>(executeFunc, IdempotentExecutorTest::defaultKeyMapper, r -> false);
124+
}
125+
126+
private static <T> String defaultKeyMapper (T input, List<String> params) {
127+
return input.toString() + StringUtils.join(params);
103128
}
104129

105-
private <T> Future<String> tryExecute(BiFunction<T,List<String>,String> executeFunc, String x) {
106-
return tryExecute(getDefaultKeyCacheAllExecutor(executeFunc), x);
130+
private Future<String> tryExecute(
131+
BiFunction<String,List<String>,String> executeFunc,
132+
BiFunction<String,List<String>,String> mapFunc) {
133+
return tryExecute(getDefaultKeyCacheAllExecutor(executeFunc, mapFunc));
107134
}
108135

109-
private <T> Future<String> tryExecute(BiFunction<T,List<String>,String> executeFunc) {
136+
private Future<String> tryExecute(BiFunction<String,List<String>,String> executeFunc) {
110137
return tryExecute(getDefaultKeyCacheAllExecutor(executeFunc));
111138
}
112139

113-
private Future<String> tryExecute(IdempotentExecutor executor) {
114-
return tryExecute(executor, "STUB");
140+
private <R> Future<R> tryExecute(IdempotentExecutor<String,R> executor) {
141+
return tryExecute(executor, input);
115142
}
116143

117-
private <V> Future<V> tryExecute(IdempotentExecutor executor, V x) {
144+
private <T, R> Future<R> tryExecute(IdempotentExecutor<T, R> executor, T x) {
118145
try {
119-
return executor.execute(x, Collections.singletonList("--mockParameter"));
146+
return executor.execute(x, params);
120147
} catch (ConcurrentException e) {
121-
logger.error("Exception for conurent excception for exectur: {}", executor, e);
148+
logger.error("Exception for concurrent exception for executor: {}", executor, e);
122149
}
123150
return null;
124151
}

0 commit comments

Comments
 (0)