View Javadoc

1   package net.sf.ehcache.terracotta;
2   
3   import org.hamcrest.CoreMatchers;
4   import org.junit.After;
5   import org.junit.Before;
6   import org.junit.Test;
7   
8   import java.io.File;
9   import java.io.IOException;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.Set;
13  import java.util.UUID;
14  import java.util.concurrent.atomic.AtomicReference;
15  
16  import static org.hamcrest.CoreMatchers.equalTo;
17  import static org.hamcrest.CoreMatchers.is;
18  import static org.junit.Assert.assertThat;
19  
20  /***
21   * @author Alex Snaps
22   */
23  public class RotatingSnapshotFileTest {
24  
25      private static final String DIRECTORY = "./dumps";
26      private RotatingSnapshotFile snapshotFile;
27      private File cleanMeUp;
28  
29      @Before
30      public void setup() {
31          snapshotFile = new RotatingSnapshotFile(DIRECTORY, "test");
32      }
33  
34      @Test
35      public void testSuccessfulWrite() throws IOException {
36  
37          Set<String> keys = populateWithValues(snapshotFile, 10000);
38          assertThat(snapshotFile.currentSnapshotFile().exists(), is(true));
39          assertThat(snapshotFile.tempSnapshotFile().exists(), is(false));
40          assertThat(snapshotFile.newSnapshotFile().exists(), is(false));
41          assertThat(snapshotFile.currentSnapshotFile().length() > 0, is(true));
42  
43          final Set<String> snapshot = snapshotFile.readAll();
44          assertThat(snapshot.size(), equalTo(keys.size()));
45          for (String key : snapshot) {
46              keys.remove(key);
47          }
48          assertThat(keys.isEmpty(), is(true));
49      }
50  
51      @Test
52      public void testStopsOnThreadInterrupted() throws IOException, InterruptedException {
53  
54          final RotatingSnapshotFile file = new RotatingSnapshotFile(DIRECTORY, "killMe");
55          final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>();
56          Set<String> keys = populateWithValues(file, 10000);
57          assertThat(file.currentSnapshotFile().exists(), is(true));
58          assertThat(file.tempSnapshotFile().exists(), is(false));
59          assertThat(file.newSnapshotFile().exists(), is(false));
60  
61          Thread writerThread = new Thread() {
62  
63              int valuesAskedWhileInterrupted = 0;
64  
65              @Override
66              public void run() {
67                  try {
68                      file.writeAll(new Iterable<Object>() {
69                          public Iterator<Object> iterator() {
70                              return new Iterator<Object>() {
71                                  public boolean hasNext() {
72                                      if (isInterrupted() && ++valuesAskedWhileInterrupted > 1) {
73                                          throwable.set(new AssertionError("We shouldn't be asked for more values by now!"));
74                                          return false;
75                                      }
76                                      return true;
77                                  }
78  
79                                  public Object next() {
80                                      return UUID.randomUUID();
81                                  }
82  
83                                  public void remove() {
84                                      // Just don't do anything...
85                                  }
86                              };
87                          }
88                      });
89                  } catch (Throwable e) {
90                      throwable.set(e);
91                  }
92              }
93          };
94  
95          writerThread.start();
96          Thread.sleep(500);
97          assertThat(file.currentSnapshotFile().exists(), is(true));
98          assertThat(file.newSnapshotFile().exists(), is(true));
99          assertThat(file.tempSnapshotFile().exists(), is(false));
100         file.setShutdownOnThreadInterrupted(true);
101         writerThread.interrupt();
102         writerThread.join();
103         assertThat(throwable.get(), CoreMatchers.<Object>nullValue());
104         assertThat(file.currentSnapshotFile().exists(), is(true));
105         assertThat(file.newSnapshotFile().exists(), is(true));
106         assertThat(file.tempSnapshotFile().exists(), is(false));
107         final Set<Object> values = file.readAll();
108         assertThat(values.size(), equalTo(keys.size()));
109         for (Object key : values) {
110             keys.remove(key);
111         }
112         assertThat(keys.isEmpty(), is(true));
113         assertThat(file.currentSnapshotFile().exists(), is(true));
114         assertThat(file.newSnapshotFile().exists(), is(false));
115         assertThat(file.tempSnapshotFile().exists(), is(false));
116 
117         cleanMeUp = file.currentSnapshotFile();
118     }
119 
120     @Test
121     public void testFinishesOnThreadInterrupted() throws IOException, InterruptedException {
122 
123         final RotatingSnapshotFile file = new RotatingSnapshotFile(DIRECTORY, "killMe");
124         final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>();
125         Set<String> keys = populateWithValues(file, 10000);
126         assertThat(file.currentSnapshotFile().exists(), is(true));
127         assertThat(file.tempSnapshotFile().exists(), is(false));
128         assertThat(file.newSnapshotFile().exists(), is(false));
129 
130         final int keyAmount = 100;
131         final String keyPrefix = "Finish with value ";
132         Thread writerThread = new Thread() {
133 
134             int valuesToDispenseOnceInterrupted = keyAmount;
135 
136             @Override
137             public void run() {
138                 try {
139                     file.writeAll(new Iterable<Object>() {
140                         public Iterator<Object> iterator() {
141                             return new Iterator<Object>() {
142                                 public boolean hasNext() {
143                                     return !isInterrupted() || valuesToDispenseOnceInterrupted-- > 0;
144                                 }
145 
146                                 public Object next() {
147                                     if (isInterrupted()) {
148                                         return keyPrefix + valuesToDispenseOnceInterrupted;
149                                     }
150                                     try {
151                                         Thread.sleep(200);
152                                     } catch (InterruptedException e) {
153                                         interrupt();
154                                     }
155                                     return UUID.randomUUID();
156                                 }
157 
158                                 public void remove() {
159                                     // Just don't do anything...
160                                 }
161                             };
162                         }
163                     });
164                 } catch (Throwable e) {
165                     throwable.set(e);
166                 }
167             }
168         };
169 
170         writerThread.start();
171         Thread.sleep(500);
172         assertThat(file.currentSnapshotFile().exists(), is(true));
173         assertThat(file.newSnapshotFile().exists(), is(true));
174         assertThat(file.tempSnapshotFile().exists(), is(false));
175         writerThread.interrupt();
176         writerThread.join();
177         assertThat(throwable.get(), CoreMatchers.<Object>nullValue());
178         assertThat(file.currentSnapshotFile().exists(), is(true));
179         assertThat(file.newSnapshotFile().exists(), is(false));
180         assertThat(file.tempSnapshotFile().exists(), is(false));
181         final Set<Object> values = file.readAll();
182         for (Object key : keys) {
183             assertThat(values.contains(key), is(false));
184         }
185         for (int i = 0; i < keyAmount; i++) {
186             final String key = keyPrefix + i;
187             assertThat(key + " is missing!", values.contains(key), is(true));
188         }
189         assertThat(values.contains(keyPrefix + keyAmount), is(false));
190         assertThat(values.size() > keyAmount, is(true));
191         assertThat(file.currentSnapshotFile().exists(), is(true));
192         assertThat(file.newSnapshotFile().exists(), is(false));
193         assertThat(file.tempSnapshotFile().exists(), is(false));
194 
195         cleanMeUp = file.currentSnapshotFile();
196     }
197 
198     private Set<String> populateWithValues(RotatingSnapshotFile snapshotFile, int amount) throws IOException {
199         Set<String> keys = new HashSet<String>();
200         for (int i = 0; i < amount; i++) {
201             keys.add("SomeKey that contains something " + i);
202         }
203 
204         snapshotFile.writeAll(keys);
205         return keys;
206     }
207 
208     @After
209     public void cleanUp() {
210         if (cleanMeUp != null) {
211             deleteSilently(cleanMeUp);
212         }
213 
214         if (snapshotFile != null) {
215             deleteSilently(snapshotFile.currentSnapshotFile());
216             deleteSilently(snapshotFile.newSnapshotFile());
217             deleteSilently(snapshotFile.tempSnapshotFile());
218             deleteSilently(new File(DIRECTORY));
219         }
220     }
221 
222     private void deleteSilently(final File file) {
223         try {
224             if (file.exists()) {
225                 file.delete();
226             }
227         } catch (Throwable e) {
228             System.err.println("Error deleting file " + file.getAbsolutePath() + ": " + e.getMessage());
229         }
230     }
231 
232 }