Skip to content

Commit 1f7a5a7

Browse files
authored
Merge pull request #30 from digipost/countdown-targetstate
Count-down TargetState
2 parents 1e8bc4b + 8d17934 commit 1f7a5a7

File tree

3 files changed

+146
-16
lines changed

3 files changed

+146
-16
lines changed

pom.xml

+22-16
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,14 @@
5050
<dependency>
5151
<groupId>org.junit</groupId>
5252
<artifactId>junit-bom</artifactId>
53-
<version>5.8.0-M1</version>
53+
<version>5.9.1</version>
54+
<type>pom</type>
55+
<scope>import</scope>
56+
</dependency>
57+
<dependency>
58+
<groupId>org.mockito</groupId>
59+
<artifactId>mockito-bom</artifactId>
60+
<version>4.11.0</version>
5461
<type>pom</type>
5562
<scope>import</scope>
5663
</dependency>
@@ -72,13 +79,12 @@
7279
<dependency>
7380
<groupId>org.mockito</groupId>
7481
<artifactId>mockito-core</artifactId>
75-
<version>3.11.1</version>
7682
<scope>test</scope>
7783
</dependency>
7884
<dependency>
7985
<groupId>com.google.guava</groupId>
8086
<artifactId>guava</artifactId>
81-
<version>30.1.1-jre</version>
87+
<version>31.1-jre</version>
8288
<scope>test</scope>
8389
</dependency>
8490
<dependency>
@@ -90,7 +96,7 @@
9096
<dependency>
9197
<groupId>nl.jqno.equalsverifier</groupId>
9298
<artifactId>equalsverifier</artifactId>
93-
<version>3.6.1</version>
99+
<version>3.12.3</version>
94100
<scope>test</scope>
95101
</dependency>
96102
<dependency>
@@ -144,7 +150,7 @@
144150
</plugin>
145151
<plugin>
146152
<artifactId>maven-enforcer-plugin</artifactId>
147-
<version>3.0.0-M3</version>
153+
<version>3.1.0</version>
148154
<configuration>
149155
<rules>
150156
<requireMavenVersion>
@@ -169,7 +175,7 @@
169175
</plugin>
170176
<plugin>
171177
<artifactId>maven-compiler-plugin</artifactId>
172-
<version>3.8.1</version>
178+
<version>3.10.1</version>
173179
<configuration>
174180
<compilerArgs>
175181
<arg>-Xlint</arg>
@@ -178,31 +184,31 @@
178184
</plugin>
179185
<plugin>
180186
<artifactId>maven-surefire-plugin</artifactId>
181-
<version>3.0.0-M5</version>
187+
<version>3.0.0-M7</version>
182188
</plugin>
183189
<plugin>
184190
<artifactId>maven-deploy-plugin</artifactId>
185-
<version>3.0.0-M1</version>
191+
<version>3.0.0</version>
186192
</plugin>
187193
<plugin>
188194
<artifactId>maven-clean-plugin</artifactId>
189-
<version>3.1.0</version>
195+
<version>3.2.0</version>
190196
</plugin>
191197
<plugin>
192198
<artifactId>maven-dependency-plugin</artifactId>
193-
<version>3.1.2</version>
199+
<version>3.3.0</version>
194200
</plugin>
195201
<plugin>
196202
<artifactId>maven-install-plugin</artifactId>
197-
<version>3.0.0-M1</version>
203+
<version>3.1.0</version>
198204
</plugin>
199205
<plugin>
200206
<artifactId>maven-resources-plugin</artifactId>
201-
<version>3.2.0</version>
207+
<version>3.3.0</version>
202208
</plugin>
203209
<plugin>
204210
<artifactId>maven-javadoc-plugin</artifactId>
205-
<version>3.2.0</version>
211+
<version>3.4.1</version>
206212
<configuration>
207213
<tags>
208214
<tag>
@@ -215,20 +221,20 @@
215221
</plugin>
216222
<plugin>
217223
<artifactId>maven-jar-plugin</artifactId>
218-
<version>3.2.0</version>
224+
<version>3.3.0</version>
219225
</plugin>
220226
<plugin>
221227
<groupId>org.codehaus.mojo</groupId>
222228
<artifactId>versions-maven-plugin</artifactId>
223-
<version>2.8.1</version>
229+
<version>2.14.2</version>
224230
<configuration>
225231
<generateBackupPoms>false</generateBackupPoms>
226232
</configuration>
227233
</plugin>
228234
<plugin>
229235
<groupId>com.github.siom79.japicmp</groupId>
230236
<artifactId>japicmp-maven-plugin</artifactId>
231-
<version>0.15.3</version>
237+
<version>0.15.7</version>
232238
<configuration>
233239
<oldVersion>
234240
<dependency>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (C) Posten Norge AS
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package no.digipost.concurrent;
17+
18+
import java.util.concurrent.atomic.AtomicLong;
19+
20+
/**
21+
* A count down implementation of {@link TargetState},
22+
* which will count the invocations of {@link #yet()} and
23+
* return {@code true} <em>after</em> a given amount of invocations.
24+
* <p>
25+
* The implementation is thread-safe in the sense that it is guaranteed
26+
* that {@link #yet()} will return {@code false} an <em>exact</em> amount
27+
* of times, regardless of different threads invoking {@code yet()},
28+
* before switching to only return {@code true}.
29+
* <p>
30+
* This can often serve for testing purposes where you would
31+
* like a controlled amount of queries to a {@code TargetState},
32+
* before it changes.
33+
*/
34+
public final class CountDown implements TargetState {
35+
36+
private final AtomicLong count;
37+
38+
/**
39+
* Create a new count down from the given start {@code count}.
40+
*
41+
* @param count the number of invocations where {@link #yet()} will
42+
* indicate the count down is not finished yet, i.e.
43+
* the number of times {@code yet()} will return {@code false},
44+
* and switches to only return {@code true}.
45+
*/
46+
public CountDown(long count) {
47+
if (count < 0) {
48+
throw new IllegalArgumentException("negative count: " + count);
49+
}
50+
this.count = new AtomicLong(count);
51+
}
52+
53+
@Override
54+
public boolean yet() {
55+
return count.getAndUpdate(i -> i > 0 ? i - 1 : i) == 0;
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return "count down currently at " + count.get();
61+
}
62+
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (C) Posten Norge AS
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package no.digipost.concurrent;
17+
18+
import org.junit.jupiter.api.Test;
19+
20+
import java.util.stream.IntStream;
21+
22+
import static org.hamcrest.MatcherAssert.assertThat;
23+
import static org.hamcrest.Matchers.is;
24+
import static org.junit.jupiter.api.Assertions.assertThrows;
25+
import static uk.co.probablyfine.matchers.Java8Matchers.where;
26+
import static uk.co.probablyfine.matchers.Java8Matchers.whereNot;
27+
28+
class CountDownTest {
29+
30+
@Test
31+
void reachesTargetStateAfterNthQuery() {
32+
CountDown countDown = new CountDown(2);
33+
assertThat(countDown, whereNot(TargetState::yet));
34+
assertThat(countDown, whereNot(TargetState::yet));
35+
assertThat(countDown, where(TargetState::yet));
36+
}
37+
38+
@Test
39+
void aZeroCountDownIsImmediatelyDone() {
40+
CountDown countDown = new CountDown(0);
41+
assertThat(countDown, where(TargetState::yet));
42+
}
43+
44+
@Test
45+
void doesNotAllowNegativeCount() {
46+
assertThrows(IllegalArgumentException.class, () -> new CountDown(-1));
47+
}
48+
49+
@Test
50+
void countDownGuaranteesAnExactAmountCrossThreads() {
51+
long count = 50_000;
52+
CountDown countDown = new CountDown(count);
53+
long invocationsBeforeZero = IntStream.generate(() -> countDown.yet() ? 0 : 1)
54+
.parallel()
55+
.limit(count * 5)
56+
.filter(i -> i == 1)
57+
.count();
58+
assertThat(invocationsBeforeZero, is(count));
59+
}
60+
61+
}

0 commit comments

Comments
 (0)