@@ -0,0 +1 @@ | |||
This directory contains temporary data required by server. Do not clean up when server is up. |
@@ -33,7 +33,7 @@ import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.PluginMetadata; | |||
import org.sonar.api.platform.PluginRepository; | |||
import org.sonar.core.plugins.PluginClassloaders; | |||
import org.sonar.core.plugins.PluginFileExtractor; | |||
import org.sonar.core.plugins.PluginInstaller; | |||
import org.sonar.core.plugins.RemotePlugin; | |||
import java.io.File; | |||
@@ -68,7 +68,7 @@ public class BatchPluginRepository implements PluginRepository { | |||
} | |||
void doStart(List<RemotePlugin> remotePlugins) { | |||
PluginFileExtractor extractor = new PluginFileExtractor(); | |||
PluginInstaller extractor = new PluginInstaller(); | |||
metadataByKey = Maps.newHashMap(); | |||
for (RemotePlugin remote : remotePlugins) { | |||
if (isAccepted(remote.getKey())) { |
@@ -33,7 +33,7 @@ import java.net.URLClassLoader; | |||
import java.util.List; | |||
import java.util.zip.ZipEntry; | |||
public class PluginFileExtractor { | |||
public class PluginInstaller { | |||
public DefaultPluginMetadata installInSameLocation(File pluginFile, boolean isCore, List<File> deprecatedExtensions) { | |||
return install(pluginFile, isCore, deprecatedExtensions, null); |
@@ -29,9 +29,9 @@ import static org.hamcrest.CoreMatchers.is; | |||
import static org.hamcrest.CoreMatchers.nullValue; | |||
import static org.junit.Assert.assertThat; | |||
public class PluginFileExtractorTest { | |||
public class PluginInstallerTest { | |||
private PluginFileExtractor extractor= new PluginFileExtractor(); | |||
private PluginInstaller extractor= new PluginInstaller(); | |||
@Test | |||
public void shouldExtractMetadata() { | |||
@@ -60,7 +60,7 @@ public class PluginFileExtractorTest { | |||
@Test | |||
public void shouldCopyAndExtractDependencies() throws IOException { | |||
File toDir = new File("target/test-tmp/PluginFileExtractorTest/shouldCopyAndExtractDependencies"); | |||
File toDir = new File("target/test-tmp/PluginInstallerTest/shouldCopyAndExtractDependencies"); | |||
FileUtils.forceMkdir(toDir); | |||
FileUtils.cleanDirectory(toDir); | |||
@@ -73,7 +73,7 @@ public class PluginFileExtractorTest { | |||
@Test | |||
public void shouldExtractOnlyDependencies() throws IOException { | |||
File toDir = new File("target/test-tmp/PluginFileExtractorTest/shouldExtractOnlyDependencies"); | |||
File toDir = new File("target/test-tmp/PluginInstallerTest/shouldExtractOnlyDependencies"); | |||
FileUtils.forceMkdir(toDir); | |||
FileUtils.cleanDirectory(toDir); | |||
@@ -86,13 +86,13 @@ public class PluginFileExtractorTest { | |||
@Test | |||
public void shouldCopyRuleExtensionsOnServerSide() throws IOException { | |||
File toDir = new File("target/test-tmp/PluginFileExtractorTest/shouldCopyRuleExtensionsOnServerSide"); | |||
File toDir = new File("target/test-tmp/PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide"); | |||
FileUtils.forceMkdir(toDir); | |||
FileUtils.cleanDirectory(toDir); | |||
DefaultPluginMetadata metadata = DefaultPluginMetadata.create(getFile("sonar-checkstyle-plugin-2.8.jar")) | |||
.setKey("checkstyle") | |||
.addDeprecatedExtension(getFile("PluginFileExtractorTest/shouldCopyRuleExtensionsOnServerSide/checkstyle-extension.xml")); | |||
.addDeprecatedExtension(getFile("PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide/checkstyle-extension.xml")); | |||
extractor.install(metadata, toDir); | |||
assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar").exists(), is(true)); |
@@ -30,6 +30,8 @@ import java.util.List; | |||
public interface ServerFileSystem extends ServerComponent { | |||
File getHomeDir(); | |||
File getTempDir(); | |||
/** | |||
* @param suffixes the file suffixes. If null, then return all the files, whatever their suffix |
@@ -0,0 +1,44 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api.web; | |||
import com.google.common.annotations.Beta; | |||
import org.sonar.api.ServerExtension; | |||
/** | |||
* Complete Ruby on Rails application (controllers/helpers/models/views) | |||
* @since 2.15 | |||
*/ | |||
@Beta | |||
public abstract class RubyRailsApp implements ServerExtension { | |||
/** | |||
* The app key, ie the plugin key. It does not relate to URLs at all. | |||
*/ | |||
public abstract String getKey(); | |||
/** | |||
* The classloader path to the root directory. It contains a sub-directory named app/. | |||
* <p>For example if Ruby on Rails controllers are located in /org/sonar/sqale/app/controllers/, | |||
* then the path is /org/sonar/sqale</p> | |||
*/ | |||
public abstract String getPath(); | |||
} |
@@ -102,6 +102,10 @@ public class DefaultServerFileSystem implements ServerFileSystem { | |||
public File getHomeDir() { | |||
return homeDir; | |||
} | |||
public File getTempDir() { | |||
return new File(homeDir, "temp"); | |||
} | |||
public File getDeployDir() { | |||
return deployDir; |
@@ -220,6 +220,7 @@ public final class Platform { | |||
private void executeStartupTasks() { | |||
ComponentContainer startupContainer = servicesContainer.createChild(); | |||
startupContainer.addSingleton(GwtPublisher.class); | |||
startupContainer.addSingleton(ApplicationDeployer.class); | |||
startupContainer.addSingleton(RegisterMetrics.class); | |||
startupContainer.addSingleton(RegisterRules.class); | |||
startupContainer.addSingleton(RegisterProvidedProfiles.class); |
@@ -80,13 +80,13 @@ public class DefaultServerPluginRepository implements ServerPluginRepository { | |||
return pluginsByKey.get(key); | |||
} | |||
public ClassLoader getClassloader(String pluginKey) { | |||
public ClassLoader getClassLoader(String pluginKey) { | |||
return classloaders.get(pluginKey); | |||
} | |||
public Class getClass(String pluginKey, String classname) { | |||
Class clazz = null; | |||
ClassLoader classloader = getClassloader(pluginKey); | |||
ClassLoader classloader = getClassLoader(pluginKey); | |||
if (classloader != null) { | |||
try { | |||
clazz = classloader.loadClass(classname); |
@@ -31,7 +31,7 @@ import org.sonar.api.utils.Logs; | |||
import org.sonar.api.utils.SonarException; | |||
import org.sonar.api.utils.TimeProfiler; | |||
import org.sonar.core.plugins.DefaultPluginMetadata; | |||
import org.sonar.core.plugins.PluginFileExtractor; | |||
import org.sonar.core.plugins.PluginInstaller; | |||
import org.sonar.server.platform.DefaultServerFileSystem; | |||
import org.sonar.server.platform.ServerStartException; | |||
@@ -47,13 +47,13 @@ public class PluginDeployer implements ServerComponent { | |||
private DefaultServerFileSystem fileSystem; | |||
private Map<String, PluginMetadata> pluginByKeys = Maps.newHashMap(); | |||
private PluginFileExtractor extractor; | |||
private PluginInstaller extractor; | |||
public PluginDeployer(DefaultServerFileSystem fileSystem) { | |||
this(fileSystem, new PluginFileExtractor()); | |||
this(fileSystem, new PluginInstaller()); | |||
} | |||
PluginDeployer(DefaultServerFileSystem fileSystem, PluginFileExtractor extractor) { | |||
PluginDeployer(DefaultServerFileSystem fileSystem, PluginInstaller extractor) { | |||
this.fileSystem = fileSystem; | |||
this.extractor = extractor; | |||
} |
@@ -46,7 +46,7 @@ public class StaticResourcesServlet extends HttpServlet { | |||
String resource = getResourcePath(request); | |||
DefaultServerPluginRepository pluginRepository = Platform.getInstance().getContainer().getComponentByType(DefaultServerPluginRepository.class); | |||
ClassLoader classLoader = pluginRepository.getClassloader(pluginKey); | |||
ClassLoader classLoader = pluginRepository.getClassLoader(pluginKey); | |||
if (classLoader == null) { | |||
LOG.error("Plugin not found: " + pluginKey); | |||
response.sendError(HttpServletResponse.SC_NOT_FOUND); |
@@ -0,0 +1,113 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.server.startup; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.base.Function; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.platform.ServerFileSystem; | |||
import org.sonar.api.web.RubyRailsApp; | |||
import javax.annotation.Nullable; | |||
import java.io.File; | |||
import java.io.IOException; | |||
/** | |||
* Ruby on Rails requires the files to be on filesystem but not in Java classpath (JAR). This component extracts | |||
* all the needed files from plugins and copy them to $SONAR_HOME/temp | |||
* | |||
* @since 2.15 | |||
*/ | |||
public class ApplicationDeployer { | |||
private static final Logger LOG = LoggerFactory.getLogger(ApplicationDeployer.class); | |||
private ServerFileSystem fileSystem; | |||
private RubyRailsApp[] apps; | |||
public ApplicationDeployer(ServerFileSystem fileSystem, RubyRailsApp[] apps) { | |||
this.fileSystem = fileSystem; | |||
this.apps = apps; | |||
} | |||
public ApplicationDeployer(ServerFileSystem fileSystem) { | |||
this(fileSystem, new RubyRailsApp[0]); | |||
} | |||
public void start() throws IOException { | |||
deployRubyRailsApps(); | |||
} | |||
private void deployRubyRailsApps() { | |||
LOG.info("Deploy Ruby on Rails applications"); | |||
File appsDir = prepareRubyRailsRootDirectory(); | |||
for (final RubyRailsApp app : apps) { | |||
try { | |||
deployRubyRailsApp(appsDir, app, app.getClass().getClassLoader()); | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Fail to deploy Ruby on Rails application: " + app.getKey(), e); | |||
} | |||
} | |||
} | |||
@VisibleForTesting | |||
File prepareRubyRailsRootDirectory() { | |||
File appsDir = new File(fileSystem.getTempDir(), "ror"); | |||
prepareDir(appsDir); | |||
return appsDir; | |||
} | |||
@VisibleForTesting | |||
static void deployRubyRailsApp(File appsDir, final RubyRailsApp app, ClassLoader appClassLoader) { | |||
LOG.debug("Deploy: " + app.getKey()); | |||
File appDir = new File(appsDir, app.getKey()); | |||
if (appDir.exists()) { | |||
LOG.error("Ruby on Rails application already exists: " + app.getKey()); | |||
} else { | |||
ClassLoaderUtils.copyResources(appClassLoader, app.getPath(), appDir, new Function<String, String>() { | |||
@Override | |||
public String apply(@Nullable String relativePath) { | |||
// relativePath format is: org/sonar/sqale/app/controllers/foo_controller.rb | |||
// app path is: /org/sonar/sqale | |||
// -> deployed file is app/controllers/foo_controller.rb | |||
return StringUtils.substringAfter(relativePath, StringUtils.removeStart(app.getPath(), "/") + "/"); | |||
} | |||
}); | |||
} | |||
} | |||
private void prepareDir(File appsDir) { | |||
if (appsDir.exists() && appsDir.isDirectory()) { | |||
try { | |||
FileUtils.deleteDirectory(appsDir); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Fail to delete temp directory: " + appsDir); | |||
} | |||
} | |||
try { | |||
FileUtils.forceMkdir(appsDir); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Fail to create temp directory: " + appsDir); | |||
} | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.server.startup; | |||
import com.google.common.base.*; | |||
import com.google.common.collect.Lists; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.CharEncoding; | |||
import org.apache.commons.lang.StringUtils; | |||
import javax.annotation.Nullable; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
import java.net.URLDecoder; | |||
import java.util.Collection; | |||
import java.util.Enumeration; | |||
import java.util.jar.JarEntry; | |||
import java.util.jar.JarFile; | |||
/** | |||
* TODO it this class needed in sonar-plugin-api ? | |||
* | |||
* @since 2.15 | |||
*/ | |||
public final class ClassLoaderUtils { | |||
private ClassLoaderUtils() { | |||
} | |||
public static File copyResources(ClassLoader classLoader, String rootPath, File toDir) { | |||
return copyResources(classLoader, rootPath, toDir, Functions.<String>identity()); | |||
} | |||
public static File copyResources(ClassLoader classLoader, String rootPath, File toDir, Function<String, String> relocationFunction) { | |||
Collection<String> relativePaths = listFiles(classLoader, rootPath); | |||
for (String relativePath : relativePaths) { | |||
URL resource = classLoader.getResource(relativePath); | |||
String filename = relocationFunction.apply(relativePath); | |||
File toFile = new File(toDir, filename); | |||
try { | |||
FileUtils.copyURLToFile(resource, toFile); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Fail to extract " + relativePath + " to " + toFile.getAbsolutePath()); | |||
} | |||
} | |||
return toDir; | |||
} | |||
public static Collection<String> listFiles(ClassLoader classLoader, String rootPath) { | |||
return listResources(classLoader, rootPath, new Predicate<String>() { | |||
@Override | |||
public boolean apply(@Nullable String path) { | |||
return !StringUtils.endsWith(path, "/"); | |||
} | |||
}); | |||
} | |||
public static Collection<String> listResources(ClassLoader classloader, String rootPath) { | |||
return listResources(classloader, rootPath, Predicates.<String>alwaysTrue()); | |||
} | |||
public static Collection<String> listResources(ClassLoader classloader, String rootPath, Predicate<String> predicate) { | |||
try { | |||
Collection<String> paths = Lists.newArrayList(); | |||
rootPath = StringUtils.removeStart(rootPath, "/"); | |||
URL root = classloader.getResource(rootPath); | |||
if (root == null) { | |||
return paths; | |||
} | |||
if (!"jar".equals(root.getProtocol())) { | |||
throw new IllegalStateException("Unsupported protocol: " + root.getProtocol()); | |||
} | |||
String jarPath = root.getPath().substring(5, root.getPath().indexOf("!")); //strip out only the JAR file | |||
JarFile jar = new JarFile(URLDecoder.decode(jarPath, CharEncoding.UTF_8)); | |||
Enumeration<JarEntry> entries = jar.entries(); | |||
while (entries.hasMoreElements()) { | |||
String name = entries.nextElement().getName(); | |||
if (name.startsWith(rootPath) && predicate.apply(name)) { | |||
paths.add(name); | |||
} | |||
} | |||
return paths; | |||
} catch (Exception e) { | |||
throw Throwables.propagate(e); | |||
} | |||
} | |||
} |
@@ -21,12 +21,11 @@ package org.sonar.server.ui; | |||
import org.apache.commons.configuration.Configuration; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.License; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.platform.PluginMetadata; | |||
import org.sonar.api.platform.PluginRepository; | |||
import org.sonar.api.platform.*; | |||
import org.sonar.api.profiles.ProfileExporter; | |||
import org.sonar.api.profiles.ProfileImporter; | |||
import org.sonar.api.resources.Language; | |||
@@ -416,6 +415,9 @@ public final class JRubyFacade { | |||
return License.readBase64(base64); | |||
} | |||
public String getServerHome() { | |||
return getContainer().getComponentByType(Settings.class).getString(CoreProperties.SONAR_HOME); | |||
} | |||
public ReviewsNotificationManager getReviewsNotificationManager() { | |||
return getContainer().getComponentByType(ReviewsNotificationManager.class); |
@@ -5,6 +5,21 @@ | |||
require File.join(File.dirname(__FILE__), 'boot') | |||
require 'color' | |||
# | |||
# Limitation of Rails 2.3 and Rails Engines (plugins) when threadsafe! is enabled in production mode | |||
# See http://groups.google.com/group/rubyonrails-core/browse_thread/thread/9067bce01444fb24?pli=1 | |||
# | |||
class EagerPluginLoader < Rails::Plugin::Loader | |||
def add_plugin_load_paths | |||
super | |||
plugins.each do |plugin| | |||
if configuration.cache_classes | |||
configuration.eager_load_paths += plugin.load_paths | |||
end | |||
end | |||
end | |||
end | |||
Rails::Initializer.run do |config| | |||
# Settings in config/environments/* take precedence over those specified here. | |||
# Application configuration should go into files in config/initializers | |||
@@ -15,8 +30,12 @@ Rails::Initializer.run do |config| | |||
# you must remove the Active Record framework. | |||
config.frameworks -= [ :action_mailer ] | |||
# Add additional load paths for your own custom dirs | |||
# config.load_paths += %W( #{RAILS_ROOT}/extras ) | |||
# This property can't be set in config/environments because of execution order | |||
# See http://strd6.com/2009/04/cant-dup-nilclass-maybe-try-unloadable/ | |||
config.reload_plugins=(RAILS_ENV == 'development') | |||
config.plugin_loader = EagerPluginLoader | |||
config.plugin_paths << "#{Java::OrgSonarServerUi::JRubyFacade.getInstance().getServerHome()}/temp/ror" | |||
# Force all environments to use the same logger level | |||
# (by default production uses :info, the others :debug) | |||
@@ -51,6 +70,8 @@ Rails::Initializer.run do |config| | |||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer | |||
end | |||
class ActiveRecord::Migration | |||
def self.alter_to_big_primary_key(tablename) | |||
dialect = ::Java::OrgSonarServerUi::JRubyFacade.getInstance().getDatabase().getDialect().getActiveRecordDialectCode() | |||
@@ -58,7 +79,7 @@ class ActiveRecord::Migration | |||
when "postgre" | |||
execute "ALTER TABLE #{tablename} ALTER COLUMN id TYPE bigint" | |||
when "mysql" | |||
execute "ALTER TABLE #{tablename} CHANGE id id BIGINT AUTO_INCREMENT"; | |||
execute "ALTER TABLE #{tablename} CHANGE id id BIGINT AUTO_INCREMENT" | |||
when "derby" | |||
# do nothing as alter can not do the job in Derby | |||
when "oracle" |
@@ -68,7 +68,7 @@ public class DefaultServerPluginRepositoryTest { | |||
assertThat(repository.getPlugins().size(), Is.is(1)); | |||
assertThat(repository.getPlugin("artifactsize"), not(nullValue())); | |||
assertThat(repository.getClassloader("artifactsize"), not(nullValue())); | |||
assertThat(repository.getClassLoader("artifactsize"), not(nullValue())); | |||
assertThat(repository.getClass("artifactsize", "org.sonar.plugins.artifactsize.ArtifactSizeMetrics"), not(nullValue())); | |||
assertThat(repository.getClass("artifactsize", "org.Unknown"), nullValue()); | |||
assertThat(repository.getClass("other", "org.sonar.plugins.artifactsize.ArtifactSizeMetrics"), nullValue()); |
@@ -25,7 +25,7 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TestName; | |||
import org.sonar.api.platform.PluginMetadata; | |||
import org.sonar.core.plugins.PluginFileExtractor; | |||
import org.sonar.core.plugins.PluginInstaller; | |||
import org.sonar.server.platform.DefaultServerFileSystem; | |||
import org.sonar.server.platform.ServerStartException; | |||
import org.sonar.test.TestUtils; | |||
@@ -39,7 +39,7 @@ import static org.junit.Assert.assertThat; | |||
public class PluginDeployerTest { | |||
private PluginFileExtractor extractor; | |||
private PluginInstaller extractor; | |||
private DefaultServerFileSystem fileSystem; | |||
private File homeDir; | |||
private File deployDir; | |||
@@ -53,7 +53,7 @@ public class PluginDeployerTest { | |||
homeDir = TestUtils.getResource(PluginDeployerTest.class, name.getMethodName()); | |||
deployDir = TestUtils.getTestTempDir(PluginDeployerTest.class, name.getMethodName() + "/deploy"); | |||
fileSystem = new DefaultServerFileSystem(null, homeDir, deployDir); | |||
extractor = new PluginFileExtractor(); | |||
extractor = new PluginInstaller(); | |||
deployer = new PluginDeployer(fileSystem, extractor); | |||
} | |||
@@ -0,0 +1,83 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.server.startup; | |||
import org.apache.commons.io.FileUtils; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.api.platform.ServerFileSystem; | |||
import org.sonar.api.web.RubyRailsApp; | |||
import java.io.File; | |||
import java.net.URL; | |||
import java.net.URLClassLoader; | |||
import static org.hamcrest.CoreMatchers.is; | |||
import static org.junit.Assert.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
public class ApplicationDeployerTest { | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@Test | |||
public void deployRubyRailsApp() throws Exception { | |||
File tempDir = this.temp.getRoot(); | |||
ClassLoader classLoader = new URLClassLoader(new URL[]{ | |||
getClass().getResource("/org/sonar/server/startup/ApplicationDeployerTest/FakeRubyRailsApp.jar").toURI().toURL()}, null); | |||
ApplicationDeployer.deployRubyRailsApp(tempDir, new FakeRubyRailsApp(), classLoader); | |||
File appDir = new File(tempDir, "fake"); | |||
assertThat(appDir.isDirectory(), is(true)); | |||
assertThat(appDir.exists(), is(true)); | |||
assertThat(FileUtils.listFiles(appDir, null, true).size(), is(2)); | |||
assertThat(new File(appDir, "app/controllers/fake_controller.rb").exists(), is(true)); | |||
assertThat(new File(appDir, "app/views/fake/index.html.erb").exists(), is(true)); | |||
} | |||
@Test | |||
public void prepareRubyRailsRootDirectory() throws Exception { | |||
ServerFileSystem fileSystem = mock(ServerFileSystem.class); | |||
File tempDir = this.temp.getRoot(); | |||
when(fileSystem.getTempDir()).thenReturn(tempDir); | |||
File dir = new ApplicationDeployer(fileSystem, new RubyRailsApp[]{new FakeRubyRailsApp()}).prepareRubyRailsRootDirectory(); | |||
assertThat(dir.isDirectory(), is(true)); | |||
assertThat(dir.exists(), is(true)); | |||
assertThat(dir.getCanonicalPath(), is(new File(tempDir, "ror").getCanonicalPath())); | |||
} | |||
static class FakeRubyRailsApp extends RubyRailsApp { | |||
@Override | |||
public String getKey() { | |||
return "fake"; | |||
} | |||
@Override | |||
public String getPath() { | |||
return "/org/sonar/server/startup/ApplicationDeployerTest/FakeRubyRailsApp"; | |||
} | |||
} | |||
} |
@@ -0,0 +1,132 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.server.startup; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Predicate; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.FilenameUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.hamcrest.core.Is; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
import javax.annotation.Nullable; | |||
import java.io.File; | |||
import java.net.URL; | |||
import java.net.URLClassLoader; | |||
import java.util.Collection; | |||
import static org.junit.Assert.assertThat; | |||
import static org.junit.matchers.JUnitMatchers.hasItems; | |||
public class ClassLoaderUtilsTest { | |||
private ClassLoader classLoader; | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@Before | |||
public void prepareClassLoader() { | |||
// This JAR file has the three following files : | |||
// org/sonar/sqale/app/copyright.txt | |||
// org/sonar/sqale/app/README.md | |||
// org/sonar/other/other.txt | |||
URL jarUrl = getClass().getResource("/org/sonar/server/startup/ClassLoaderUtilsTest/ClassLoaderUtilsTest.jar"); | |||
classLoader = new URLClassLoader(new URL[]{jarUrl}, /* no parent classloader */null); | |||
} | |||
@Test | |||
public void listResources_unknown_root() { | |||
Collection<String> strings = ClassLoaderUtils.listResources(classLoader, "unknown/directory"); | |||
assertThat(strings.size(), Is.is(0)); | |||
} | |||
@Test | |||
public void listResources_all() { | |||
Collection<String> strings = ClassLoaderUtils.listResources(classLoader, "org/sonar/sqale"); | |||
assertThat(strings, hasItems( | |||
"org/sonar/sqale/", | |||
"org/sonar/sqale/app/", | |||
"org/sonar/sqale/app/copyright.txt", | |||
"org/sonar/sqale/app/README.md")); | |||
assertThat(strings.size(), Is.is(4)); | |||
} | |||
@Test | |||
public void listResources_root_path_starts_with_slash() { | |||
Collection<String> strings = ClassLoaderUtils.listResources(classLoader, "/org/sonar/sqale"); | |||
assertThat(strings, hasItems( | |||
"org/sonar/sqale/", | |||
"org/sonar/sqale/app/", | |||
"org/sonar/sqale/app/copyright.txt", | |||
"org/sonar/sqale/app/README.md")); | |||
assertThat(strings.size(), Is.is(4)); | |||
} | |||
@Test | |||
public void listResources_use_predicate() { | |||
Collection<String> strings = ClassLoaderUtils.listResources(classLoader, "org/sonar/sqale", new Predicate<String>() { | |||
@Override | |||
public boolean apply(@Nullable String s) { | |||
return StringUtils.endsWith(s, "md"); | |||
} | |||
}); | |||
assertThat(strings.size(), Is.is(1)); | |||
assertThat(strings, hasItems("org/sonar/sqale/app/README.md")); | |||
} | |||
@Test | |||
public void listFiles() { | |||
Collection<String> strings = ClassLoaderUtils.listFiles(classLoader, "org/sonar/sqale"); | |||
assertThat(strings, hasItems( | |||
"org/sonar/sqale/app/copyright.txt", | |||
"org/sonar/sqale/app/README.md")); | |||
assertThat(strings.size(), Is.is(2)); | |||
} | |||
@Test | |||
public void copyRubyRailsApp() { | |||
File toDir = temp.newFolder("dest"); | |||
ClassLoaderUtils.copyResources(classLoader, "org/sonar/sqale", toDir); | |||
assertThat(FileUtils.listFiles(toDir, null, true).size(), Is.is(2)); | |||
assertThat(new File(toDir, "org/sonar/sqale/app/copyright.txt").exists(), Is.is(true)); | |||
assertThat(new File(toDir, "org/sonar/sqale/app/README.md").exists(), Is.is(true)); | |||
} | |||
@Test | |||
public void copyRubyRailsApp_relocate_files() { | |||
File toDir = temp.newFolder("dest"); | |||
ClassLoaderUtils.copyResources(classLoader, "org/sonar/sqale", toDir, new Function<String, String>() { | |||
@Override | |||
public String apply(@Nullable String path) { | |||
return "foo/" + FilenameUtils.getName(path); | |||
} | |||
}); | |||
assertThat(FileUtils.listFiles(toDir, null, true).size(), Is.is(2)); | |||
assertThat(new File(toDir, "foo/copyright.txt").exists(), Is.is(true)); | |||
assertThat(new File(toDir, "foo/README.md").exists(), Is.is(true)); | |||
} | |||
} |