package com.aragost.javahg.internals;
import java.io.File;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.aragost.javahg.BaseRepository;
import com.aragost.javahg.Repository;
import com.aragost.javahg.RepositoryConfiguration;
import com.aragost.javahg.commands.CancelledExecutionException;
import com.aragost.javahg.commands.ExecutionException;
import com.aragost.javahg.commands.VersionCommand;
import com.aragost.javahg.test.AbstractTestCase;
import com.google.common.base.Strings;
import com.google.common.io.Files;
public class JavaHgTestMercurialExtensionTest extends AbstractTestCase {
@Test
public void testAbort() throws IOException {
BaseRepository repo = getTestRepository();
GenericCommand cmd = new GenericCommand(repo, "javahg-abort");
try {
cmd.execute();
assertFailedExecution(cmd);
} catch (ExecutionException e) {
Assert.assertEquals(-1, cmd.getReturnCode());
Assert.assertEquals("abort: crash\n", cmd.getErrorString());
}
}
@Test
public void testError() throws IOException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-write");
cmd.execute("e", "foo bar");
Assert.assertEquals(0, cmd.getReturnCode());
Assert.assertEquals("foo bar", cmd.getErrorString());
}
@Test
public void testStdout() throws IOException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-stdout");
try {
cmd.execute("XXX YYY ZZZ"); // capital letter is
// important, triggers illegal
// channel exception
assertFailedExecution(cmd);
} catch (IllegalStateException e) {
Assert.assertEquals("Unknown channel: X", e.getMessage());
}
// The server is aborted
Assert.assertEquals(0, getTestRepository().getServerPool().getServers().size());
VersionCommand.on(getTestRepository()).execute();
Assert.assertEquals(1, getTestRepository().getServerPool().getServers().size());
}
@Test
public void testStderr() throws IOException, InterruptedException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-stderr");
Process process = getFirstServer(cmd.getRepository()).getProcess();
try {
cmd.execute("foo");
assertFailedExecution(cmd);
} catch (RuntimeException e) {
Assert.assertEquals(0, cmd.getReturnCode());
Assert.assertEquals("", cmd.getErrorString());
String msg = e.getMessage();
Assert.assertEquals("foo\n", msg);
Assert.assertEquals(RuntimeException.class, e.getClass());
int exitValue = process.exitValue();
Assert.assertEquals(0, exitValue);
}
}
@Test
public void testLongMessageOnStderr() {
// See comment in Server#checkStderr()
// Without that available call in checkStderr typically not
// everything from stderr will be read and this testcase fails
// Assume.assumeTrue(System.getProperty("java.runtime.version").compareTo("1.7")
// < 0);
BaseRepository repo = getTestRepository();
RepositoryConfiguration configuration = repo.getConfiguration();
int bufSize = configuration.getStderrBufferSize();
String longMessage = Strings.repeat("x", bufSize + 100) + "A";
GenericCommand cmd = new GenericCommand(repo, "javahg-stderr");
try {
cmd.execute(longMessage);
assertFailedExecution(cmd);
} catch (RuntimeException e) {
String msg = e.getMessage();
Assert.assertEquals(bufSize, msg.length());
Assert.assertEquals(Strings.repeat("x", bufSize), msg);
}
}
@Test
public void testUnknownOptionalChannel() throws IOException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-write");
cmd.execute("x", "foo bar");
Assert.assertEquals(0, cmd.getReturnCode());
Assert.assertEquals("", cmd.getErrorString());
}
@Test
public void testUnknownMandatoryChannel() throws IOException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-write");
try {
cmd.execute("X", "foo bar");
assertFailedExecution(cmd);
} catch (IllegalStateException e) {
Assert.assertEquals("Unknown channel: X", e.getMessage());
}
}
@Test
public void testHang() throws IOException {
// This test case has historical not fail consistently so
// execute it 10 times
for (int i = 0; i < 10; i++) {
File dir = Files.createTempDir();
final Repository repo = Repository.create(REPO_CONF, dir);
GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
Thread executioner = new Thread() {
/**
* Sleep 1/2 seconds to allow cmd to exit normally if
* the 'javahg-hang' doesn't make it hang and then
* kill server process
*/
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw Utils.asRuntime(e);
}
getFirstServer(repo).getProcess().destroy();
}
};
executioner.start();
try {
cmd.execute();
assertFailedExecution(cmd);
} catch (UnexpectedServerTerminationException e) {
// When process is kill we get an IOException with
// Stream closed, it is a
// BlockInputStream.InvalidStreamException exception
Throwable cause = e.getCause();
if (cause instanceof IOException) {
String msg = ((IOException) cause).getMessage();
Assert.assertTrue(
"Unexpected message. Got \"" + msg + "\"",
msg.equals("Bad file descriptor")
|| msg.equals("Stream Closed")
|| msg.equals("Stream closed"));
} else {
Assert.assertEquals(BlockInputStream.InvalidStreamException.class, cause.getClass());
}
} catch (ExecutionException e) {
// System.err.println("Got 'killed!' on 'e' channel");
Assert.assertEquals("killed!", e.getMessage());
}
// TODO There seems to be some kind of race condition.
// Sometimes an UnexpectedServerTerminationException is
// thrown, and sometimes an ExecutionException
// Analysis so far: Mercurial server process writes
// 'killed!' when the process is destroyed, sometimes it
// writes it to
// the actual stderr stream (typically case, gives
// UnexpectedServerTerminationException), and
// sometimes to the 'e'
// channel (rare case, gives ExecutionException).
//
// TODO also try to access the server on stdout and stdin
repo.close();
deleteTempDir(dir);
}
}
@Test
public void testCancel() throws IOException {
File dir = Files.createTempDir();
final Repository repo = Repository.create(REPO_CONF, dir);
final GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
Thread executioner = new Thread() {
@Override
public void run() {
while (cmd.getState() != GenericCommand.State.RUNNING) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw Utils.asRuntime(e);
}
}
cmd.cancel();
}
};
executioner.start();
try {
cmd.execute();
assertFailedExecution(cmd);
} catch (CancelledExecutionException e) {
// Expected
} catch (Throwable e) {
Assert.fail("CancelledExecutionException expected. Got:" + e);
}
VersionCommand.on(repo).execute();
repo.close();
deleteTempDir(dir);
}
@Test
public void testPreCancel() throws IOException {
File dir = Files.createTempDir();
final Repository repo = Repository.create(REPO_CONF, dir);
final GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
cmd.cancel();
try {
cmd.execute();
assertFailedExecution(cmd);
} catch (CancelledExecutionException e) {
// Expected
} catch (Throwable e) {
Assert.fail("CancelledExecutionException expected. Got:" + e);
}
VersionCommand.on(repo).execute();
repo.close();
deleteTempDir(dir);
}
/**
* Test cancelling a command that is queued
*/
@Test
public void testCancelQueued() throws IOException {
File dir = Files.createTempDir();
final Repository repo = Repository.create(REPO_CONF, dir);
final GenericCommand cmd = new GenericCommand(repo, "javahg-hang");
final GenericCommand cmd2 = new GenericCommand(repo, "javahg-hang");
final Thread executor = new Thread() {
@Override
public void run() {
try {
Thread.sleep(500);
Assert.assertEquals(0, repo.getServerPool().getNumIdleServers());
cmd2.execute();
assertFailedExecution(cmd);
} catch (CancelledExecutionException e) {
// Expected
} catch (InterruptedException e) {
throw Utils.asRuntime(e);
}
}
};
Thread executioner = new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw Utils.asRuntime(e);
}
Assert.assertEquals(AbstractCommand.State.QUEUED, cmd2.getState());
cmd2.cancel();
try {
executor.join();
} catch (InterruptedException e) {
throw Utils.asRuntime(e);
}
cmd.cancel();
}
};
Assert.assertEquals(1, repo.getServerPool().getNumIdleServers());
executor.start();
executioner.start();
try {
cmd.execute();
assertFailedExecution(cmd);
} catch (CancelledExecutionException e) {
// Expected
} catch (Throwable e) {
Assert.fail("CancelledExecutionException expected. Got:" + e);
}
VersionCommand.on(repo).execute();
repo.close();
deleteTempDir(dir);
}
@Test
public void testThrow() throws IOException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-throw");
try {
cmd.execute();
assertFailedExecution(cmd);
} catch (UnexpectedServerTerminationException e) {
int expectedExitValue = Utils.isWindows() ? 255 : 1;
Assert.assertEquals(expectedExitValue, e.getExitValue());
}
}
@Test
public void testExit() throws IOException {
GenericCommand cmd = new GenericCommand(getTestRepository(), "javahg-exit");
try {
cmd.execute("foo");
assertFailedExecution(cmd);
} catch (RuntimeIOException e) {
Assert.assertEquals("Unexpected EOF", e.getMessage());
}
}
}