From 220c27d45e9577c4c27dcc48a5219c7f15aad4e9 Mon Sep 17 00:00:00 2001 From: simonbrandhof Date: Fri, 27 May 2011 13:52:46 +0200 Subject: [PATCH] SONAR-2469 add unit tests --- .../bootstrap/BatchPluginRepository.java | 53 +++++++---- .../batch/bootstrap/ExtensionDownloader.java | 2 +- .../bootstrap/BatchPluginRepositoryTest.java | 87 +++++++++++++++--- .../sonar-artifact-size-plugin-0.2.jar | Bin 0 -> 7448 bytes .../sonar-clirr-plugin-1.1.jar | Bin 0 -> 18342 bytes 5 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-clirr-plugin-1.1.jar diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java index c9dce2513c8..b647df8bc7a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java @@ -57,23 +57,38 @@ public class BatchPluginRepository implements PluginRepository { } public void start() { - List pluginsMetadata = Lists.newArrayList(); + doStart(dao.getPlugins()); + } + + public void doStart(List basePlugins) { pluginsByKey = Maps.newHashMap(); ClassLoadersCollection classLoaders = new ClassLoadersCollection(Thread.currentThread().getContextClassLoader()); - List jpaPlugins = dao.getPlugins(); + List pluginsMetadata = Lists.newArrayList(basePlugins); + createClassloaders(classLoaders, basePlugins); + pluginsMetadata.addAll(extendClassloaders(classLoaders, pluginsMetadata)); + instantiatePluginEntryPoints(classLoaders, pluginsMetadata); - for (JpaPlugin pluginMetadata : jpaPlugins) { - if (StringUtils.isEmpty(pluginMetadata.getBasePlugin())) { - String key = pluginMetadata.getKey(); - List urls = download(pluginMetadata); - classLoaders.createClassLoader(key, urls, pluginMetadata.isUseChildFirstClassLoader() == Boolean.TRUE); - pluginsMetadata.add(pluginMetadata); + classLoaders.done(); + } + + private void instantiatePluginEntryPoints(ClassLoadersCollection classLoaders, List pluginsMetadata) { + for (JpaPlugin pluginMetadata : pluginsMetadata) { + try { + Class claz = classLoaders.get(pluginMetadata.getKey()).loadClass(pluginMetadata.getPluginClass()); + Plugin plugin = (Plugin) claz.newInstance(); + pluginsByKey.put(pluginMetadata.getKey(), plugin); + + } catch (Exception e) { + throw new SonarException("Fail to load plugin " + pluginMetadata.getKey(), e); } } + } + private List extendClassloaders(ClassLoadersCollection classLoaders, List pluginsMetadata) { + List extensions = Lists.newArrayList(); // Extend plugins by other plugins - for (JpaPlugin pluginMetadata : jpaPlugins) { + for (JpaPlugin pluginMetadata : pluginsMetadata) { String pluginKey = pluginMetadata.getKey(); String basePluginKey = pluginMetadata.getBasePlugin(); if (StringUtils.isNotEmpty(basePluginKey)) { @@ -81,7 +96,7 @@ public class BatchPluginRepository implements PluginRepository { LOG.debug("Plugin {} extends {}", pluginKey, basePluginKey); List urls = download(pluginMetadata); classLoaders.extend(basePluginKey, pluginKey, urls); - pluginsMetadata.add(pluginMetadata); + extensions.add(pluginMetadata); } else { // Ignored, because base plugin doesn't exists @@ -89,19 +104,17 @@ public class BatchPluginRepository implements PluginRepository { } } } + return extensions; + } - for (JpaPlugin pluginMetadata : jpaPlugins) { - try { - Class claz = classLoaders.get(pluginMetadata.getKey()).loadClass(pluginMetadata.getPluginClass()); - Plugin plugin = (Plugin) claz.newInstance(); - pluginsByKey.put(pluginMetadata.getKey(), plugin); - - } catch (Exception e) { - throw new SonarException("Fail to load plugin " + pluginMetadata.getKey(), e); + private void createClassloaders(ClassLoadersCollection classLoaders, List basePlugins) { + for (JpaPlugin pluginMetadata : basePlugins) { + if (StringUtils.isEmpty(pluginMetadata.getBasePlugin())) { + String key = pluginMetadata.getKey(); + List urls = download(pluginMetadata); + classLoaders.createClassLoader(key, urls, pluginMetadata.isUseChildFirstClassLoader() == Boolean.TRUE); } } - - classLoaders.done(); } private List download(JpaPlugin pluginMetadata) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionDownloader.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionDownloader.java index 49ec936b24d..397838986f7 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionDownloader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionDownloader.java @@ -32,7 +32,7 @@ import java.net.URISyntaxException; /** * TODO this class should be renamed ArtifactDownloader, because it does not relate only to plugin extensions. */ -public final class ExtensionDownloader implements BatchComponent { +public class ExtensionDownloader implements BatchComponent { private HttpDownloader httpDownloader; private TempDirectories workingDirectories; diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java index 18a6281e6b8..00c914319cc 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java @@ -19,25 +19,84 @@ */ package org.sonar.batch.bootstrap; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.util.FileUtils; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Test; +import org.sonar.api.Plugin; +import org.sonar.core.plugin.JpaPlugin; +import org.sonar.core.plugin.JpaPluginFile; + +import java.util.Arrays; + +import static org.hamcrest.Matchers.not; import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.junit.Ignore; -import org.junit.Test; -import org.picocontainer.MutablePicoContainer; -import org.sonar.api.BatchExtension; -import org.sonar.api.ServerExtension; -import org.sonar.api.batch.AbstractCoverageExtension; -import org.sonar.api.resources.Java; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Project.AnalysisType; -import org.sonar.api.utils.IocContainer; - -@Ignore public class BatchPluginRepositoryTest { + @Test + public void shouldLoadPlugin() { + ExtensionDownloader extensionDownloader = mock(ExtensionDownloader.class); + when(extensionDownloader.downloadExtension(any(JpaPluginFile.class))).thenReturn( + FileUtils.toFile(getClass().getResource("/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar"))); + BatchPluginRepository repository = new BatchPluginRepository(null, extensionDownloader); + + JpaPlugin plugin = new JpaPlugin("artifactsize"); + plugin.setPluginClass("org.sonar.plugins.artifactsize.ArtifactSizePlugin"); + plugin.createFile("sonar-artifact-size-plugin-0.2.jar"); + repository.doStart(Arrays.asList(plugin)); + + Plugin entryPoint = repository.getPlugin("artifactsize"); + assertThat(entryPoint, not(nullValue())); + ClassRealm classloader = (ClassRealm) entryPoint.getClass().getClassLoader(); + assertThat(classloader.getId(), is("artifactsize")); + } + + /** + * Of course clirr does not extend artifact-size plugin in real life ! + */ + @Test + public void shouldPluginExtensionInTheSameClassloader() { + ExtensionDownloader extensionDownloader = mock(ExtensionDownloader.class); + prepareDownloader(extensionDownloader, "artifactsize", "/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar"); + prepareDownloader(extensionDownloader, "clirr", "/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-clirr-plugin-1.1.jar"); + BatchPluginRepository repository = new BatchPluginRepository(null, extensionDownloader); + + JpaPlugin pluginBase = new JpaPlugin("artifactsize"); + pluginBase.setPluginClass("org.sonar.plugins.artifactsize.ArtifactSizePlugin"); + pluginBase.createFile("sonar-artifact-size-plugin-0.2.jar"); + + JpaPlugin pluginExtension = new JpaPlugin("clirr"); + pluginExtension.setBasePlugin("artifactsize"); + pluginExtension.setPluginClass("org.sonar.plugins.clirr.ClirrPlugin"); + pluginExtension.createFile("sonar-clirr-plugin-1.1.jar"); + + repository.doStart(Arrays.asList(pluginBase, pluginExtension)); + + Plugin entryPointBase = repository.getPlugin("artifactsize"); + Plugin entryPointExtension = repository.getPlugin("clirr"); + assertThat(entryPointBase.getClass().getClassLoader(), is(entryPointExtension.getClass().getClassLoader())); + } + + private void prepareDownloader(ExtensionDownloader extensionDownloader, final String pluginKey, final String filename) { + when(extensionDownloader.downloadExtension(argThat(new BaseMatcher() { + public boolean matches(Object o) { + return o!=null && ((JpaPluginFile) o).getPluginKey().equals(pluginKey); + } + + public void describeTo(Description description) { + + } + }))).thenReturn(FileUtils.toFile(getClass().getResource(filename))); + } + // @Test // public void shouldRegisterBatchExtension() { // MutablePicoContainer pico = IocContainer.buildPicoContainer(); diff --git a/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar b/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..917d9860f5bce19854a1b9b30763c245b0246c28 GIT binary patch literal 7448 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 UAhn;93Pl94M{bG)ij$}R0lwT3W&i*H literal 0 HcmV?d00001 diff --git a/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-clirr-plugin-1.1.jar b/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginRepositoryTest/sonar-clirr-plugin-1.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..ef2ee8c4ac40dca442d1556cf18fc83e13ee6b6a GIT binary patch literal 18342 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