View Javadoc

1   package com.aragost.javahg.internals;
2   
3   import java.io.File;
4   import java.io.IOException;
5   
6   import org.junit.Assert;
7   import org.junit.Test;
8   
9   import com.aragost.javahg.BaseRepository;
10  import com.aragost.javahg.Repository;
11  import com.aragost.javahg.RepositoryConfiguration;
12  import com.aragost.javahg.commands.CancelledExecutionException;
13  import com.aragost.javahg.commands.ExecutionException;
14  import com.aragost.javahg.commands.VersionCommand;
15  import com.aragost.javahg.test.AbstractTestCase;
16  import com.google.common.base.Strings;
17  import com.google.common.io.Files;
18  
19  public class JavaHgTestMercurialExtensionTest extends AbstractTestCase {
20  
21      @Test
22      public void testAbort() throws IOException {
23          BaseRepository repo = getTestRepository();
24          GenericCommand cmd = new GenericCommand(repo, "javahg-abort");
25          try {
26              cmd.execute();
27              assertFailedExecution(cmd);
28          } catch (ExecutionException e) {
29              Assert.assertEquals(-1, cmd.getReturnCode());
30              Assert.assertEquals("abort: crash\n", cmd.getErrorString());
31          }
32      }
33  
34      @Test
35      public void testError() throws IOException {
36          GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-write");
37          cmd.execute("e", "foo bar");
38          Assert.assertEquals(0, cmd.getReturnCode());
39          Assert.assertEquals("foo bar", cmd.getErrorString());
40      }
41  
42      @Test
43      public void testStdout() throws IOException {
44          GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-stdout");
45          try {
46              cmd.execute("XXX YYY ZZZ"); // capital letter is
47                                          // important, triggers illegal
48                                          // channel exception
49              assertFailedExecution(cmd);
50          } catch (IllegalStateException e) {
51              Assert.assertEquals("Unknown channel: X", e.getMessage());
52          }
53  
54          // The server is aborted
55          Assert.assertEquals(0, getTestRepository().getServerPool().getServers().size());
56  
57          VersionCommand.on(getTestRepository()).execute();
58  
59          Assert.assertEquals(1, getTestRepository().getServerPool().getServers().size());
60      }
61  
62      @Test
63      public void testStderr() throws IOException, InterruptedException {
64          GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-stderr");
65          Process process = getFirstServer(cmd.getRepository()).getProcess();
66          try {
67              cmd.execute("foo");
68              assertFailedExecution(cmd);
69          } catch (RuntimeException e) {
70              Assert.assertEquals(0, cmd.getReturnCode());
71              Assert.assertEquals("", cmd.getErrorString());
72              String msg = e.getMessage();
73              Assert.assertEquals("foo\n", msg);
74              Assert.assertEquals(RuntimeException.class, e.getClass());
75              int exitValue = process.exitValue();
76              Assert.assertEquals(0, exitValue);
77          }
78      }
79  
80      @Test
81      public void testLongMessageOnStderr() {
82          // See comment in Server#checkStderr()
83          // Without that available call in checkStderr typically not
84          // everything from stderr will be read and this testcase fails
85          // Assume.assumeTrue(System.getProperty("java.runtime.version").compareTo("1.7")
86          // < 0);
87          BaseRepository repo = getTestRepository();
88          RepositoryConfiguration configuration = repo.getConfiguration();
89          int bufSize = configuration.getStderrBufferSize();
90          String longMessage = Strings.repeat("x", bufSize + 100) + "A";
91          GenericCommand cmd = new GenericCommand(repo, "javahg-stderr");
92          try {
93              cmd.execute(longMessage);
94              assertFailedExecution(cmd);
95          } catch (RuntimeException e) {
96              String msg = e.getMessage();
97              Assert.assertEquals(bufSize, msg.length());
98              Assert.assertEquals(Strings.repeat("x", bufSize), msg);
99          }
100     }
101 
102     @Test
103     public void testUnknownOptionalChannel() throws IOException {
104         GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-write");
105         cmd.execute("x", "foo bar");
106         Assert.assertEquals(0, cmd.getReturnCode());
107         Assert.assertEquals("", cmd.getErrorString());
108     }
109 
110     @Test
111     public void testUnknownMandatoryChannel() throws IOException {
112         GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-write");
113         try {
114             cmd.execute("X", "foo bar");
115             assertFailedExecution(cmd);
116         } catch (IllegalStateException e) {
117             Assert.assertEquals("Unknown channel: X", e.getMessage());
118         }
119     }
120 
121     @Test
122     public void testHang() throws IOException {
123         // This test case has historical not fail consistently so
124         // execute it 10 times
125         for (int i = 0; i < 10; i++) {
126             File dir = Files.createTempDir();
127 
128             final Repository repo = Repository.create(REPO_CONF, dir);
129             GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
130 
131             Thread executioner = new Thread() {
132                 /**
133                  * Sleep 1/2 seconds to allow cmd to exit normally if
134                  * the 'javahg-hang' doesn't make it hang and then
135                  * kill server process
136                  */
137                 @Override
138                 public void run() {
139                     try {
140                         Thread.sleep(500);
141                     } catch (InterruptedException e) {
142                         throw Utils.asRuntime(e);
143                     }
144                     getFirstServer(repo).getProcess().destroy();
145                 }
146             };
147 
148             executioner.start();
149             try {
150                 cmd.execute();
151                 assertFailedExecution(cmd);
152             } catch (UnexpectedServerTerminationException e) {
153                 // When process is kill we get an IOException with
154                 // Stream closed, it is a
155                 // BlockInputStream.InvalidStreamException exception
156                 Throwable cause = e.getCause();
157                 if (cause instanceof IOException) {
158                     String msg = ((IOException) cause).getMessage();
159                     Assert.assertTrue(
160                             "Unexpected message. Got \"" + msg + "\"",
161                             msg.equals("Bad file descriptor")
162                                     || msg.equals("Stream Closed")
163                                     || msg.equals("Stream closed"));
164                 } else {
165                     Assert.assertEquals(BlockInputStream.InvalidStreamException.class, cause.getClass());
166                 }
167             } catch (ExecutionException e) {
168                 // System.err.println("Got 'killed!' on 'e' channel");
169                 Assert.assertEquals("killed!", e.getMessage());
170             }
171             // TODO There seems to be some kind of race condition.
172             // Sometimes an UnexpectedServerTerminationException is
173             // thrown, and sometimes an ExecutionException
174             // Analysis so far: Mercurial server process writes
175             // 'killed!' when the process is destroyed, sometimes it
176             // writes it to
177             // the actual stderr stream (typically case, gives
178             // UnexpectedServerTerminationException), and
179             // sometimes to the 'e'
180             // channel (rare case, gives ExecutionException).
181             //
182             // TODO also try to access the server on stdout and stdin
183 
184             repo.close();
185             deleteTempDir(dir);
186         }
187     }
188     
189     @Test
190     public void testCancel() throws IOException {
191         File dir = Files.createTempDir();
192 
193         final Repository repo = Repository.create(REPO_CONF, dir);
194         final GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
195 
196         Thread executioner = new Thread() {
197             @Override
198             public void run() {
199                 while (cmd.getState() != GenericCommand.State.RUNNING) {
200                     try {
201                         Thread.sleep(100);
202                     } catch (InterruptedException e) {
203                         throw Utils.asRuntime(e);
204                     }
205                 }
206                 cmd.cancel();
207             }
208         };
209 
210         executioner.start();
211         try {
212             cmd.execute();
213             assertFailedExecution(cmd);
214         } catch (CancelledExecutionException e) {
215             // Expected
216         } catch (Throwable e) {
217             Assert.fail("CancelledExecutionException expected. Got:" + e);
218         }
219 
220         VersionCommand.on(repo).execute();
221         
222         repo.close();
223         deleteTempDir(dir);
224     }
225 
226     @Test
227     public void testPreCancel() throws IOException {
228         File dir = Files.createTempDir();
229 
230         final Repository repo = Repository.create(REPO_CONF, dir);
231         final GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
232 
233         cmd.cancel();
234 
235         try {
236             cmd.execute();
237             assertFailedExecution(cmd);
238         } catch (CancelledExecutionException e) {
239             // Expected
240         } catch (Throwable e) {
241             Assert.fail("CancelledExecutionException expected. Got:" + e);
242         }
243 
244         VersionCommand.on(repo).execute();
245 
246         repo.close();
247         deleteTempDir(dir);
248     }
249 
250     /**
251      * Test cancelling a command that is queued
252      */
253     @Test
254     public void testCancelQueued() throws IOException {
255         File dir = Files.createTempDir();
256 
257         final Repository repo = Repository.create(REPO_CONF, dir);
258         final GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
259         final GenericCommand cmd2 = new GenericCommand(repo, "javahg-hang");
260 
261         final Thread executor = new Thread() {
262             
263             @Override
264             public void run() {
265                 try {
266                     Thread.sleep(500);
267                     Assert.assertEquals(0, repo.getServerPool().getNumIdleServers());
268                     cmd2.execute();
269                     assertFailedExecution(cmd);
270                 } catch (CancelledExecutionException e) {
271                     // Expected
272                 } catch (InterruptedException e) {
273                     throw Utils.asRuntime(e);
274                 }
275             }
276         };
277         
278         Thread executioner = new Thread() {
279             
280             @Override
281             public void run() {
282                 try {
283                     Thread.sleep(1000);
284                 } catch (InterruptedException e) {
285                     throw Utils.asRuntime(e);
286                 }
287                 Assert.assertEquals(AbstractCommand.State.QUEUED, cmd2.getState());
288                 cmd2.cancel();
289                 try {
290                     executor.join();
291                 } catch (InterruptedException e) {
292                     throw Utils.asRuntime(e);
293                 }
294                 cmd.cancel();
295             }
296         };
297 
298         Assert.assertEquals(1, repo.getServerPool().getNumIdleServers());
299         executor.start();
300         executioner.start();
301         try {
302             cmd.execute();
303             assertFailedExecution(cmd);
304         } catch (CancelledExecutionException e) {
305             // Expected
306         } catch (Throwable e) {
307             Assert.fail("CancelledExecutionException expected. Got:" + e);
308         }
309 
310         VersionCommand.on(repo).execute();
311 
312         repo.close();
313         deleteTempDir(dir);
314     }
315 
316     @Test
317     public void testThrow() throws IOException {
318         GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-throw");
319         try {
320             cmd.execute();
321             assertFailedExecution(cmd);
322         } catch (UnexpectedServerTerminationException e) {
323             int expectedExitValue = Utils.isWindows() ? 255 : 1;
324             Assert.assertEquals(expectedExitValue, e.getExitValue());
325         }
326     }
327 
328     @Test
329     public void testExit() throws IOException {
330         GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-exit");
331         try {
332             cmd.execute("foo");
333             assertFailedExecution(cmd);
334         } catch (RuntimeIOException e) {
335             Assert.assertEquals("Unexpected EOF", e.getMessage());
336         }
337     }
338 
339 }