/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see <http://www.gnu.org/licenses/>.
*/
package org.graylog2.shared.plugins;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Collections;
import java.util.Enumeration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ChainingClassLoaderTest {
@Test(expected = ClassNotFoundException.class)
public void loadThrowsClassNotFoundExceptionIfClassDoesNotExist() throws Exception {
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(getClass().getClassLoader());
chainingClassLoader.loadClass("ThisClassHopeFullyDoesNotExist" + Instant.now().toEpochMilli());
}
@Test
public void loadReturnsClassFromParentClassLoader() throws Exception {
final ClassLoader parent = getClass().getClassLoader();
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
final String className = "org.graylog2.shared.plugins.ChainingClassLoaderTest$Dummy";
final Class<?> aClass = chainingClassLoader.loadClass(className);
assertThat(aClass).isNotNull();
assertThat(aClass.getSimpleName()).isEqualTo("Dummy");
assertThat(aClass.getClassLoader()).isSameAs(parent);
}
@Test
@SuppressWarnings("unchecked")
public void loadReturnsClassFromChildClassLoader() throws Exception {
final String className = "com.example.this.class.does.not.exist.Cls";
final ClassLoader parent = getClass().getClassLoader();
final ClassLoader child = mock(ClassLoader.class);
final Class<Dummy> dummyClass = Dummy.class;
when(child.loadClass(className)).thenReturn((Class) dummyClass);
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
chainingClassLoader.addClassLoader(child);
assertThat(chainingClassLoader.getClassLoaders())
.hasSize(2)
.containsExactly(parent, child);
final Class<?> aClass = chainingClassLoader.loadClass(className);
assertThat(aClass).isNotNull();
assertThat(aClass).isSameAs(dummyClass);
}
@Test
public void getResourceAsStreamReturnsNullIfResourceDoesNotExist() throws Exception {
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(getClass().getClassLoader());
final InputStream stream = chainingClassLoader.getResourceAsStream("ThisClassHopeFullyDoesNotExist" + Instant.now().toEpochMilli());
assertThat(stream).isNull();
}
@Test
public void getResourceAsStreamReturnsStreamFromChildClassLoader() throws Exception {
final ClassLoader parent = getClass().getClassLoader();
final ClassLoader child = mock(ClassLoader.class);
final ByteArrayInputStream inputStream = new ByteArrayInputStream("foobar".getBytes(StandardCharsets.UTF_8));
when(child.getResourceAsStream("name")).thenReturn(inputStream);
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
chainingClassLoader.addClassLoader(child);
final InputStream stream = chainingClassLoader.getResourceAsStream("name");
final ByteArrayInputStream expected = new ByteArrayInputStream("foobar".getBytes(StandardCharsets.UTF_8));
assertThat(stream).hasSameContentAs(expected);
}
@Test
public void getResourceReturnsNullIfResourceDoesNotExist() throws Exception {
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(getClass().getClassLoader());
final URL resource = chainingClassLoader.getResource("ThisClassHopeFullyDoesNotExist" + Instant.now().toEpochMilli());
assertThat(resource).isNull();
}
@Test
public void getResourceReturnsURLFromChildClassLoader() throws Exception {
final ClassLoader parent = getClass().getClassLoader();
final ClassLoader child = mock(ClassLoader.class);
final URL url = new URL("file://test");
when(child.getResource("name")).thenReturn(url);
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
chainingClassLoader.addClassLoader(child);
final URL resource = chainingClassLoader.getResource("name");
assertThat(resource).isEqualTo(url);
}
@Test
public void getResourcesReturnsEmptyEnumerationIfResourceDoesNotExist() throws Exception {
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(getClass().getClassLoader());
final Enumeration<URL> resources = chainingClassLoader.getResources("ThisClassHopeFullyDoesNotExist" + Instant.now().toEpochMilli());
assertThat(resources.hasMoreElements()).isFalse();
}
@Test
@SuppressWarnings("unchecked")
public void getResourcesReturnsEnumerationFromChildClassLoader() throws Exception {
final ClassLoader parent = getClass().getClassLoader();
final ClassLoader child = mock(ClassLoader.class);
final Enumeration<URL> urls = Collections.enumeration(Collections.singleton(new URL("file://test")));
when(child.getResources("name")).thenReturn(urls);
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
chainingClassLoader.addClassLoader(child);
final Enumeration<URL> resources = chainingClassLoader.getResources("name");
assertThat(Collections.list(resources)).containsExactly(new URL("file://test"));
}
@Test
public void getClassLoadersReturnsListOfClassLoaders() throws Exception {
final ClassLoader parent = getClass().getClassLoader();
final ClassLoader child = new URLClassLoader(new URL[0], parent);
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
chainingClassLoader.addClassLoader(child);
assertThat(chainingClassLoader.getClassLoaders())
.hasSize(2)
.containsExactly(parent, child);
}
@Test
public void addClassLoaderAddsClassLoaderToList() throws Exception {
final ClassLoader parent = getClass().getClassLoader();
final ClassLoader child = new URLClassLoader(new URL[0], parent);
final ChainingClassLoader chainingClassLoader = new ChainingClassLoader(parent);
assertThat(chainingClassLoader.getClassLoaders())
.hasSize(1)
.containsExactly(parent);
chainingClassLoader.addClassLoader(child);
assertThat(chainingClassLoader.getClassLoaders())
.hasSize(2)
.containsExactly(parent, child);
}
public static final class Dummy {
}
}