From 3e1a2e8a3e097c09525260e19d75eb68ce3c0ce9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Tue, 28 Apr 2015 15:31:07 +0200 Subject: [PATCH] SONAR-6366 split ruby upgradeAndStart into three Java steps modified ruby scripts used by RubyBridge to define and instance a class instead of only define a method alone because mapping such script to a Java interface works only for the first script (at least in unit tests) split upgrade_and_start from Ruby into two seperate Ruby tasks (trigger ActiveRecord migration on one side and web route (re)creation on the other) and a pure Java task to restart the container --- .../migrations/PlatformDatabaseMigration.java | 54 +++++++++++++++---- .../ruby/CallDatabaseVersionUpgrade.java | 32 +++++++++++ .../server/ruby/CallLoadJavaWebServices.java | 31 +++++++++++ .../sonar/server/ruby/PlatformRubyBridge.java | 44 ++++++++------- .../org/sonar/server/ruby/RubyBridge.java | 7 +++ .../sonar/server/ruby/RubyRailsRoutes.java | 28 ++++++++++ .../ruby/call_databaseversion_upgrade.rb | 12 +++++ .../ruby/call_load_java_web_services.rb | 12 +++++ .../server/ruby/call_upgrade_and_start.rb | 8 --- ...formDatabaseMigrationAsynchronousTest.java | 24 +++------ ...DatabaseMigrationConcurrentAccessTest.java | 7 ++- .../PlatformDatabaseMigrationTest.java | 44 ++++++++------- .../server/ruby/PlatformRubyBridgeTest.java | 23 ++++++-- .../org/sonar/server/ruby/database_version.rb | 6 ++- .../webapp/WEB-INF/lib/database_version.rb | 4 ++ 15 files changed, 254 insertions(+), 82 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/ruby/CallDatabaseVersionUpgrade.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/ruby/CallLoadJavaWebServices.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/ruby/RubyRailsRoutes.java create mode 100644 server/sonar-server/src/main/resources/org/sonar/server/ruby/call_databaseversion_upgrade.rb create mode 100644 server/sonar-server/src/main/resources/org/sonar/server/ruby/call_load_java_web_services.rb delete mode 100644 server/sonar-server/src/main/resources/org/sonar/server/ruby/call_upgrade_and_start.rb diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/PlatformDatabaseMigration.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/PlatformDatabaseMigration.java index f7fc0ad2060..a983979c124 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/PlatformDatabaseMigration.java +++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/PlatformDatabaseMigration.java @@ -19,16 +19,19 @@ */ package org.sonar.server.db.migrations; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.server.ruby.RubyBridge; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +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.platform.Platform; +import org.sonar.server.ruby.RubyBridge; + /** * Handles concurrency to make sure only one DB migration can run at a time. */ @@ -41,6 +44,7 @@ public class PlatformDatabaseMigration implements DatabaseMigration { * ExecutorService implements threads management. */ private final PlatformDatabaseMigrationExecutorService executorService; + private final Platform platform; /** * This lock implements thread safety from concurrent calls of method {@link #startIt()} */ @@ -60,9 +64,10 @@ public class PlatformDatabaseMigration implements DatabaseMigration { @Nullable private Throwable failureError; - public PlatformDatabaseMigration(RubyBridge rubyBridge, PlatformDatabaseMigrationExecutorService executorService) { + public PlatformDatabaseMigration(RubyBridge rubyBridge, PlatformDatabaseMigrationExecutorService executorService, Platform platform) { this.rubyBridge = rubyBridge; this.executorService = executorService; + this.platform = platform; } @Override @@ -96,19 +101,46 @@ public class PlatformDatabaseMigration implements DatabaseMigration { status = Status.RUNNING; startDate = new Date(); failureError = null; + Profiler profiler = Profiler.create(LOGGER); try { - LOGGER.info("Starting DB Migration at {}", startDate); - rubyBridge.databaseMigration().trigger(); - LOGGER.info("DB Migration ended successfully at {}", new Date()); + profiler.startInfo("Starting DB Migration"); + upgradeDb(); + restartContainer(); + recreateWebRoutes(); status = Status.SUCCEEDED; + profiler.stopInfo("DB Migration ended successfully"); } catch (Throwable t) { - LOGGER.error("DB Migration failed and ended at " + startDate + " with an exception", t); + profiler.stopInfo("DB migration failed"); + LOGGER.error( + "DB Migration or container restart failed. Process ended with an exception", t + ); status = Status.FAILED; failureError = t; } finally { running.getAndSet(false); } } + + private void upgradeDb() { + Profiler profiler = Profiler.createIfTrace(LOGGER); + profiler.startTrace("Starting DB Migration"); + rubyBridge.databaseMigration().trigger(); + profiler.stopTrace("DB Migration ended"); + } + + private void restartContainer() { + Profiler profiler = Profiler.createIfTrace(LOGGER); + profiler.startTrace("Restarting container"); + platform.doStart(); + profiler.stopTrace("Container restarted successfully"); + } + + private void recreateWebRoutes() { + Profiler profiler = Profiler.createIfTrace(LOGGER); + profiler.startTrace("Recreating web routes"); + rubyBridge.railsRoutes().recreate(); + profiler.startTrace("Routes recreated successfully"); + } }); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ruby/CallDatabaseVersionUpgrade.java b/server/sonar-server/src/main/java/org/sonar/server/ruby/CallDatabaseVersionUpgrade.java new file mode 100644 index 00000000000..1212291ce5e --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ruby/CallDatabaseVersionUpgrade.java @@ -0,0 +1,32 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.ruby; + +/** + * Interface which must be top-level public class to be used by the Ruby engine but that hides name of the Ruby method + * in the Ruby script from the rest of the platform (only {@link RubyDatabaseMigration} is known to the platform). + */ +public interface CallDatabaseVersionUpgrade { + + /** + * Java method that calls the upgrade_and_start method defined in the {@code call_databaseversion_upgrade.rb} script. + */ + void callUpgrade(); +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ruby/CallLoadJavaWebServices.java b/server/sonar-server/src/main/java/org/sonar/server/ruby/CallLoadJavaWebServices.java new file mode 100644 index 00000000000..1b5fbe2b802 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ruby/CallLoadJavaWebServices.java @@ -0,0 +1,31 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.ruby; + +/** + * Interface which must be a top-level public class to be used by the Ruby engine but that hides name of the Ruby + * method in the Ruby script from the rest of the platform (only {@link RubyRailsRoutes} is known to the platform). + */ +public interface CallLoadJavaWebServices { + /** + * Java method that calls the call_upgrade_and_start method defined in the {@code call_load_java_web_services.rb} script. + */ + void callLoadJavaWebServices(); +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ruby/PlatformRubyBridge.java b/server/sonar-server/src/main/java/org/sonar/server/ruby/PlatformRubyBridge.java index 9c970319148..3ac71e4f013 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ruby/PlatformRubyBridge.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ruby/PlatformRubyBridge.java @@ -19,6 +19,9 @@ */ package org.sonar.server.ruby; +import java.io.IOException; +import java.io.InputStream; +import javax.annotation.Nullable; import org.jruby.Ruby; import org.jruby.RubyNil; import org.jruby.RubyRuntimeAdapter; @@ -27,11 +30,9 @@ import org.jruby.javasupport.JavaEmbedUtils; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; -import java.io.IOException; -import java.io.InputStream; - public class PlatformRubyBridge implements RubyBridge { - private static final String CALL_UPGRADE_AND_START_RB_FILENAME = "call_upgrade_and_start.rb"; + private static final String CALL_UPGRADE_AND_START_RB_FILENAME = "call_databaseversion_upgrade.rb"; + private static final String CALL_LOAD_JAVA_WEB_SERVICES_RB_FILENAME = "call_load_java_web_services.rb"; private final RackBridge rackBridge; private final RubyRuntimeAdapter adapter = JavaEmbedUtils.newRuntimeAdapter(); @@ -42,14 +43,28 @@ public class PlatformRubyBridge implements RubyBridge { @Override public RubyDatabaseMigration databaseMigration() { - final CallUpgradeAndStart callUpgradeAndStart = parseMethodScriptToInterface( - CALL_UPGRADE_AND_START_RB_FILENAME, CallUpgradeAndStart.class + final CallDatabaseVersionUpgrade callDatabaseVersionUpgrade = parseMethodScriptToInterface( + CALL_UPGRADE_AND_START_RB_FILENAME, CallDatabaseVersionUpgrade.class ); return new RubyDatabaseMigration() { @Override public void trigger() { - callUpgradeAndStart.callUpgradeAndStart(); + callDatabaseVersionUpgrade.callUpgrade(); + } + }; + } + + @Override + public RubyRailsRoutes railsRoutes() { + final CallLoadJavaWebServices callLoadJavaWebServices = parseMethodScriptToInterface( + CALL_LOAD_JAVA_WEB_SERVICES_RB_FILENAME, CallLoadJavaWebServices.class + ); + + return new RubyRailsRoutes() { + @Override + public void recreate() { + callLoadJavaWebServices.callLoadJavaWebServices(); } }; } @@ -61,7 +76,7 @@ public class PlatformRubyBridge implements RubyBridge { private T parseMethodScriptToInterface(String fileName, Class clazz) { try (InputStream in = getClass().getResourceAsStream(fileName)) { Ruby rubyRuntime = rackBridge.getRubyRuntime(); - JavaEmbedUtils.EvalUnit evalUnit = adapter.parse(rubyRuntime, in, fileName, 0); + JavaEmbedUtils.EvalUnit evalUnit = JavaEmbedUtils.newRuntimeAdapter().parse(rubyRuntime, in, fileName, 0); IRubyObject rubyObject = evalUnit.run(); Object receiver = JavaEmbedUtils.rubyToJava(rubyObject); T wrapper = getInstance(rubyRuntime, receiver, clazz); @@ -75,7 +90,7 @@ public class PlatformRubyBridge implements RubyBridge { * Fork of method {@link org.jruby.embed.internal.EmbedRubyInterfaceAdapterImpl#getInstance(Object, Class)} */ @SuppressWarnings("unchecked") - public T getInstance(Ruby runtime, Object receiver, Class clazz) { + public T getInstance(Ruby runtime, @Nullable Object receiver, @Nullable Class clazz) { if (clazz == null || !clazz.isInterface()) { return null; } @@ -97,15 +112,4 @@ public class PlatformRubyBridge implements RubyBridge { } } - /** - * Interface which must be public to be used by the Ruby engine but that hides name of the Ruby method in the Ruby - * script from the rest of the platform (only {@link RubyDatabaseMigration} is known to the platform). - */ - public interface CallUpgradeAndStart { - - /** - * Java method that calls the upgrade_and_start method defined in the {@code call_upgrade_and_start.rb} script. - */ - void callUpgradeAndStart(); - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyBridge.java b/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyBridge.java index 1861263d516..36e893d770e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyBridge.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyBridge.java @@ -30,4 +30,11 @@ public interface RubyBridge { * @return a {@link RubyDatabaseMigration} */ RubyDatabaseMigration databaseMigration(); + + /** + * Returns a class that allows calling the (re)creation of web routes in Rails. + * + * @return a {@link RubyRailsRoutes} + */ + RubyRailsRoutes railsRoutes(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyRailsRoutes.java b/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyRailsRoutes.java new file mode 100644 index 00000000000..c5298cbfdf9 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ruby/RubyRailsRoutes.java @@ -0,0 +1,28 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.ruby; + +public interface RubyRailsRoutes { + /** + * Triggers the (re)creation of web route in Ruby On Rails. + * This is not thread safe! + */ + void recreate(); +} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_databaseversion_upgrade.rb b/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_databaseversion_upgrade.rb new file mode 100644 index 00000000000..b53c60d034a --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_databaseversion_upgrade.rb @@ -0,0 +1,12 @@ +# this script defines a method which calls the class method "upgrade" of the DatabaseVersion class defined +# in /server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb + +require 'database_version' + +class RbCallUpgrade + include Java::org.sonar.server.ruby.CallDatabaseVersionUpgrade + def call_upgrade + DatabaseVersion.upgrade + end +end +RbCallUpgrade.new \ No newline at end of file diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_load_java_web_services.rb b/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_load_java_web_services.rb new file mode 100644 index 00000000000..7623e055931 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_load_java_web_services.rb @@ -0,0 +1,12 @@ +# this script defines a method which calls the class method "load_java_web_services" of the DatabaseVersion class +# definedin /server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb + +require 'database_version' + +class RbCallLoadJavaWebServices + include Java::org.sonar.server.ruby.CallLoadJavaWebServices + def call_load_java_web_services + DatabaseVersion.load_java_web_services + end +end +RbCallLoadJavaWebServices.new \ No newline at end of file diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_upgrade_and_start.rb b/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_upgrade_and_start.rb deleted file mode 100644 index 5359ff11db7..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/ruby/call_upgrade_and_start.rb +++ /dev/null @@ -1,8 +0,0 @@ -# this script defines a method which calls the class method "upgrade_and_start" of the DatabaseVersion class defined -# in /server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb - -require 'database_version' - -def call_upgrade_and_start - DatabaseVersion.upgrade_and_start -end \ No newline at end of file diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationAsynchronousTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationAsynchronousTest.java index 1eb35d1873b..978174fd191 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationAsynchronousTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationAsynchronousTest.java @@ -20,15 +20,14 @@ package org.sonar.server.db.migrations; import com.google.common.base.Throwables; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.junit.After; -import org.junit.Before; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.sonar.server.platform.Platform; import org.sonar.server.ruby.RubyBridge; import org.sonar.server.ruby.RubyDatabaseMigration; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import static org.mockito.Mockito.mock; public class PlatformDatabaseMigrationAsynchronousTest { @@ -54,17 +53,10 @@ public class PlatformDatabaseMigrationAsynchronousTest { }); } }; - @Mock - private RubyDatabaseMigration rubyDatabaseMigration; - @Mock - private RubyBridge rubyBridge; - private PlatformDatabaseMigration underTest; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - underTest = new PlatformDatabaseMigration(rubyBridge, executorService); - } + private RubyDatabaseMigration rubyDatabaseMigration = mock(RubyDatabaseMigration.class); + private RubyBridge rubyBridge = mock(RubyBridge.class); + private Platform platform = mock(Platform.class); + private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform); @After public void tearDown() throws Exception { diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationConcurrentAccessTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationConcurrentAccessTest.java index d7d212b3c52..b4b9c767484 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationConcurrentAccessTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationConcurrentAccessTest.java @@ -27,8 +27,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.Test; +import org.sonar.server.platform.Platform; import org.sonar.server.ruby.RubyBridge; import org.sonar.server.ruby.RubyDatabaseMigration; +import org.sonar.server.ruby.RubyRailsRoutes; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -71,7 +73,9 @@ public class PlatformDatabaseMigrationConcurrentAccessTest { } }; private RubyBridge rubyBridge = mock(RubyBridge.class); - private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService); + private Platform platform = mock(Platform.class); + private RubyRailsRoutes railsRoutes = mock(RubyRailsRoutes.class); + private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform); @After public void tearDown() throws Exception { @@ -81,6 +85,7 @@ public class PlatformDatabaseMigrationConcurrentAccessTest { @Test public void two_concurrent_calls_to_startit_call_trigger_only_once() throws Exception { when(rubyBridge.databaseMigration()).thenReturn(rubyDatabaseMigration); + when(rubyBridge.railsRoutes()).thenReturn(railsRoutes); pool.submit(new CallStartit()); pool.submit(new CallStartit()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationTest.java index 7000c36f841..2d98d836989 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/PlatformDatabaseMigrationTest.java @@ -19,26 +19,26 @@ */ package org.sonar.server.db.migrations; -import org.junit.Before; +import java.util.Date; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.InOrder; +import org.sonar.server.platform.Platform; import org.sonar.server.ruby.RubyBridge; import org.sonar.server.ruby.RubyDatabaseMigration; - -import java.util.Date; +import org.sonar.server.ruby.RubyRailsRoutes; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Unit test for PlatformDatabaseMigration which does not test any of its concurrency management and asynchronous execution code. */ public class PlatformDatabaseMigrationTest { - private static final Throwable AN_ERROR = new RuntimeException(); + private static final Throwable AN_ERROR = new RuntimeException("runtime exception created on purpose"); /** * Implementation of execute runs Runnable synchronously. @@ -49,17 +49,13 @@ public class PlatformDatabaseMigrationTest { command.run(); } }; - @Mock - private RubyDatabaseMigration rubyDatabaseMigration; - @Mock - private RubyBridge rubyBridge; - private PlatformDatabaseMigration underTest; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - underTest = new PlatformDatabaseMigration(rubyBridge, executorService); - } + private RubyBridge rubyBridge = mock(RubyBridge.class); + private RubyDatabaseMigration rubyDatabaseMigration = mock(RubyDatabaseMigration.class); + private RubyRailsRoutes rubyRailsRoutes = mock(RubyRailsRoutes.class); + private Platform platform = mock(Platform.class); + private InOrder inOrder = inOrder(rubyDatabaseMigration, rubyBridge, rubyRailsRoutes, platform); + + private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform); @Test public void status_is_NONE_when_component_is_created() throws Exception { @@ -79,16 +75,22 @@ public class PlatformDatabaseMigrationTest { @Test public void startit_calls_databasemigration_trigger_in_a_separate_thread() throws Exception { when(rubyBridge.databaseMigration()).thenReturn(rubyDatabaseMigration); + when(rubyBridge.railsRoutes()).thenReturn(rubyRailsRoutes); underTest.startIt(); - verify(rubyBridge).databaseMigration(); - verify(rubyDatabaseMigration).trigger(); + inOrder.verify(rubyBridge).databaseMigration(); + inOrder.verify(rubyDatabaseMigration).trigger(); + inOrder.verify(platform).doStart(); + inOrder.verify(rubyBridge).railsRoutes(); + inOrder.verify(rubyRailsRoutes).recreate(); + inOrder.verifyNoMoreInteractions(); } @Test public void status_is_SUCCEEDED_and_failure_is_null_when_trigger_runs_without_an_exception() throws Exception { when(rubyBridge.databaseMigration()).thenReturn(rubyDatabaseMigration); + when(rubyBridge.railsRoutes()).thenReturn(rubyRailsRoutes); underTest.startIt(); @@ -131,10 +133,12 @@ public class PlatformDatabaseMigrationTest { private void mockTriggerThrowsError() { when(rubyBridge.databaseMigration()).thenReturn(rubyDatabaseMigration); doThrow(AN_ERROR).when(rubyDatabaseMigration).trigger(); + when(rubyBridge.railsRoutes()).thenReturn(rubyRailsRoutes); } private void mockTriggerDoesNothing() { when(rubyBridge.databaseMigration()).thenReturn(rubyDatabaseMigration); doNothing().when(rubyDatabaseMigration).trigger(); + when(rubyBridge.railsRoutes()).thenReturn(rubyRailsRoutes); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/ruby/PlatformRubyBridgeTest.java b/server/sonar-server/src/test/java/org/sonar/server/ruby/PlatformRubyBridgeTest.java index 527f48fc104..56729daec6f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ruby/PlatformRubyBridgeTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ruby/PlatformRubyBridgeTest.java @@ -20,16 +20,15 @@ package org.sonar.server.ruby; import com.google.common.collect.ImmutableList; +import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; import org.jruby.embed.LocalContextScope; import org.jruby.embed.ScriptingContainer; import org.jruby.exceptions.RaiseException; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.net.URISyntaxException; -import java.net.URL; - import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -51,7 +50,7 @@ public class PlatformRubyBridgeTest { */ private static ScriptingContainer setupScriptingContainer() { try { - ScriptingContainer container = new ScriptingContainer(LocalContextScope.CONCURRENT); + ScriptingContainer container = new ScriptingContainer(LocalContextScope.THREADSAFE); URL resource = PlatformRubyBridge.class.getResource("database_version.rb"); String dirPath = new File(resource.toURI()).getParentFile().getPath(); container.setLoadPaths(ImmutableList.of(dirPath)); @@ -75,4 +74,18 @@ public class PlatformRubyBridgeTest { } } + /** + * unit test only makes sure the wrapping and method forwarding provided by JRuby works so building the + * RubyRailsRoutes object and calling its trigger method is enough as it would otherwise raise an exception + */ + @Test + public void testRailsRoutes() { + try { + underTest.railsRoutes().recreate(); + } catch (RaiseException e) { + e.printStackTrace(); + throw new RuntimeException("Loading error with container loadPath " + container.getLoadPaths(), e); + } + } + } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/ruby/database_version.rb b/server/sonar-server/src/test/resources/org/sonar/server/ruby/database_version.rb index e1cc2ca163d..46797b911dc 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/ruby/database_version.rb +++ b/server/sonar-server/src/test/resources/org/sonar/server/ruby/database_version.rb @@ -3,7 +3,11 @@ # it would otherwise raise an exception class DatabaseVersion - def self.upgrade_and_start + def self.upgrade + + end + + def self.load_java_web_services end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb b/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb index 9473dfe3356..b1e7da54f35 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb @@ -58,6 +58,10 @@ class DatabaseVersion $uptodate end + def self.upgrade + ActiveRecord::Migrator.migrate(migrations_path) + end + def self.upgrade_and_start ActiveRecord::Migrator.migrate(migrations_path) Java::OrgSonarServerPlatform::Platform.getInstance().doStart() -- 2.39.5