11package bwapi ;
22
3- import static org .assertj .core .api .Assertions .assertThat ;
4- import static org .junit .Assert .assertEquals ;
5- import static org .junit .Assert .assertNull ;
6- import static org .junit .Assert .assertThrows ;
7- import static org .mockito .Mockito .*;
3+ import org .junit .Test ;
84
9- import java .util .HashMap ;
10- import java .util .Map ;
115import java .util .stream .IntStream ;
126
13- import org .junit .Rule ;
14- import org .junit .Test ;
15- import org .junit .rules . Timeout ;
7+ import static org .junit .Assert . assertEquals ;
8+ import static org .junit .Assert . assertThrows ;
9+ import static org .junit .Assert . assertTrue ;
1610
1711public class SynchronizationTest {
1812
@@ -24,6 +18,26 @@ private void sleepUnchecked(int milliseconds) {
2418 }
2519 }
2620
21+ private String describeApproximateExpectation (double expected , double actual , double margin ) {
22+ return "Expected " + expected + " == " + actual + " +/- " + margin ;
23+ }
24+
25+ private boolean measureApproximateEquality (double expected , double actual , double margin ) {
26+ return expected + margin >= actual && expected - margin <= actual ;
27+ }
28+
29+ private void assertWithin (double expected , double actual , double margin ) {
30+ assertTrue (
31+ describeApproximateExpectation (expected , actual , margin ),
32+ measureApproximateEquality (expected , actual , margin ));
33+ }
34+
35+ private void assertWithin (String message , double expected , double actual , double margin ) {
36+ assertTrue (
37+ message + ": " + describeApproximateExpectation (expected , actual , margin ),
38+ measureApproximateEquality (expected , actual , margin ));
39+ }
40+
2741 @ Test
2842 public void sync_IfException_ThrowException () throws InterruptedException {
2943 SynchronizationEnvironment environment = new SynchronizationEnvironment ();
@@ -48,6 +62,7 @@ public void sync_IfDelay_ThenNoBuffer() throws InterruptedException {
4862 environment .configuration .async = false ;
4963 environment .configuration .asyncFrameDurationMs = 1 ;
5064 environment .configuration .asyncFrameBufferSize = 3 ;
65+
5166 IntStream .range (0 , 5 ).forEach (frame -> {
5267 environment .onFrame (frame , () -> {
5368 sleepUnchecked (5 );
@@ -61,17 +76,163 @@ public void sync_IfDelay_ThenNoBuffer() throws InterruptedException {
6176 }
6277
6378 @ Test
64- public void async_IfDelay_ThenBuffer () throws InterruptedException {
79+ public void async_IfBotDelay_ThenClientBuffers () throws InterruptedException {
6580 SynchronizationEnvironment environment = new SynchronizationEnvironment ();
6681 environment .configuration .async = true ;
67- environment .configuration .asyncFrameDurationMs = 1 ;
82+ environment .configuration .asyncFrameDurationMs = 10 ;
6883 environment .configuration .asyncFrameBufferSize = 4 ;
84+
6985 environment .onFrame (1 , () -> {
70- sleepUnchecked (5 );
86+ sleepUnchecked (40 );
7187 assertEquals ("Bot should be observing an old frame" , 1 , environment .bwClient .getGame ().getFrameCount ());
7288 assertEquals ("Client should be as far ahead as the frame buffer allows" , 4 , environment .liveGameData ().getFrameCount ());
7389 assertEquals ("Bot should be behind the live game" , 3 , environment .bwClient .framesBehind ());
7490 });
91+
92+ environment .onFrame (6 , () -> { // Maybe it should be possible to demand that these assertions pass a frame earlier?
93+ assertEquals ("Bot should be observing the live frame" , 6 , environment .bwClient .getGame ().getFrameCount ());
94+ assertEquals ("Client should not be ahead of the bot" , 6 , environment .liveGameData ().getFrameCount ());
95+ assertEquals ("Bot should not be behind the live game" , 0 , environment .bwClient .framesBehind ());
96+ });
97+
98+ environment .runGame ();
99+ }
100+
101+ @ Test
102+ public void async_IfBotDelay_ThenClientStalls () throws InterruptedException {
103+ SynchronizationEnvironment environment = new SynchronizationEnvironment ();
104+ environment .configuration .async = true ;
105+ environment .configuration .asyncFrameDurationMs = 50 ;
106+ environment .configuration .asyncFrameBufferSize = 5 ;
107+
108+ environment .onFrame (1 , () -> {
109+ sleepUnchecked (125 );
110+ assertEquals ("3: Bot should be observing an old frame" , 1 , environment .bwClient .getGame ().getFrameCount ());
111+ assertEquals ("3: Client should have progressed as slowly as possible" , 3 , environment .liveGameData ().getFrameCount ());
112+ assertEquals ("3: Bot should be behind the live game by as little as possible" , 2 , environment .bwClient .framesBehind ());
113+ sleepUnchecked (50 );
114+ assertEquals ("4: Bot should be observing an old frame" , 1 , environment .bwClient .getGame ().getFrameCount ());
115+ assertEquals ("4: Client should have progressed as slowly as possible" , 4 , environment .liveGameData ().getFrameCount ());
116+ assertEquals ("4: Bot should be behind the live game by as little as possible" , 3 , environment .bwClient .framesBehind ());
117+ sleepUnchecked (50 );
118+ assertEquals ("5: Bot should be observing an old frame" , 1 , environment .bwClient .getGame ().getFrameCount ());
119+ assertEquals ("5: Client should have progressed as slowly as possible" , 5 , environment .liveGameData ().getFrameCount ());
120+ assertEquals ("5: Bot should be behind the live game by as little as possible" , 4 , environment .bwClient .framesBehind ());
121+ });
122+
75123 environment .runGame ();
76124 }
125+
126+ @ Test
127+ public void async_IfFrameZeroWaitsEnabled_ThenAllowInfiniteTime () throws InterruptedException {
128+ SynchronizationEnvironment environment = new SynchronizationEnvironment ();
129+ environment .configuration .async = true ;
130+ environment .configuration .unlimitedFrameZero = true ;
131+ environment .configuration .asyncFrameDurationMs = 5 ;
132+ environment .configuration .asyncFrameBufferSize = 2 ;
133+
134+ environment .onFrame (0 , () -> {
135+ sleepUnchecked (50 );
136+ assertEquals ("Bot should still be on frame zero" , 0 , environment .bwClient .getGame ().getFrameCount ());
137+ assertEquals ("Client should still be on frame zero" , 0 , environment .liveGameData ().getFrameCount ());
138+ assertEquals ("Bot should not be behind the live game" , 0 , environment .bwClient .framesBehind ());
139+ });
140+
141+ environment .runGame ();
142+ }
143+
144+ @ Test
145+ public void async_IfFrameZeroWaitsDisabled_ThenClientBuffers () throws InterruptedException {
146+ SynchronizationEnvironment environment = new SynchronizationEnvironment ();
147+ environment .configuration .async = true ;
148+ environment .configuration .unlimitedFrameZero = false ;
149+ environment .configuration .asyncFrameDurationMs = 5 ;
150+ environment .configuration .asyncFrameBufferSize = 2 ;
151+
152+ environment .onFrame (0 , () -> {
153+ sleepUnchecked (50 );
154+ assertEquals ("Bot should still be on frame zero" , 0 , environment .bwClient .getGame ().getFrameCount ());
155+ assertEquals ("Client should have advanced to the next frame" , 2 , environment .liveGameData ().getFrameCount ());
156+ assertEquals ("Bot should be behind the live game" , 2 , environment .bwClient .framesBehind ());
157+ });
158+
159+ environment .runGame ();
160+ }
161+
162+ @ Test
163+ public void async_MeasurePerformance_TotalFrameDuration () {
164+
165+ }
166+
167+ @ Test
168+ public void async_MeasurePerformance_CopyingToBuffer () {
169+
170+ }
171+
172+ @ Test
173+ public void async_MeasurePerformance_IntentionallyBlocking () {
174+
175+ }
176+
177+ @ Test
178+ public void async_MeasurePerformance_FrameBufferSize () {
179+
180+ }
181+
182+ @ Test
183+ public void async_MeasurePerformance_FlushSideEffects () {
184+
185+ }
186+
187+ /**
188+ * Number of milliseconds of leeway to give in performance metrics.
189+ * Increase if tests are flaky due to variance in execution speed.
190+ */
191+ private final static long MS_MARGIN = 10 ;
192+
193+ @ Test
194+ public void async_MeasurePerformance_BotResponse () {
195+ SynchronizationEnvironment environment = new SynchronizationEnvironment ();
196+
197+ // Frame zero appears to take an extra 60ms, so let's disable timing for it
198+ // (and also verify that we omit frame zero from performance metrics)
199+ environment .configuration .unlimitedFrameZero = true ;
200+
201+ environment .onFrame (1 , () -> {
202+ sleepUnchecked (100 );
203+ });
204+ environment .onFrame (2 , () -> {
205+ assertWithin ("2: Bot response average" , 100 , environment .metrics ().botResponse .avgValue , MS_MARGIN );
206+ assertWithin ("2: Bot response minimum" , 100 , environment .metrics ().botResponse .minValue , MS_MARGIN );
207+ assertWithin ("2: Bot response maximum" , 100 , environment .metrics ().botResponse .maxValue , MS_MARGIN );
208+ assertWithin ("2: Bot response previous" , 100 , environment .metrics ().botResponse .lastValue , MS_MARGIN );
209+ sleepUnchecked (300 );
210+ });
211+ environment .onFrame (3 , () -> {
212+ assertWithin ("3: Bot response average" , 200 , environment .metrics ().botResponse .avgValue , MS_MARGIN );
213+ assertWithin ("3: Bot response minimum" , 100 , environment .metrics ().botResponse .minValue , MS_MARGIN );
214+ assertWithin ("3: Bot response maximum" , 300 , environment .metrics ().botResponse .maxValue , MS_MARGIN );
215+ assertWithin ("3: Bot response previous" , 300 , environment .metrics ().botResponse .lastValue , MS_MARGIN );
216+ sleepUnchecked (200 );
217+ });
218+
219+ environment .runGame (4 );
220+
221+ assertWithin ("Final: Bot response average" , 200 , environment .metrics ().botResponse .avgValue , MS_MARGIN );
222+ assertWithin ("Final: Bot response minimum" , 100 , environment .metrics ().botResponse .minValue , MS_MARGIN );
223+ assertWithin ("Final: Bot response maximum" , 300 , environment .metrics ().botResponse .maxValue , MS_MARGIN );
224+ assertWithin ("Final: Bot response previous" , 200 , environment .metrics ().botResponse .lastValue , MS_MARGIN );
225+ }
226+
227+ @ Test
228+ public void async_MeasurePerformance_BwapiResponse () {
229+
230+ }
231+
232+ @ Test
233+ public void async_MeasurePerformance_BotIdle () {
234+
235+ }
236+
237+
77238}
0 commit comments