View Javadoc

1   package net.sf.ehcache.util;
2   
3   import org.junit.Test;
4   
5   import java.util.ArrayList;
6   import java.util.Collections;
7   import java.util.Date;
8   import java.util.List;
9   import java.util.concurrent.TimeUnit;
10  import java.util.concurrent.atomic.AtomicBoolean;
11  import java.util.concurrent.atomic.AtomicInteger;
12  import java.util.concurrent.atomic.AtomicLong;
13  
14  import static org.hamcrest.CoreMatchers.is;
15  import static org.junit.Assert.assertThat;
16  
17  /***
18   * @author Alex Snaps
19   */
20  public class SlewClockTest {
21  
22      private static final boolean SLOWRUN      = Boolean.getBoolean("TimestamperTest.slowRun");
23      private static final long    BACK_IN_TIME = TimeUnit.SECONDS.toMillis(30);
24      private static final int     THREADS      = 10;
25      private static final long    DURATION     = 15;
26  
27  
28      @Test
29      public void testTimeMillis() throws Throwable {
30          final AtomicLong slewStart = new AtomicLong();
31          final AtomicLong offset = new AtomicLong(0);
32          final List<Throwable> errors = Collections.synchronizedList(new ArrayList<Throwable>());
33          TimeProviderLoader.setTimeProvider(new SlewClock.TimeProvider() {
34              public long currentTimeMillis() {
35                  return System.currentTimeMillis() - offset.get();
36              }
37          });
38          final AtomicBoolean stopped = new AtomicBoolean(false);
39          final AtomicInteger catchingUp = new AtomicInteger();
40          SlewClockVerifierThread[] threads = new SlewClockVerifierThread[THREADS];
41          for(int i =0; i < THREADS; i++) {
42              threads[i] = new SlewClockVerifierThread(stopped, catchingUp, errors, slewStart, i == 0);
43          }
44          for (Thread thread : threads) {
45              thread.start();
46          }
47          Thread.sleep(TimeUnit.SECONDS.toMillis(DURATION));
48          System.out.println("Going back in time by " + BACK_IN_TIME);
49          slewStart.set(System.currentTimeMillis());
50          offset.set(BACK_IN_TIME);
51          Thread.sleep(SLOWRUN ? BACK_IN_TIME * 3 : BACK_IN_TIME * 2);
52          stopped.set(true);
53          for (SlewClockVerifierThread thread : threads) {
54              thread.join();
55          }
56          if(!errors.isEmpty()) {
57              System.err.println("We have " + errors.size() + " error(s) here!");
58              throw errors.get(0);
59          }
60          assertThat(catchingUp.get(), is(THREADS));
61      }
62  
63  
64      private static class SlewClockVerifierThread extends Thread {
65          private final AtomicBoolean stopped;
66          private final AtomicInteger catchingUp;
67          private final AtomicLong slewTime;
68          private final boolean log;
69          private List<Throwable> errors;
70          private boolean wasSlewing;
71          private int previousSecond;
72          private long previous;
73  
74          public SlewClockVerifierThread(final AtomicBoolean stopped, final AtomicInteger catchingUp, final List<Throwable> errors,
75                                         final AtomicLong slewTime, final boolean log) {
76              this.stopped = stopped;
77              this.catchingUp = catchingUp;
78              this.errors = errors;
79              this.slewTime = slewTime;
80              this.log = log;
81          }
82  
83          @Override
84          public void run() {
85              long run =0;
86              while (!stopped.get()) {
87                  long timeMillis = SlewClock.timeMillis();
88                  if(SlewClock.isThreadCatchingUp()) {
89                      if (!wasSlewing) {
90                          catchingUp.incrementAndGet();
91                      }
92                      wasSlewing = true;
93                      if(log) {
94                          int x = (int) TimeUnit.MILLISECONDS.toSeconds(timeMillis) % 10;
95                          if (SLOWRUN || x != previousSecond) {
96                              previousSecond = x;
97                              System.out.println(new Date(timeMillis) + " (" + timeMillis + "): " +
98                                                 new Date(TimeProviderLoader.getTimeProvider().currentTimeMillis()) + " " +
99                                                 SlewClock.behind());
100                         }
101                     }
102                     if (SLOWRUN) {
103                         try {
104                             Thread.sleep(15);
105                         } catch (InterruptedException e) {
106                             interrupt();
107                         }
108                     }
109                 } else if(wasSlewing) {
110                     System.out.println("Caught up in " + (System.currentTimeMillis() - slewTime.get()) + "ms");
111                     wasSlewing = false;
112                 }
113                 assertThat(timeMillis >= previous, is(true));
114                 previous = timeMillis;
115             }
116             try {
117                 assertThat(SlewClock.isThreadCatchingUp(), is(false));
118             } catch (AssertionError e) {
119                 errors.add(e);
120             }
121         }
122     }
123 }