Add test case for FileLockFactory

This change introduce a test for cross-process/jvm file locking
using the FileLockFactory class. It uses a client program that
will lock a file aftwards the test case proceed.

Fixes #6610

Fixes #7117
This commit is contained in:
Wainer dos Santos Moschetta 2017-05-15 19:37:06 -03:00 committed by Armin Braun
parent 47517b8932
commit 95347b6025
4 changed files with 83 additions and 10 deletions

View file

@ -1,9 +0,0 @@
#!/usr/bin/env bin/ruby
require_relative "../lib/bootstrap/environment"
LogStash::Bundler.setup!({:without => [:build, :development]})
require "logstash-core"
lock = Java::OrgLogstash::FileLockFactory.getDefault.obtainLock(ARGV[0], ".lock")
puts("locking " + File.join(ARGV[0], ".lock"))
sleep

View file

@ -0,0 +1,23 @@
package org.logstash;
import java.io.IOException;
/*
* This program is used to test the FileLockFactory in cross-process/JVM.
*/
public class FileLockFactoryMain {
public static void main(String[] args) {
try {
FileLockFactory.getDefault().obtainLock(args[0], args[1]);
System.out.println("File locked");
// Sleep enough time until this process is killed.
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
// This process is killed. Do nothing.
} catch (IOException e) {
// Failed to obtain the lock.
System.exit(1);
}
}
}

View file

@ -1,16 +1,24 @@
package org.logstash;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileLock;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
@ -24,9 +32,12 @@ public class FileLockFactoryTest {
private FileLock lock;
private ExecutorService executor;
@Before
public void setUp() throws Exception {
lockDir = temporaryFolder.newFolder("lock").getPath();
executor = Executors.newSingleThreadExecutor();
}
@Before
@ -36,6 +47,14 @@ public class FileLockFactoryTest {
assertThat(lock.isShared(), is(equalTo(false)));
}
@After
public void tearDown() throws Exception {
executor.shutdownNow();
if (!executor.awaitTermination(2L, TimeUnit.MINUTES)) {
throw new IllegalStateException("Failed to shut down Executor");
}
}
@Test
public void ObtainLockOnNonLocked() throws IOException {
// empty to just test the lone @Before lockFirst() test
@ -88,4 +107,45 @@ public class FileLockFactoryTest {
FileLockFactory.getDefault().releaseLock(lock);
FileLockFactory.getDefault().releaseLock(lock);
}
@Test
public void crossJvmObtainLockOnLocked() throws Exception {
Process p = null;
String lockFile = ".testCrossJvm";
FileLock lock = null;
// Build the command to spawn a children JVM.
String[] cmd = {
Paths.get(System.getProperty("java.home"), "bin", "java").toString(),
"-cp", System.getProperty("java.class.path"),
Class.forName("org.logstash.FileLockFactoryMain").getName(),
lockDir, lockFile
};
try {
// Start the children program that will lock the file.
p = new ProcessBuilder(cmd).start();
InputStream is = p.getInputStream();
/* Wait the children program write to stdout, meaning the file
* is locked. Set a timeout to ensure it returns.
*/
Future<Integer> future = executor.submit(() -> {return is.read();});
assertTrue(future.get(30, TimeUnit.SECONDS) > -1);
// Check the children process is still running.
assertThat(p.isAlive(), is(equalTo(true)));
try {
// Try to obtain the lock held by the children process.
FileLockFactory.getDefault().obtainLock(lockDir, lockFile);
fail("Should have threw an exception");
} catch (LockException e) {
// Expected exception as the file is already locked.
}
} finally {
if (p != null) {
p.destroy();
}
}
}
}

View file

@ -52,7 +52,6 @@ namespace "artifact" do
@exclude_paths << "bin/bundle"
@exclude_paths << "bin/rspec"
@exclude_paths << "bin/rspec.bat"
@exclude_paths << "bin/lock"
@exclude_paths
end