implemented simple ClassLoaderLifeCycle to fix integration tests on Java > 8

This commit is contained in:
Sebastian Sdorra
2020-02-04 15:59:11 +01:00
parent a36551597d
commit 71c5f68878
9 changed files with 424 additions and 253 deletions

View File

@@ -1,116 +1,25 @@
package sonia.scm.lifecycle.classloading;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorFactory;
import java.io.Closeable;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class ClassLoaderLifeCycleTest {
@Mock
private ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory;
@Mock
private ClassLoaderLeakPreventor classLoaderLeakPreventor;
@Test
void shouldThrowIllegalStateExceptionWithoutInit() {
ClassLoaderLifeCycle lifeCycle = ClassLoaderLifeCycle.create();
assertThrows(IllegalStateException.class, lifeCycle::getBootstrapClassLoader);
void shouldCreateSimpleClassLoader() {
System.setProperty(ClassLoaderLifeCycle.PROPERTY, SimpleClassLoaderLifeCycle.NAME);
try {
ClassLoaderLifeCycle classLoaderLifeCycle = ClassLoaderLifeCycle.create();
assertThat(classLoaderLifeCycle).isInstanceOf(SimpleClassLoaderLifeCycle.class);
} finally {
System.clearProperty(ClassLoaderLifeCycle.PROPERTY);
}
}
@Test
void shouldThrowIllegalStateExceptionAfterShutdown() {
ClassLoaderLifeCycle lifeCycle = createMockedLifeCycle();
lifeCycle.initialize();
lifeCycle.shutdown();
assertThrows(IllegalStateException.class, lifeCycle::getBootstrapClassLoader);
void shouldCreateDefaultClassLoader() {
ClassLoaderLifeCycle classLoaderLifeCycle = ClassLoaderLifeCycle.create();
assertThat(classLoaderLifeCycle).isInstanceOf(ClassLoaderLifeCycleWithLeakPrevention.class);
}
@Test
void shouldCreateBootstrapClassLoaderOnInit() {
ClassLoaderLifeCycle lifeCycle = ClassLoaderLifeCycle.create();
lifeCycle.initialize();
assertThat(lifeCycle.getBootstrapClassLoader()).isNotNull();
}
@Test
void shouldCallTheLeakPreventor() {
ClassLoaderLifeCycle lifeCycle = createMockedLifeCycle();
lifeCycle.initialize();
verify(classLoaderLeakPreventor, times(2)).runPreClassLoaderInitiators();
lifeCycle.createChildFirstPluginClassLoader(new URL[0], null, "a");
lifeCycle.createPluginClassLoader(new URL[0], null, "b");
verify(classLoaderLeakPreventor, times(4)).runPreClassLoaderInitiators();
lifeCycle.shutdown();
verify(classLoaderLeakPreventor, times(4)).runCleanUps();
}
@Test
void shouldCloseCloseableClassLoaders() throws IOException {
// we use URLClassLoader, because we must be sure that the classloader is closable
URLClassLoader webappClassLoader = spy(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()));
ClassLoaderLifeCycle lifeCycle = createMockedLifeCycle(webappClassLoader);
lifeCycle.setClassLoaderAppendListener(new ClassLoaderLifeCycle.ClassLoaderAppendListener() {
@Override
public <C extends ClassLoader> C apply(C classLoader) {
return spy(classLoader);
}
});
lifeCycle.initialize();
ClassLoader pluginA = lifeCycle.createChildFirstPluginClassLoader(new URL[0], null, "a");
ClassLoader pluginB = lifeCycle.createPluginClassLoader(new URL[0], null, "b");
lifeCycle.shutdown();
closed(pluginB);
closed(pluginA);
neverClosed(webappClassLoader);
}
private void neverClosed(Object object) throws IOException {
Closeable closeable = closeable(object);
verify(closeable, never()).close();
}
private void closed(Object object) throws IOException {
Closeable closeable = closeable(object);
verify(closeable).close();
}
private Closeable closeable(Object object) {
assertThat(object).isInstanceOf(Closeable.class);
return (Closeable) object;
}
private ClassLoaderLifeCycle createMockedLifeCycle() {
return createMockedLifeCycle(Thread.currentThread().getContextClassLoader());
}
private ClassLoaderLifeCycle createMockedLifeCycle(ClassLoader classLoader) {
when(classLoaderLeakPreventorFactory.newLeakPreventor(any(ClassLoader.class))).thenReturn(classLoaderLeakPreventor);
return new ClassLoaderLifeCycle(classLoader, classLoaderLeakPreventorFactory);
}
}

View File

@@ -0,0 +1,116 @@
package sonia.scm.lifecycle.classloading;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorFactory;
import java.io.Closeable;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class ClassLoaderLifeCycleWithLeakPreventionTest {
@Mock
private ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory;
@Mock
private ClassLoaderLeakPreventor classLoaderLeakPreventor;
@Test
void shouldThrowIllegalStateExceptionWithoutInit() {
ClassLoaderLifeCycleWithLeakPrevention lifeCycle = new ClassLoaderLifeCycleWithLeakPrevention(Thread.currentThread().getContextClassLoader());
assertThrows(IllegalStateException.class, lifeCycle::getBootstrapClassLoader);
}
@Test
void shouldThrowIllegalStateExceptionAfterShutdown() {
ClassLoaderLifeCycleWithLeakPrevention lifeCycle = createMockedLifeCycle();
lifeCycle.initialize();
lifeCycle.shutdown();
assertThrows(IllegalStateException.class, lifeCycle::getBootstrapClassLoader);
}
@Test
void shouldCreateBootstrapClassLoaderOnInit() {
ClassLoaderLifeCycleWithLeakPrevention lifeCycle = new ClassLoaderLifeCycleWithLeakPrevention(Thread.currentThread().getContextClassLoader());
lifeCycle.initialize();
assertThat(lifeCycle.getBootstrapClassLoader()).isNotNull();
}
@Test
void shouldCallTheLeakPreventor() {
ClassLoaderLifeCycleWithLeakPrevention lifeCycle = createMockedLifeCycle();
lifeCycle.initialize();
verify(classLoaderLeakPreventor, times(1)).runPreClassLoaderInitiators();
lifeCycle.createChildFirstPluginClassLoader(new URL[0], null, "a");
lifeCycle.createPluginClassLoader(new URL[0], null, "b");
verify(classLoaderLeakPreventor, times(3)).runPreClassLoaderInitiators();
lifeCycle.shutdown();
verify(classLoaderLeakPreventor, times(3)).runCleanUps();
}
@Test
void shouldCloseCloseableClassLoaders() throws IOException {
// we use URLClassLoader, because we must be sure that the classloader is closable
URLClassLoader webappClassLoader = spy(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()));
ClassLoaderLifeCycleWithLeakPrevention lifeCycle = createMockedLifeCycle(webappClassLoader);
lifeCycle.setClassLoaderAppendListener(new ClassLoaderLifeCycleWithLeakPrevention.ClassLoaderAppendListener() {
@Override
public <C extends ClassLoader> C apply(C classLoader) {
return spy(classLoader);
}
});
lifeCycle.initialize();
ClassLoader pluginA = lifeCycle.createChildFirstPluginClassLoader(new URL[0], null, "a");
ClassLoader pluginB = lifeCycle.createPluginClassLoader(new URL[0], null, "b");
lifeCycle.shutdown();
closed(pluginB);
closed(pluginA);
neverClosed(webappClassLoader);
}
private void neverClosed(Object object) throws IOException {
Closeable closeable = closeable(object);
verify(closeable, never()).close();
}
private void closed(Object object) throws IOException {
Closeable closeable = closeable(object);
verify(closeable).close();
}
private Closeable closeable(Object object) {
assertThat(object).isInstanceOf(Closeable.class);
return (Closeable) object;
}
private ClassLoaderLifeCycleWithLeakPrevention createMockedLifeCycle() {
return createMockedLifeCycle(Thread.currentThread().getContextClassLoader());
}
private ClassLoaderLifeCycleWithLeakPrevention createMockedLifeCycle(ClassLoader classLoader) {
when(classLoaderLeakPreventorFactory.newLeakPreventor(any(ClassLoader.class))).thenReturn(classLoaderLeakPreventor);
return new ClassLoaderLifeCycleWithLeakPrevention(classLoader, classLoaderLeakPreventorFactory);
}
}

View File

@@ -0,0 +1,37 @@
package sonia.scm.lifecycle.classloading;
import org.junit.jupiter.api.Test;
import java.io.Closeable;
import static org.assertj.core.api.Assertions.assertThat;
class SimpleClassLoaderLifeCycleTest {
@Test
void shouldCloseClosableClassLoaderOnShutdown() {
SimpleClassLoaderLifeCycle lifeCycle = new SimpleClassLoaderLifeCycle(Thread.currentThread().getContextClassLoader());
lifeCycle.initialize();
ClosableClassLoader classLoader = new ClosableClassLoader();
lifeCycle.initAndAppend(classLoader);
lifeCycle.shutdown();
assertThat(classLoader.closed).isTrue();
}
private static class ClosableClassLoader extends ClassLoader implements Closeable {
private boolean closed = false;
public ClosableClassLoader() {
super();
}
@Override
public void close() {
closed = true;
}
}
}