diff options
author | Matteo Mara <matteo.mara@sonarsource.com> | 2022-11-25 16:14:14 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-12-06 20:02:53 +0000 |
commit | 7cbc1b9bdaf97cab2f194895071ac1129f55f27c (patch) | |
tree | 0ce0a999b7557ae00f546ae279a1412639f7f89e /server/sonar-webserver-api | |
parent | 09e15e5451251ab6e4a1e13f07c200af3d0ee7f2 (diff) | |
download | sonarqube-7cbc1b9bdaf97cab2f194895071ac1129f55f27c.tar.gz sonarqube-7cbc1b9bdaf97cab2f194895071ac1129f55f27c.zip |
SONAR-17678 remove usage of pack200
Diffstat (limited to 'server/sonar-webserver-api')
7 files changed, 38 insertions, 277 deletions
diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginCompressor.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginCompressor.java deleted file mode 100644 index 7cfc7321422..00000000000 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginCompressor.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.plugins; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Optional; -import java.util.jar.JarInputStream; -import java.util.jar.Pack200; -import java.util.zip.GZIPOutputStream; -import org.sonar.api.config.Configuration; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; -import org.sonar.server.plugins.PluginFilesAndMd5.FileAndMd5; - -@ServerSide -public class PluginCompressor { - - public static final String PROPERTY_PLUGIN_COMPRESSION_ENABLE = "sonar.pluginsCompression.enable"; - private static final Logger LOG = Loggers.get(PluginCompressor.class); - - private final Configuration configuration; - - public PluginCompressor(Configuration configuration) { - this.configuration = configuration; - } - - public boolean enabled() { - return configuration.getBoolean(PROPERTY_PLUGIN_COMPRESSION_ENABLE).orElse(false); - } - - /** - * @param loadedJar the JAR loaded by classloaders. It differs from {@code jar} - * which is the initial location of JAR as seen by users - */ - public PluginFilesAndMd5 compress(String key, File jar, File loadedJar) { - Optional<File> compressed = compressJar(key, jar, loadedJar); - return new PluginFilesAndMd5(new FileAndMd5(loadedJar), compressed.map(FileAndMd5::new).orElse(null)); - } - - private Optional<File> compressJar(String key, File jar, File loadedJar) { - if (!configuration.getBoolean(PROPERTY_PLUGIN_COMPRESSION_ENABLE).orElse(false)) { - return Optional.empty(); - } - - Path targetPack200 = getPack200Path(loadedJar.toPath()); - Path sourcePack200Path = getPack200Path(jar.toPath()); - - // check if packed file was deployed alongside the jar. If that's the case, use it instead of generating it (SONAR-10395). - if (sourcePack200Path.toFile().exists()) { - try { - LOG.debug("Found pack200: " + sourcePack200Path); - Files.copy(sourcePack200Path, targetPack200); - } catch (IOException e) { - throw new IllegalStateException("Failed to copy pack200 file from " + sourcePack200Path + " to " + targetPack200, e); - } - } else { - pack200(loadedJar.toPath(), targetPack200, key); - } - return Optional.of(targetPack200.toFile()); - } - - private static void pack200(Path jarPath, Path toPack200Path, String pluginKey) { - Profiler profiler = Profiler.create(LOG); - profiler.startInfo("Compressing plugin " + pluginKey + " [pack200]"); - - try (JarInputStream in = new JarInputStream(new BufferedInputStream(Files.newInputStream(jarPath))); - OutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(toPack200Path)))) { - Pack200.newPacker().pack(in, out); - } catch (IOException e) { - throw new IllegalStateException(String.format("Fail to pack200 plugin [%s] '%s' to '%s'", pluginKey, jarPath, toPack200Path), e); - } - profiler.stopInfo(); - } - - private static Path getPack200Path(Path jar) { - String jarFileName = jar.getFileName().toString(); - String filename = jarFileName.substring(0, jarFileName.length() - 3) + "pack.gz"; - return jar.resolveSibling(filename); - } -} diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPlugin.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPlugin.java index 6d348d03094..11a6ce1418c 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPlugin.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPlugin.java @@ -19,8 +19,6 @@ */ package org.sonar.server.plugins; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; import org.sonar.api.Plugin; import org.sonar.core.platform.PluginInfo; import org.sonar.core.plugin.PluginType; @@ -31,19 +29,17 @@ public class ServerPlugin { private final PluginType type; private final Plugin instance; private final FileAndMd5 jar; - private final FileAndMd5 compressed; private final ClassLoader classloader; - public ServerPlugin(PluginInfo pluginInfo, PluginType type, Plugin instance, FileAndMd5 jar, @Nullable FileAndMd5 compressed) { - this(pluginInfo, type, instance, jar, compressed, instance.getClass().getClassLoader()); + public ServerPlugin(PluginInfo pluginInfo, PluginType type, Plugin instance, FileAndMd5 jar) { + this(pluginInfo, type, instance, jar, instance.getClass().getClassLoader()); } - public ServerPlugin(PluginInfo pluginInfo, PluginType type, Plugin instance, FileAndMd5 jar, @Nullable FileAndMd5 compressed, ClassLoader classloader) { + public ServerPlugin(PluginInfo pluginInfo, PluginType type, Plugin instance, FileAndMd5 jar, ClassLoader classloader) { this.pluginInfo = pluginInfo; this.type = type; this.instance = instance; this.jar = jar; - this.compressed = compressed; this.classloader = classloader; } @@ -63,11 +59,6 @@ public class ServerPlugin { return jar; } - @CheckForNull - public FileAndMd5 getCompressed() { - return compressed; - } - public ClassLoader getClassloader() { return classloader; } diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPluginManager.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPluginManager.java index 3b97129c13d..22dea0b6ed2 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPluginManager.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPluginManager.java @@ -48,15 +48,13 @@ public class ServerPluginManager implements Startable { private final PluginJarLoader pluginJarLoader; private final PluginJarExploder pluginJarExploder; private final PluginClassLoader pluginClassLoader; - private final PluginCompressor pluginCompressor; private final ServerPluginRepository pluginRepository; public ServerPluginManager(PluginClassLoader pluginClassLoader, PluginJarExploder pluginJarExploder, - PluginJarLoader pluginJarLoader, PluginCompressor pluginCompressor, ServerPluginRepository pluginRepository) { + PluginJarLoader pluginJarLoader, ServerPluginRepository pluginRepository) { this.pluginClassLoader = pluginClassLoader; this.pluginJarExploder = pluginJarExploder; this.pluginJarLoader = pluginJarLoader; - this.pluginCompressor = pluginCompressor; this.pluginRepository = pluginRepository; } @@ -67,7 +65,7 @@ public class ServerPluginManager implements Startable { Collection<ExplodedPlugin> explodedPlugins = extractPlugins(loadedPlugins); Map<String, Plugin> instancesByKey = pluginClassLoader.load(explodedPlugins); Map<String, PluginType> typesByKey = getTypesByKey(loadedPlugins); - List<ServerPlugin> plugins = compressAndCreateServerPlugins(explodedPlugins, instancesByKey, typesByKey); + List<ServerPlugin> plugins = createServerPlugins(explodedPlugins, instancesByKey, typesByKey); pluginRepository.addPlugins(plugins); } @@ -88,12 +86,11 @@ public class ServerPluginManager implements Startable { return plugins.stream().map(pluginJarExploder::explode).collect(Collectors.toList()); } - private List<ServerPlugin> compressAndCreateServerPlugins(Collection<ExplodedPlugin> explodedPlugins, Map<String, Plugin> instancesByKey, Map<String, PluginType> typseByKey) { + private static List<ServerPlugin> createServerPlugins(Collection<ExplodedPlugin> explodedPlugins, Map<String, Plugin> instancesByKey, Map<String, PluginType> typesByKey) { List<ServerPlugin> plugins = new ArrayList<>(); for (ExplodedPlugin p : explodedPlugins) { - PluginFilesAndMd5 installedPlugin = pluginCompressor.compress(p.getKey(), p.getPluginInfo().getNonNullJarFile(), p.getMain()); - plugins.add(new ServerPlugin(p.getPluginInfo(), typseByKey.get(p.getKey()), instancesByKey.get(p.getKey()), - installedPlugin.getLoadedJar(), installedPlugin.getCompressedJar())); + plugins.add(new ServerPlugin(p.getPluginInfo(), typesByKey.get(p.getKey()), instancesByKey.get(p.getKey()), + new PluginFilesAndMd5.FileAndMd5(p.getPluginInfo().getNonNullJarFile()))); } return plugins; } diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginCompressorTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginCompressorTest.java deleted file mode 100644 index 0c75517d094..00000000000 --- a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginCompressorTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.plugins; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.config.internal.MapSettings; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.plugins.PluginCompressor.PROPERTY_PLUGIN_COMPRESSION_ENABLE; - -public class PluginCompressorTest { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - private MapSettings settings = new MapSettings(); - - @Before - public void setUp() throws IOException { - Path targetFolder = temp.newFolder("target").toPath(); - Path targetJarPath = targetFolder.resolve("test.jar"); - Files.createFile(targetJarPath); - } - - @Test - public void compress_jar_if_compression_enabled() throws IOException { - File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - // the JAR is copied somewhere else in order to be loaded by classloaders - File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - - settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true); - PluginCompressor underTest = new PluginCompressor(settings.asConfig()); - - PluginFilesAndMd5 installedPlugin = underTest.compress("foo", jar, loadedJar); - assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath()); - assertThat(installedPlugin.getCompressedJar().getFile()) - .exists() - .isFile() - .hasName("sonar-foo-plugin.pack.gz") - .hasParent(loadedJar.getParentFile()); - } - - @Test - public void dont_compress_jar_if_compression_disable() throws IOException { - File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - // the JAR is copied somewhere else in order to be loaded by classloaders - File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - - settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, false); - PluginCompressor underTest = new PluginCompressor(settings.asConfig()); - - PluginFilesAndMd5 installedPlugin = underTest.compress("foo", jar, loadedJar); - assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath()); - assertThat(installedPlugin.getCompressedJar()).isNull(); - assertThat(installedPlugin.getLoadedJar().getFile().getParentFile().listFiles()).containsOnly(loadedJar); - } - - @Test - public void copy_and_use_existing_packed_jar_if_compression_enabled() throws IOException { - File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - File packedJar = touch(jar.getParentFile(), "sonar-foo-plugin.pack.gz"); - // the JAR is copied somewhere else in order to be loaded by classloaders - File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - - settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true); - PluginCompressor underTest = new PluginCompressor(settings.asConfig()); - - PluginFilesAndMd5 installedPlugin = underTest.compress("foo", jar, loadedJar); - assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath()); - assertThat(installedPlugin.getCompressedJar().getFile()) - .exists() - .isFile() - .hasName(packedJar.getName()) - .hasParent(loadedJar.getParentFile()) - .hasSameTextualContentAs(packedJar); - } - - private static File touch(File dir, String filename) throws IOException { - File file = new File(dir, filename); - FileUtils.write(file, RandomStringUtils.random(10), StandardCharsets.UTF_8); - return file; - } - - // - // @Test - // public void should_use_deployed_packed_file() throws IOException { - // Path packedPath = sourceFolder.resolve("test.pack.gz"); - // Files.write(packedPath, new byte[] {1, 2, 3}); - // - // settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true); - // underTest = new PluginFileSystem(settings.asConfig()); - // underTest.compressJar("key", sourceFolder, targetJarPath); - // - // assertThat(Files.list(targetFolder)).containsOnly(targetJarPath, targetFolder.resolve("test.pack.gz")); - // assertThat(underTest.getPlugins()).hasSize(1); - // assertThat(underTest.getPlugins().get("key").getFilename()).isEqualTo("test.pack.gz"); - // - // // check that the file was copied, not generated - // assertThat(targetFolder.resolve("test.pack.gz")).hasSameContentAs(packedPath); - // } - -} diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java index 5bf536717e1..8bbbdf7860d 100644 --- a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java +++ b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java @@ -162,7 +162,7 @@ public class PluginUninstallerTest { private static ServerPlugin newPlugin(ServerPluginInfo pluginInfo) { return new ServerPlugin(pluginInfo, pluginInfo.getType(), mock(Plugin.class), - mock(PluginFilesAndMd5.FileAndMd5.class), mock(PluginFilesAndMd5.FileAndMd5.class), mock(ClassLoader.class)); + mock(PluginFilesAndMd5.FileAndMd5.class), mock(ClassLoader.class)); } private File copyTestPluginTo(String testPluginName, File toDir) throws IOException { diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginManagerTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginManagerTest.java index 1075795185c..4164eb7c373 100644 --- a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginManagerTest.java +++ b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginManagerTest.java @@ -21,9 +21,11 @@ package org.sonar.server.plugins; import com.google.common.collect.ImmutableMap; import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Map; +import org.jetbrains.annotations.NotNull; import org.junit.After; import org.junit.Rule; import org.junit.Test; @@ -36,7 +38,7 @@ import org.sonar.server.plugins.PluginFilesAndMd5.FileAndMd5; import org.sonar.updatecenter.common.Version; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -50,9 +52,8 @@ public class ServerPluginManagerTest { private PluginClassLoader pluginClassLoader = mock(PluginClassLoader.class); private PluginJarExploder jarExploder = mock(PluginJarExploder.class); private PluginJarLoader jarLoader = mock(PluginJarLoader.class); - private PluginCompressor pluginCompressor = mock(PluginCompressor.class); private ServerPluginRepository pluginRepository = new ServerPluginRepository(); - private ServerPluginManager underTest = new ServerPluginManager(pluginClassLoader, jarExploder, jarLoader, pluginCompressor, pluginRepository); + private ServerPluginManager underTest = new ServerPluginManager(pluginClassLoader, jarExploder, jarLoader, pluginRepository); @After public void tearDown() { @@ -69,18 +70,20 @@ public class ServerPluginManagerTest { Map<String, Plugin> instances = ImmutableMap.of("p1", mock(Plugin.class), "p2", mock(Plugin.class)); when(pluginClassLoader.load(anyList())).thenReturn(instances); - PluginFilesAndMd5 p1Files = newPluginFilesAndMd5("p1"); - PluginFilesAndMd5 p2Files = newPluginFilesAndMd5("p2"); - - when(pluginCompressor.compress("p1", new File("p1.jar"), new File("p1Exploded.jar"))).thenReturn(p1Files); - when(pluginCompressor.compress("p2", new File("p2.jar"), new File("p2Exploded.jar"))).thenReturn(p2Files); underTest.start(); - assertThat(pluginRepository.getPlugins()) - .extracting(ServerPlugin::getPluginInfo, ServerPlugin::getCompressed, ServerPlugin::getJar, ServerPlugin::getInstance) - .containsOnly(tuple(p1, p1Files.getCompressedJar(), p1Files.getLoadedJar(), instances.get("p1")), - tuple(p2, p2Files.getCompressedJar(), p2Files.getLoadedJar(), instances.get("p2"))); + assertEquals(2, pluginRepository.getPlugins().size()); + + assertEquals(p1, pluginRepository.getPlugin("p1").getPluginInfo()); + assertEquals(newFileAndMd5(p1.getNonNullJarFile()).getFile(), pluginRepository.getPlugin("p1").getJar().getFile()); + assertEquals(newFileAndMd5(p1.getNonNullJarFile()).getMd5(), pluginRepository.getPlugin("p1").getJar().getMd5()); + assertEquals(instances.get("p1"), pluginRepository.getPlugin("p1").getInstance()); + + assertEquals(p2, pluginRepository.getPlugin("p2").getPluginInfo()); + assertEquals(newFileAndMd5(p2.getNonNullJarFile()).getFile(), pluginRepository.getPlugin("p2").getJar().getFile()); + assertEquals(newFileAndMd5(p2.getNonNullJarFile()).getMd5(), pluginRepository.getPlugin("p2").getJar().getMd5()); + assertEquals(instances.get("p2"), pluginRepository.getPlugin("p2").getInstance()); assertThat(pluginRepository.getPlugins()).extracting(ServerPlugin::getPluginInfo) .allMatch(p -> logTester.logs().contains(String.format("Deploy %s / %s / %s", p.getName(), p.getVersion(), p.getImplementationBuild()))); @@ -90,7 +93,7 @@ public class ServerPluginManagerTest { ServerPluginInfo pluginInfo = mock(ServerPluginInfo.class); when(pluginInfo.getKey()).thenReturn(key); when(pluginInfo.getType()).thenReturn(EXTERNAL); - when(pluginInfo.getNonNullJarFile()).thenReturn(new File(key + ".jar")); + when(pluginInfo.getNonNullJarFile()).thenReturn(getJarFile(key)); when(pluginInfo.getName()).thenReturn(key + "_name"); Version version = mock(Version.class); when(version.getName()).thenReturn(key + "_version"); @@ -99,15 +102,18 @@ public class ServerPluginManagerTest { return pluginInfo; } - private static PluginFilesAndMd5 newPluginFilesAndMd5(String name) { - FileAndMd5 jar = mock(FileAndMd5.class); - when(jar.getFile()).thenReturn(new File(name)); - when(jar.getMd5()).thenReturn(name + "-md5"); - - FileAndMd5 compressed = mock(FileAndMd5.class); - when(compressed.getFile()).thenReturn(new File(name + "-compressed")); - when(compressed.getMd5()).thenReturn(name + "-compressed-md5"); + @NotNull + private static File getJarFile(String key) { + File file = new File(key + ".jar"); + try { + file.createNewFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return file; + } - return new PluginFilesAndMd5(jar, compressed); + private static FileAndMd5 newFileAndMd5(File file) { + return new PluginFilesAndMd5.FileAndMd5(file); } } diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java index f5250e05951..f66e2adfa7f 100644 --- a/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java +++ b/server/sonar-webserver-api/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java @@ -133,6 +133,6 @@ public class ServerPluginRepositoryTest { } private ServerPlugin newPlugin(String key, PluginType type) { - return new ServerPlugin(newPluginInfo(key), type, mock(Plugin.class), mock(FileAndMd5.class), mock(FileAndMd5.class), mock(ClassLoader.class)); + return new ServerPlugin(newPluginInfo(key), type, mock(Plugin.class), mock(FileAndMd5.class), mock(ClassLoader.class)); } } |