From 3e287729c549b68656952c1cad53392df51e9ef9 Mon Sep 17 00:00:00 2001 From: Decebal Suiu Date: Mon, 24 Jun 2024 19:20:26 +0300 Subject: [PATCH] Add more tests --- pf4j/pom.xml | 6 + .../pf4j/ServiceProviderExtensionFinder.java | 14 ++- .../main/java/org/pf4j/asm/ExtensionInfo.java | 2 +- .../pf4j/LoggingPluginStateListenerTest.java | 54 +++++++++ .../ServiceProviderExtensionFinderTest.java | 110 ++++++++++++++++++ .../java/org/pf4j/asm/ExtensionInfoTest.java | 64 ++++++++++ .../org/pf4j/asm/ExtensionVisitorTest.java | 89 ++++++++++++++ 7 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 pf4j/src/test/java/org/pf4j/LoggingPluginStateListenerTest.java create mode 100644 pf4j/src/test/java/org/pf4j/ServiceProviderExtensionFinderTest.java create mode 100644 pf4j/src/test/java/org/pf4j/asm/ExtensionInfoTest.java create mode 100644 pf4j/src/test/java/org/pf4j/asm/ExtensionVisitorTest.java diff --git a/pf4j/pom.xml b/pf4j/pom.xml index c5d1917..3fe78ff 100644 --- a/pf4j/pom.xml +++ b/pf4j/pom.xml @@ -181,6 +181,12 @@ ${mockito.version} test + + org.mockito + mockito-inline + ${mockito.version} + test + com.google.testing.compile compile-testing diff --git a/pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java b/pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java index b477192..b28c576 100644 --- a/pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java +++ b/pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java @@ -64,7 +64,7 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { final Set bucket = new HashSet<>(); try { - Enumeration urls = getClass().getClassLoader().getResources(EXTENSIONS_RESOURCE); + Enumeration urls = getExtensionResource(getClass().getClassLoader()); if (urls.hasMoreElements()) { collectExtensions(urls, bucket); } else { @@ -88,12 +88,12 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { List plugins = pluginManager.getPlugins(); for (PluginWrapper plugin : plugins) { - String pluginId = plugin.getDescriptor().getPluginId(); + String pluginId = plugin.getPluginId(); log.debug("Reading extensions storages for plugin '{}'", pluginId); final Set bucket = new HashSet<>(); try { - Enumeration urls = ((PluginClassLoader) plugin.getPluginClassLoader()).findResources(EXTENSIONS_RESOURCE); + Enumeration urls = findExtensionResource((PluginClassLoader) plugin.getPluginClassLoader()); if (urls.hasMoreElements()) { collectExtensions(urls, bucket); } else { @@ -111,6 +111,14 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { return result; } + Enumeration getExtensionResource(ClassLoader classLoader) throws IOException { + return classLoader.getResources(EXTENSIONS_RESOURCE); + } + + Enumeration findExtensionResource(PluginClassLoader classLoader) throws IOException { + return classLoader.findResources(EXTENSIONS_RESOURCE); + } + private void collectExtensions(Enumeration urls, Set bucket) throws URISyntaxException, IOException { while (urls.hasMoreElements()) { URL url = urls.nextElement(); diff --git a/pf4j/src/main/java/org/pf4j/asm/ExtensionInfo.java b/pf4j/src/main/java/org/pf4j/asm/ExtensionInfo.java index d0acee1..02cdce8 100644 --- a/pf4j/src/main/java/org/pf4j/asm/ExtensionInfo.java +++ b/pf4j/src/main/java/org/pf4j/asm/ExtensionInfo.java @@ -43,7 +43,7 @@ public final class ExtensionInfo { List plugins = new ArrayList<>(); List points = new ArrayList<>(); - private ExtensionInfo(String className) { + ExtensionInfo(String className) { this.className = className; } diff --git a/pf4j/src/test/java/org/pf4j/LoggingPluginStateListenerTest.java b/pf4j/src/test/java/org/pf4j/LoggingPluginStateListenerTest.java new file mode 100644 index 0000000..c335cc9 --- /dev/null +++ b/pf4j/src/test/java/org/pf4j/LoggingPluginStateListenerTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pf4j; + +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class LoggingPluginStateListenerTest { + + @Test + void pluginStateChangedShouldLogStateChange() { + Logger mockedLogger = mock(Logger.class); + + try (MockedStatic context = Mockito.mockStatic(LoggerFactory.class)) { + context.when(() -> LoggerFactory.getLogger(Mockito.any(Class.class))) + .thenReturn(mockedLogger); + + // create a PluginStateEvent + PluginManager pluginManager = mock(PluginManager.class); + PluginWrapper pluginWrapper = mock(PluginWrapper.class); + when(pluginWrapper.getPluginId()).thenReturn("testPlugin"); + when(pluginWrapper.getPluginState()).thenReturn(PluginState.STARTED); + PluginStateEvent event = new PluginStateEvent(pluginManager, pluginWrapper, PluginState.CREATED); + + // call the method under test + LoggingPluginStateListener listener = new LoggingPluginStateListener(); + listener.pluginStateChanged(event); + + // verify that the logger was called with the expected message + verify(mockedLogger).debug("The state of plugin '{}' has changed from '{}' to '{}'", "testPlugin", PluginState.CREATED, PluginState.STARTED); + } + } + +} diff --git a/pf4j/src/test/java/org/pf4j/ServiceProviderExtensionFinderTest.java b/pf4j/src/test/java/org/pf4j/ServiceProviderExtensionFinderTest.java new file mode 100644 index 0000000..1d00188 --- /dev/null +++ b/pf4j/src/test/java/org/pf4j/ServiceProviderExtensionFinderTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pf4j; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ServiceProviderExtensionFinderTest { + + private static final String GREETER_EXTENSION_POINT = "org.pf4j.demo.api.Greeting"; + private static final String HELLO_GREETER_EXTENSION = "org.pf4j.demo.hello.HelloGreeting"; + private static final String WELCOME_GREETER_EXTENSION = "org.pf4j.demo.welcome.WelcomeGreeting"; + + @TempDir + public Path tempDir; + + @Test + void readClasspathStorages() { + PluginManager pluginManager = mock(PluginManager.class); + ServiceProviderExtensionFinder finder = new ServiceProviderExtensionFinder(pluginManager) { + + @Override + Enumeration getExtensionResource(ClassLoader classLoader) throws IOException { + return getExtensionEnumeration(); + } + + }; + + Map> storages = finder.readClasspathStorages(); + assertNotNull(storages); + assertTrue(storages.containsKey(null)); + Set extensions = storages.get(null); + assertEquals(2, extensions.size()); + assertThat(extensions, containsInAnyOrder(HELLO_GREETER_EXTENSION, WELCOME_GREETER_EXTENSION)); + } + + + @Test + void readPluginsStorages() { + String pluginId = "testPlugin"; + PluginWrapper pluginWrapper = mock(PluginWrapper.class); + when(pluginWrapper.getPluginId()).thenReturn(pluginId); + when(pluginWrapper.getPluginClassLoader()).thenReturn(null); // not needed for this test + + PluginManager pluginManager = mock(PluginManager.class); + when(pluginManager.getPlugins()).thenReturn(Collections.singletonList(pluginWrapper)); + ServiceProviderExtensionFinder finder = new ServiceProviderExtensionFinder(pluginManager) { + + @Override + Enumeration findExtensionResource(PluginClassLoader classLoader) throws IOException { + return getExtensionEnumeration(); + } + + }; + + Map> storages = finder.readPluginsStorages(); + assertNotNull(storages); + assertTrue(storages.containsKey(pluginId)); + Set extensions = storages.get(pluginId); + assertEquals(2, extensions.size()); + assertThat(extensions, containsInAnyOrder(HELLO_GREETER_EXTENSION, WELCOME_GREETER_EXTENSION)); + } + + private Enumeration getExtensionEnumeration() throws IOException { + Path servicesPath = tempDir.resolve("META-INF/services"); + servicesPath.toFile().mkdirs(); + + Path greetingPath = servicesPath.resolve(GREETER_EXTENSION_POINT); + List extensions = new ArrayList<>(); + extensions.add(HELLO_GREETER_EXTENSION); + extensions.add(WELCOME_GREETER_EXTENSION); + Files.write(greetingPath, extensions, StandardCharsets.UTF_8); + + return Collections.enumeration(Collections.singletonList(servicesPath.toUri().toURL())); + } + +} diff --git a/pf4j/src/test/java/org/pf4j/asm/ExtensionInfoTest.java b/pf4j/src/test/java/org/pf4j/asm/ExtensionInfoTest.java new file mode 100644 index 0000000..5dc0b5e --- /dev/null +++ b/pf4j/src/test/java/org/pf4j/asm/ExtensionInfoTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pf4j.asm; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ExtensionInfoTest { + + @Test + void loadShouldReturnExtensionInfoWhenClassExists() { + ExtensionInfo info = ExtensionInfo.load("org.pf4j.asm.ExtensionInfo", this.getClass().getClassLoader()); + assertNotNull(info); + assertEquals("org.pf4j.asm.ExtensionInfo", info.getClassName()); + } + + @Test + void loadShouldReturnNullWhenClassDoesNotExist() { + ExtensionInfo info = ExtensionInfo.load("non.existent.Class", this.getClass().getClassLoader()); + assertNull(info); + } + + @Test + void getClassNameShouldReturnCorrectName() { + ExtensionInfo info = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + assertEquals("org.pf4j.asm.ExtensionInfo", info.getClassName()); + } + + @Test + void getOrdinalShouldReturnZeroWhenNotSet() { + ExtensionInfo info = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + assertEquals(0, info.getOrdinal()); + } + + @Test + void getPluginsShouldReturnEmptyListWhenNotSet() { + ExtensionInfo info = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + assertTrue(info.getPlugins().isEmpty()); + } + + @Test + void getPointsShouldReturnEmptyListWhenNotSet() { + ExtensionInfo info = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + assertTrue(info.getPoints().isEmpty()); + } + +} diff --git a/pf4j/src/test/java/org/pf4j/asm/ExtensionVisitorTest.java b/pf4j/src/test/java/org/pf4j/asm/ExtensionVisitorTest.java new file mode 100644 index 0000000..ecccc0a --- /dev/null +++ b/pf4j/src/test/java/org/pf4j/asm/ExtensionVisitorTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pf4j.asm; + +import org.junit.jupiter.api.Test; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Type; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ExtensionVisitorTest { + + @Test + void visitAnnotationShouldReturnExtensionAnnotationVisitor() { + ExtensionInfo extensionInfo = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + ClassVisitor extensionVisitor = new ExtensionVisitor(extensionInfo); + + AnnotationVisitor returnedVisitor = extensionVisitor.visitAnnotation("Lorg/pf4j/Extension;", true); + + assertNotNull(returnedVisitor); + } + + @Test + void visitAnnotationShouldReturnSuperVisitorForNonExtensionAnnotation() { + ExtensionInfo extensionInfo = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + ClassVisitor extensionVisitor = new ExtensionVisitor(extensionInfo); + + AnnotationVisitor returnedVisitor = extensionVisitor.visitAnnotation("Lorg/pf4j/NonExtension;", true); + + assertNull(returnedVisitor); + } + + @Test + void visitArrayShouldHandleOrdinalAttribute() { + ExtensionInfo extensionInfo = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + ClassVisitor extensionVisitor = new ExtensionVisitor(extensionInfo); + + AnnotationVisitor annotationVisitor = extensionVisitor.visitAnnotation("Lorg/pf4j/Extension;", true); + AnnotationVisitor arrayVisitor = annotationVisitor.visitArray("ordinal"); + + arrayVisitor.visit("key", 1); + + assertEquals(1, extensionInfo.getOrdinal()); + } + + @Test + void visitArrayShouldHandlePluginsAttribute() { + ExtensionInfo extensionInfo = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + ClassVisitor extensionVisitor = new ExtensionVisitor(extensionInfo); + + AnnotationVisitor annotationVisitor = extensionVisitor.visitAnnotation("Lorg/pf4j/Extension;", true); + AnnotationVisitor arrayVisitor = annotationVisitor.visitArray("plugins"); + + arrayVisitor.visit("key", "plugin1"); + + assertTrue(extensionInfo.getPlugins().contains("plugin1")); + } + + @Test + void visitArrayShouldHandlePointsAttribute() { + ExtensionInfo extensionInfo = new ExtensionInfo("org.pf4j.asm.ExtensionInfo"); + ClassVisitor extensionVisitor = new ExtensionVisitor(extensionInfo); + + AnnotationVisitor annotationVisitor = extensionVisitor.visitAnnotation("Lorg/pf4j/Extension;", true); + AnnotationVisitor arrayVisitor = annotationVisitor.visitArray("points"); + + arrayVisitor.visit("key", Type.getType("Lorg/pf4j/Point;")); + + assertTrue(extensionInfo.getPoints().contains("org.pf4j.Point")); + } + +} -- 2.39.5