]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6732 disable Compute Engine in WebServer
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 14 Mar 2016 15:51:28 +0000 (16:51 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 21 Mar 2016 15:44:05 +0000 (16:44 +0100)
179 files changed:
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-server/src/main/java/org/sonar/ce/CeModule.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/log/CeFileAppenderFactory.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/log/CeLogAcceptFilter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/log/CeLogDenyFilter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/log/CeLogging.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/log/LogFileRef.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/log/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/monitoring/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/property/CePropertyDefinitions.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/property/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueue.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueListener.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/CeTask.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/CeTaskResult.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/CeTaskSubmit.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/report/ReportFiles.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/report/ReportSubmitter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/queue/report/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/CeTaskProcessor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/ReportTaskProcessorDeclaration.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/app/ServerProcessLogging.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/CancelAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/CancelAllAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWs.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/IsQueueEmptyWs.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/LogsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/SubmitAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskTypesAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeModule.java
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainer.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactory.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactoryImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportProcessingModule.java
server/sonar-server/src/main/java/org/sonar/server/computation/log/CeFileAppenderFactory.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogAcceptFilter.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogDenyFilter.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogging.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/log/LogFileRef.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/log/package-info.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatus.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatusImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitor.java
server/sonar-server/src/main/java/org/sonar/server/computation/property/CePropertyDefinitions.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/property/package-info.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueue.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueCleaner.java
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueImpl.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueInitializer.java
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueListener.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueModule.java
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTask.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTaskResult.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTaskSubmit.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueue.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/PurgeCeActivities.java
server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/CleanReportQueueListener.java
server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportSubmitter.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/step/ExtractReportStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/LoadReportAnalysisMetadataHolderStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/PublishTaskResultStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeTaskProcessor.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeTaskProcessorRepository.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeTaskProcessorRepositoryImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeWorkerCallable.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeWorkerCallableImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/MutableTaskResultHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/MutableTaskResultHolderImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/TaskResultHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/report/ReportTaskProcessor.java
server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CancelAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CancelAllAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWs.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWs.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/LogsAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskTypesAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/package-info.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java
server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentNavigationAction.java
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity-example.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/component-example.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/is_queue_empty-example.txt [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/logs-example.log [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/submit-example.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/task-example.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/ce/ws/task_types-example.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/is_queue_empty-example.txt [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/logs-example.log [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/submit-example.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task_types-example.json [deleted file]
server/sonar-server/src/test/java/org/sonar/ce/log/CeFileAppenderFactoryTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/log/CeLogAcceptFilterTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/log/CeLogDenyFilterTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/log/CeLoggingTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/log/LogFileRefTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/property/CePropertyDefinitionsTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/queue/CeTaskTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/queue/report/ReportSubmitterTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/ce/taskprocessor/ReportTaskProcessorDeclarationTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/app/ServerProcessLoggingTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/CancelAllActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/LogsActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/SubmitActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskTypesActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/CePropertyDefinitionsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/PurgeCeActivitiesTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ReportFilesTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulatorTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/log/CeFileAppenderFactoryTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLogAcceptFilterTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLogDenyFilterTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLoggingTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/log/LogFileRefTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplConcurrentTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueCleanerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueImplTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueInitializerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeTaskTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/queue/report/CleanReportQueueListenerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/queue/report/ReportSubmitterTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ComputationStepsTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ExtractReportStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/LoadReportAnalysisMetadataHolderStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/taskprocessor/CeTaskProcessorRepositoryImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/taskprocessor/CeTaskProcessorRepositoryRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/taskprocessor/CeWorkerCallableImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/taskprocessor/MutableTaskResultHolderImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CancelActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CancelAllActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsModuleTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/LogsActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskTypesActionTest.java [deleted file]

index ad8abbfd0a9d1b6ac2d531a5e289c8c78f2b3569..4afc821568317a6d85fe10c6445302c1f4ac5c5c 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
 import org.sonar.api.utils.Durations;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.UriReader;
+import org.sonar.ce.property.CePropertyDefinitions;
 import org.sonar.core.component.DefaultResourceTypes;
 import org.sonar.core.config.CorePropertyDefinitions;
 import org.sonar.core.i18n.DefaultI18n;
@@ -65,7 +66,6 @@ import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentService;
 import org.sonar.server.computation.CeModule;
 import org.sonar.server.computation.container.ReportProcessingModule;
-import org.sonar.server.computation.property.CePropertyDefinitions;
 import org.sonar.server.computation.queue.CeQueueModule;
 import org.sonar.server.computation.queue.PurgeCeActivities;
 import org.sonar.server.computation.taskprocessor.CeTaskProcessorModule;
@@ -111,6 +111,7 @@ import org.sonar.server.plugins.InstalledPluginReferentialFactory;
 import org.sonar.server.plugins.ServerExtensionInstaller;
 import org.sonar.server.plugins.ServerPluginJarExploder;
 import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.properties.ProjectSettingsFactory;
 import org.sonar.server.qualityprofile.BuiltInProfiles;
 import org.sonar.server.qualityprofile.QProfileComparison;
 import org.sonar.server.qualityprofile.QProfileLookup;
@@ -554,6 +555,8 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
     CeTaskProcessorModule.class,
     // CeWsModule.class, no Web Service in CE
 
+    ProjectSettingsFactory.class,
+
     // UI
     // GlobalNavigationAction.class, no Web Service in CE
     // SettingsNavigationAction.class, no Web Service in CE
index fd255a25fe4134343a751c84e81a1c3d725363a7..44a2b815a9ef29d5ba5b59fc947ee323c274d3d0 100644 (file)
@@ -79,8 +79,8 @@ public class ComputeEngineContainerImplTest {
         + 59 // content of MigrationStepModule
         + 10 // level 2
         + 5 // level 3
-        + 76 // level 4
-        + 6 // content of CeModule
+        + 77 // level 4
+        + 5 // content of CeModule
         + 7 // content of CeQueueModule
         + 4 // content of ReportProcessingModule
         + 4 // content of CeTaskProcessorModule
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/CeModule.java b/server/sonar-server/src/main/java/org/sonar/ce/CeModule.java
new file mode 100644 (file)
index 0000000..f4f05b1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce;
+
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.monitoring.DummyCEQueueStatusImpl;
+import org.sonar.ce.queue.CeQueueImpl;
+import org.sonar.ce.queue.report.ReportFiles;
+import org.sonar.ce.queue.report.ReportSubmitter;
+import org.sonar.ce.taskprocessor.ReportTaskProcessorDeclaration;
+import org.sonar.core.platform.Module;
+
+public class CeModule extends Module {
+  @Override
+  protected void configureModule() {
+    add(CeLogging.class,
+
+      // queue monitoring
+      DummyCEQueueStatusImpl.class,
+
+      // Queue
+      CeQueueImpl.class,
+      ReportSubmitter.class,
+      ReportFiles.class,
+
+      // Core tasks processors
+      ReportTaskProcessorDeclaration.class);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/log/CeFileAppenderFactory.java b/server/sonar-server/src/main/java/org/sonar/ce/log/CeFileAppenderFactory.java
new file mode 100644 (file)
index 0000000..f07289f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.FileAppender;
+import ch.qos.logback.core.sift.AppenderFactory;
+import com.google.common.annotations.VisibleForTesting;
+import java.io.File;
+import org.sonar.ce.queue.CeTask;
+
+import static java.lang.String.format;
+
+/**
+ * Creates a Logback appender for a Compute Engine task. See
+ * http://logback.qos.ch/manual/loggingSeparation.html
+ */
+public class CeFileAppenderFactory<E> implements AppenderFactory<E> {
+
+  private static final String ENCODER_PATTERN = "%d{yyyy.MM.dd HH:mm:ss} %-5level [%logger{20}] %msg%n";
+
+  private final File ceLogsDir;
+
+  @VisibleForTesting
+  CeFileAppenderFactory(File ceLogsDir) {
+    this.ceLogsDir = ceLogsDir;
+  }
+
+  /**
+   * @param context
+   * @param discriminatingValue path of log file relative to the directory data/ce/logs
+   * @see CeLogging#initForTask(CeTask)
+   */
+  @Override
+  public FileAppender<E> buildAppender(Context context, String discriminatingValue) {
+    PatternLayoutEncoder consoleEncoder = new PatternLayoutEncoder();
+    consoleEncoder.setContext(context);
+    consoleEncoder.setPattern(ENCODER_PATTERN);
+    consoleEncoder.start();
+    FileAppender appender = new FileAppender<>();
+    appender.setContext(context);
+    appender.setEncoder(consoleEncoder);
+    appender.setName(format("ce-%s", discriminatingValue));
+    appender.setFile(new File(ceLogsDir, discriminatingValue).getAbsolutePath());
+    appender.start();
+    return appender;
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/log/CeLogAcceptFilter.java b/server/sonar-server/src/main/java/org/sonar/ce/log/CeLogAcceptFilter.java
new file mode 100644 (file)
index 0000000..892eea2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+import org.slf4j.MDC;
+
+/**
+ * Keeps only the Compute Engine logs.
+ */
+public class CeLogAcceptFilter<E> extends Filter<E> {
+
+  @Override
+  public FilterReply decide(E o) {
+    return MDC.get(CeLogging.MDC_LOG_PATH) == null ? FilterReply.DENY : FilterReply.ACCEPT;
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/log/CeLogDenyFilter.java b/server/sonar-server/src/main/java/org/sonar/ce/log/CeLogDenyFilter.java
new file mode 100644 (file)
index 0000000..ea02d4d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+import org.slf4j.MDC;
+
+/**
+ * Filters out the Compute Engine logs.
+ */
+public class CeLogDenyFilter<E> extends Filter<E> {
+
+  @Override
+  public FilterReply decide(E o) {
+    return MDC.get(CeLogging.MDC_LOG_PATH) == null ? FilterReply.ACCEPT : FilterReply.DENY;
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/log/CeLogging.java b/server/sonar-server/src/main/java/org/sonar/ce/log/CeLogging.java
new file mode 100644 (file)
index 0000000..80264dc
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
+import ch.qos.logback.classic.sift.SiftingAppender;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.sift.AppenderTracker;
+import ch.qos.logback.core.util.Duration;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.comparator.LastModifiedFileComparator;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.log4j.MDC;
+import org.sonar.api.config.Settings;
+import org.sonar.process.LogbackHelper;
+import org.sonar.process.ProcessProperties;
+import org.sonar.process.Props;
+import org.sonar.ce.queue.CeTask;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.FluentIterable.from;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.lang.String.format;
+
+/**
+ * Manages the logs written by Compute Engine:
+ * <ul>
+ *   <li>access to existing logs</li>
+ *   <li>configure logback when CE worker starts and stops processing a task</li>
+ * </ul>
+ */
+public class CeLogging {
+
+  private static final long TIMEOUT_2_MINUTES = 1000 * 60 * 2L;
+  private static final String CE_APPENDER_NAME = "ce";
+  // using 0L as timestamp when retrieving appender to stop it will make it instantly eligible for removal
+  private static final long STOPPING_TRACKER_TIMESTAMP = 0L;
+
+  @VisibleForTesting
+  static final String MDC_LOG_PATH = "ceLogPath";
+  public static final String MAX_LOGS_PROPERTY = "sonar.ce.maxLogsPerTask";
+
+  private final LogbackHelper helper = new LogbackHelper();
+  private final File logsDir;
+  private final Settings settings;
+
+  public CeLogging(Settings settings) {
+    String dataDir = settings.getString(ProcessProperties.PATH_DATA);
+    checkArgument(dataDir != null, "Property %s is not set", ProcessProperties.PATH_DATA);
+    this.logsDir = logsDirFromDataDir(new File(dataDir));
+    this.settings = settings;
+  }
+
+  /**
+   * Gets the log file of a given task. It may not exist if it
+   * was purged or if the task does not exist.
+   */
+  public Optional<File> getFile(LogFileRef ref) {
+    File logFile = new File(logsDir, ref.getRelativePath());
+    if (logFile.exists()) {
+      return Optional.of(logFile);
+    }
+    return Optional.absent();
+  }
+
+  public void deleteIfExists(LogFileRef ref) {
+    File logFile = new File(logsDir, ref.getRelativePath());
+    logFile.delete();
+  }
+
+  /**
+   * Initialize logging of a Compute Engine task. Must be called
+   * before first writing of log.
+   * <p>After this method is executed, then Compute Engine logs are
+   * written to a dedicated appender and are removed from sonar.log.</p>
+   */
+  public void initForTask(CeTask task) {
+    LogFileRef ref = LogFileRef.from(task);
+    // Logback SiftingAppender requires to use a String, so
+    // the path is put but not the object LogFileRef
+    MDC.put(MDC_LOG_PATH, ref.getRelativePath());
+  }
+
+  /**
+   * Clean-up the logging of a task. Must be called after the last writing
+   * of log.
+   * <p>After this method is executed, then Compute Engine logs are
+   * written to sonar.log only.</p>
+   */
+  public void clearForTask() {
+    String relativePath = (String) MDC.get(MDC_LOG_PATH);
+    MDC.remove(MDC_LOG_PATH);
+
+    if (relativePath != null) {
+      stopAppender(relativePath);
+      purgeDir(new File(logsDir, relativePath).getParentFile());
+    }
+  }
+
+  private void stopAppender(String relativePath) {
+    Appender<ILoggingEvent> appender = helper.getRootContext().getLogger(Logger.ROOT_LOGGER_NAME).getAppender(CE_APPENDER_NAME);
+    checkState(appender instanceof SiftingAppender, "Appender with name %s is null or not a SiftingAppender", CE_APPENDER_NAME);
+    AppenderTracker<ILoggingEvent> ceAppender = ((SiftingAppender) appender).getAppenderTracker();
+    ceAppender.getOrCreate(relativePath, STOPPING_TRACKER_TIMESTAMP).stop();
+  }
+
+  @VisibleForTesting
+  void purgeDir(File dir) {
+    if (dir.exists()) {
+      int maxLogs = settings.getInt(MAX_LOGS_PROPERTY);
+      if (maxLogs < 0) {
+        throw new IllegalArgumentException(format("Property %s must be positive. Got: %d", MAX_LOGS_PROPERTY, maxLogs));
+      }
+      List<File> logFiles = newArrayList(FileUtils.listFiles(dir, FileFilterUtils.fileFileFilter(), FileFilterUtils.falseFileFilter()));
+      if (logFiles.size() > maxLogs) {
+        Collections.sort(logFiles, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
+        for (File logFile : from(logFiles).limit(logFiles.size() - maxLogs)) {
+          logFile.delete();
+        }
+      }
+    }
+  }
+
+  /**
+   * Directory which contains all the compute engine logs.
+   * Log files must be persistent among server restarts and upgrades, so they are
+   * stored into directory data/ but not into directories logs/ or temp/.
+   * @return the non-null directory. It may not exist at startup.
+   */
+  static File logsDirFromDataDir(File dataDir) {
+    return new File(dataDir, "ce/logs");
+  }
+
+  /**
+   * Create Logback configuration for enabling sift appender.
+   * A new log file is created for each task. It is based on MDC as long
+   * as Compute Engine is not executed in its
+   * own process but in the same process as web server.
+   */
+  public static Appender<ILoggingEvent> createAppenderConfiguration(LoggerContext ctx, Props processProps) {
+    File dataDir = new File(processProps.nonNullValue(ProcessProperties.PATH_DATA));
+    File logsDir = logsDirFromDataDir(dataDir);
+    return createAppenderConfiguration(ctx, logsDir);
+  }
+
+  static SiftingAppender createAppenderConfiguration(LoggerContext ctx, File logsDir) {
+    SiftingAppender siftingAppender = new SiftingAppender();
+    siftingAppender.addFilter(new CeLogAcceptFilter<ILoggingEvent>());
+    MDCBasedDiscriminator mdcDiscriminator = new MDCBasedDiscriminator();
+    mdcDiscriminator.setContext(ctx);
+    mdcDiscriminator.setKey(MDC_LOG_PATH);
+    mdcDiscriminator.setDefaultValue("error");
+    mdcDiscriminator.start();
+    siftingAppender.setContext(ctx);
+    siftingAppender.setDiscriminator(mdcDiscriminator);
+    siftingAppender.setAppenderFactory(new CeFileAppenderFactory(logsDir));
+    siftingAppender.setName(CE_APPENDER_NAME);
+    siftingAppender.setTimeout(new Duration(TIMEOUT_2_MINUTES));
+    siftingAppender.start();
+    return siftingAppender;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/log/LogFileRef.java b/server/sonar-server/src/main/java/org/sonar/ce/log/LogFileRef.java
new file mode 100644 (file)
index 0000000..6692c70
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.regex.Pattern;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.ce.queue.CeTask;
+
+import static java.lang.String.format;
+
+public class LogFileRef {
+
+  // restricted white-list for now
+  private static final Pattern FILENAME_PATTERN = Pattern.compile("^[\\w\\-]*$");
+  private final String taskType;
+  private final String taskUuid;
+
+  @CheckForNull
+  private final String componentUuid;
+
+  public LogFileRef(String taskType, String taskUuid, @Nullable String componentUuid) {
+    this.taskType = requireValidFilename(taskType);
+    this.taskUuid = requireValidFilename(taskUuid);
+    this.componentUuid = requireValidFilename(componentUuid);
+  }
+
+  @VisibleForTesting
+  @CheckForNull
+  static String requireValidFilename(@Nullable String s) {
+    if (s != null && !FILENAME_PATTERN.matcher(s).matches()) {
+      throw new IllegalArgumentException(String.format("'%s' is not a valid filename for Compute Engine logs", s));
+    }
+    return s;
+  }
+
+  /**
+   * Path relative to the CE logs directory
+   */
+  public String getRelativePath() {
+    if (componentUuid == null) {
+      return format("%s/%s.log", taskType, taskUuid);
+    }
+    return format("%s/%s/%s.log", taskType, componentUuid, taskUuid);
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    LogFileRef that = (LogFileRef) o;
+    if (!taskType.equals(that.taskType)) {
+      return false;
+    }
+    if (!taskUuid.equals(that.taskUuid)) {
+      return false;
+    }
+    return componentUuid == null ? (that.componentUuid == null) : componentUuid.equals(that.componentUuid);
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = taskType.hashCode();
+    result = 31 * result + taskUuid.hashCode();
+    result = 31 * result + (componentUuid != null ? componentUuid.hashCode() : 0);
+    return result;
+  }
+
+  public static LogFileRef from(CeActivityDto dto) {
+    return new LogFileRef(dto.getTaskType(), dto.getUuid(), dto.getComponentUuid());
+  }
+
+  public static LogFileRef from(CeQueueDto dto) {
+    return new LogFileRef(dto.getTaskType(), dto.getUuid(), dto.getComponentUuid());
+  }
+
+  public static LogFileRef from(CeTask task) {
+    return new LogFileRef(task.getType(), task.getUuid(), task.getComponentUuid());
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/log/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/log/package-info.java
new file mode 100644 (file)
index 0000000..fa5b1f7
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce.log;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java b/server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java
new file mode 100644 (file)
index 0000000..1ffac1e
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.monitoring;
+
+public interface CEQueueStatus {
+
+  /**
+   * Sets the count of reports waiting for processing at startup. This method can be called only once.
+   *
+   * @param initialPendingCount the count of reports, must be {@literal >=} 0
+   *
+   * @return the new count of batch reports waiting for processing (which is the same as the argument)
+   *
+   * @throws IllegalStateException if this method has already been called or is called after {@link #getPendingCount()}
+   * @throws IllegalArgumentException if the argument is {@literal <} 0
+   */
+  long initPendingCount(long initialPendingCount);
+
+  /**
+   * Adds 1 to the count of received batch reports and 1 to the count of batch reports waiting for processing.
+   * <p>
+   * Calling this method is equivalent to calling {@link #addReceived(long)} with {@code 1} as argument but will
+   * trigger no parameter check. So, it can be faster.
+   * </p>
+   *
+   * @return the new count of received batch reports
+   *
+   * @see #getReceivedCount()
+   * @see #getPendingCount()
+   *
+   * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
+   */
+  long addReceived();
+
+  /**
+   * Adds {@code numberOfReceived} to the count of received batch reports and {@code numberOfReceived} to the count of
+   * batch reports waiting for processing.
+   *
+   * @return the new count of received batch reports
+   *
+   * @see #getReceivedCount()
+   * @see #getPendingCount()
+   *
+   * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
+   * @throws IllegalArgumentException if {@code numberOfReceived} is less or equal to 0
+   */
+  long addReceived(long numberOfReceived);
+
+  /**
+   * Adds 1 to the count of batch reports under processing and removes 1 from the count of batch reports waiting for
+   * processing.
+   *
+   * @return the new count of batch reports under processing
+   *
+   * @see #getInProgressCount()
+   * @see #getPendingCount()
+   *
+   * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
+   */
+  long addInProgress();
+
+  /**
+   * Adds 1 to the count of batch reports which processing ended successfully and removes 1 from the count of batch
+   * reports under processing. Adds the specified time to the processing time counter.
+   *
+   * @param processingTime duration of processing in ms
+   *
+   * @return the new count of batch reports which processing ended successfully
+   *
+   * @see #getSuccessCount()
+   * @see #getInProgressCount()
+   *
+   * @throws IllegalArgumentException if processingTime is < 0
+   */
+  long addSuccess(long processingTime);
+
+  /**
+   * Adds 1 to the count of batch reports which processing ended with an error and removes 1 from the count of batch
+   * reports under processing. Adds the specified time to the processing time counter.
+   *
+   * @param processingTime duration of processing in ms
+   *
+   * @return the new count of batch reports which processing ended with an error
+   *
+   * @see #getErrorCount()
+   * @see #getInProgressCount()
+   *
+   * @throws IllegalArgumentException if processingTime is < 0
+   */
+  long addError(long processingTime);
+
+  /**
+   * Count of received batch reports since instance startup
+   */
+  long getReceivedCount();
+
+  /**
+   * Count of batch reports waiting for processing since startup, including reports received before instance startup.
+   */
+  long getPendingCount();
+
+  /**
+   * Count of batch reports under processing.
+   */
+  long getInProgressCount();
+
+  /**
+   * Count of batch reports which processing ended with an error since instance startup.
+   */
+  long getErrorCount();
+
+  /**
+   * Count of batch reports which processing ended successfully since instance startup.
+   */
+  long getSuccessCount();
+
+  /**
+   * Time spent processing batch reports since startup.
+   */
+  long getProcessingTime();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java b/server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java
new file mode 100644 (file)
index 0000000..9ed4fcc
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.monitoring;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * FIXME fix this dummy CEQueueStatus implementation, probably by removing its use from
+ */
+public class DummyCEQueueStatusImpl implements CEQueueStatus {
+  private final AtomicLong received = new AtomicLong(0);
+
+  @Override
+  public long initPendingCount(long initialPendingCount) {
+    return notImplemented();
+  }
+
+  @Override
+  public long addReceived() {
+    return received.incrementAndGet();
+  }
+
+  @Override
+  public long addReceived(long numberOfReceived) {
+    return received.addAndGet(numberOfReceived);
+  }
+
+  @Override
+  public long addInProgress() {
+    return notImplemented();
+  }
+
+  @Override
+  public long addSuccess(long processingTime) {
+    return notImplemented();
+  }
+
+  @Override
+  public long addError(long processingTime) {
+    return notImplemented();
+  }
+
+  @Override
+  public long getReceivedCount() {
+    return received.get();
+  }
+
+  @Override
+  public long getPendingCount() {
+    return notImplemented();
+  }
+
+  @Override
+  public long getInProgressCount() {
+    return notImplemented();
+  }
+
+  @Override
+  public long getErrorCount() {
+    return notImplemented();
+  }
+
+  @Override
+  public long getSuccessCount() {
+    return notImplemented();
+  }
+
+  @Override
+  public long getProcessingTime() {
+    return notImplemented();
+  }
+
+  private static long notImplemented() {
+    throw new UnsupportedOperationException("Not implemented!");
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/monitoring/package-info.java
new file mode 100644 (file)
index 0000000..08f19c0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce.monitoring;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/package-info.java
new file mode 100644 (file)
index 0000000..29fd81a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/property/CePropertyDefinitions.java b/server/sonar-server/src/main/java/org/sonar/ce/property/CePropertyDefinitions.java
new file mode 100644 (file)
index 0000000..9ad2dc1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.property;
+
+import java.util.List;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.ce.log.CeLogging;
+
+import static java.util.Arrays.asList;
+
+public class CePropertyDefinitions {
+  private CePropertyDefinitions() {
+    // only statics
+  }
+
+  public static List<PropertyDefinition> all() {
+    return asList(
+      PropertyDefinition.builder(CeLogging.MAX_LOGS_PROPERTY)
+        .name("Compute Engine Log Retention")
+        .description("Number of tasks to keep logs for a given project. Once the number of logs exceeds this limit, oldest logs are purged.")
+        .type(PropertyType.INTEGER)
+        .defaultValue("10")
+        .category(CoreProperties.CATEGORY_GENERAL)
+        .build());
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/property/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/property/package-info.java
new file mode 100644 (file)
index 0000000..58c7240
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce.property;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueue.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueue.java
new file mode 100644 (file)
index 0000000..fe8b10e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Queue of pending Compute Engine tasks. Both producer and consumer actions
+ * are implemented.
+ * <p>
+ *   This class is decoupled from the regular task type {@link org.sonar.db.ce.CeTaskTypes#REPORT}.
+ * </p>
+ */
+public interface CeQueue {
+  /**
+   * Build an instance of {@link CeTaskSubmit} required for {@link #submit(CeTaskSubmit)}. It allows
+   * to enforce that task ids are generated by the queue. It's used also for having access
+   * to the id before submitting the task to the queue.
+   */
+  CeTaskSubmit.Builder prepareSubmit();
+
+  /**
+   * Submits a task to the queue. The task is processed asynchronously.
+   * <p>
+   * This method is equivalent to calling {@code massSubmit(Collections.singletonList(submission))}.
+   * </p>
+   *
+   * @throws IllegalStateException If submits are paused (see {@link #isSubmitPaused()})
+   */
+  CeTask submit(CeTaskSubmit submission);
+
+  /**
+   * Submits multiple tasks to the queue at once. All tasks are processed asynchronously.
+   * <p>
+   * This method will perform significantly better that calling {@link #submit(CeTaskSubmit)} in a loop.
+   * </p>
+   *
+   * @throws IllegalStateException If submits are paused (see {@link #isSubmitPaused()})
+   */
+  List<CeTask> massSubmit(Collection<CeTaskSubmit> submissions);
+
+  /**
+   * Cancels a task in status {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}. An unchecked
+   * exception is thrown if the status is not {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}.
+   * The method does nothing and returns {@code false} if the task does not exist.
+   *
+   * @return true if the task exists and is successfully canceled.
+   */
+  boolean cancel(String taskUuid);
+
+  /**
+   * Removes all the tasks from the queue, except the tasks with status
+   * {@link org.sonar.db.ce.CeQueueDto.Status#IN_PROGRESS} are ignored. They are marked
+   * as {@link org.sonar.db.ce.CeActivityDto.Status#CANCELED} in past activity.
+   * This method can be called at runtime, even if workers are being executed.
+   *
+   * @return the number of canceled tasks
+   */
+  int cancelAll();
+
+  void pauseSubmit();
+
+  void resumeSubmit();
+
+  boolean isSubmitPaused();
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java
new file mode 100644 (file)
index 0000000..a6aff10
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ServerSide;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.ce.monitoring.CEQueueStatus;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.FluentIterable.from;
+import static org.sonar.db.component.ComponentDtoFunctions.toUuid;
+
+@ServerSide
+public class CeQueueImpl implements CeQueue {
+
+  private final DbClient dbClient;
+  private final UuidFactory uuidFactory;
+  private final CEQueueStatus queueStatus;
+  private final CeQueueListener[] listeners;
+
+  // state
+  private AtomicBoolean submitPaused = new AtomicBoolean(false);
+
+  /**
+   * Constructor in case there is no CeQueueListener
+   */
+  public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory, CEQueueStatus queueStatus) {
+    this(dbClient, uuidFactory, queueStatus, new CeQueueListener[]{});
+  }
+
+  public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory, CEQueueStatus queueStatus, CeQueueListener[] listeners) {
+    this.dbClient = dbClient;
+    this.uuidFactory = uuidFactory;
+    this.queueStatus = queueStatus;
+    this.listeners = listeners;
+  }
+
+  @Override
+  public CeTaskSubmit.Builder prepareSubmit() {
+    return new CeTaskSubmit.Builder(uuidFactory.create());
+  }
+
+  @Override
+  public CeTask submit(CeTaskSubmit submission) {
+    checkState(!submitPaused.get(), "Compute Engine does not currently accept new tasks");
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      CeQueueDto dto = new CeTaskSubmitToInsertedCeQueueDto(dbSession, dbClient).apply(submission);
+      CeTask task = loadTask(dbSession, dto);
+      dbSession.commit();
+      queueStatus.addReceived();
+      return task;
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  @Override
+  public List<CeTask> massSubmit(Collection<CeTaskSubmit> submissions) {
+    checkState(!submitPaused.get(), "Compute Engine does not currently accept new tasks");
+    if (submissions.isEmpty()) {
+      return Collections.emptyList();
+    }
+
+    DbSession dbSession = dbClient.openSession(true);
+    try {
+      List<CeQueueDto> ceQueueDtos = from(submissions)
+        .transform(new CeTaskSubmitToInsertedCeQueueDto(dbSession, dbClient))
+        .toList();
+      List<CeTask> tasks = loadTasks(dbSession, ceQueueDtos);
+      dbSession.commit();
+      queueStatus.addReceived(tasks.size());
+      return tasks;
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  protected CeTask loadTask(DbSession dbSession, CeQueueDto dto) {
+    if (dto.getComponentUuid() == null) {
+      return new CeQueueDtoToCeTask().apply(dto);
+    }
+    Optional<ComponentDto> componentDto = dbClient.componentDao().selectByUuid(dbSession, dto.getComponentUuid());
+    if (componentDto.isPresent()) {
+      return new CeQueueDtoToCeTask(ImmutableMap.of(dto.getComponentUuid(), componentDto.get())).apply(dto);
+    }
+    return new CeQueueDtoToCeTask().apply(dto);
+  }
+
+  private List<CeTask> loadTasks(DbSession dbSession, List<CeQueueDto> dtos) {
+    Set<String> componentUuids = from(dtos)
+      .transform(CeQueueDtoToComponentUuid.INSTANCE)
+      .filter(notNull())
+      .toSet();
+    Map<String, ComponentDto> componentDtoByUuid = from(dbClient.componentDao()
+      .selectByUuids(dbSession, componentUuids))
+      .uniqueIndex(toUuid());
+
+    return from(dtos)
+      .transform(new CeQueueDtoToCeTask(componentDtoByUuid))
+      .toList();
+  }
+
+  @Override
+  public boolean cancel(String taskUuid) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
+      if (queueDto.isPresent()) {
+        checkState(CeQueueDto.Status.PENDING.equals(queueDto.get().getStatus()), "Task is in progress and can't be canceled [uuid=%s]", taskUuid);
+        cancelImpl(dbSession, queueDto.get());
+        return true;
+      }
+      return false;
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  protected void cancelImpl(DbSession dbSession, CeQueueDto q) {
+    CeTask task = loadTask(dbSession, q);
+    CeActivityDto activityDto = new CeActivityDto(q);
+    activityDto.setStatus(CeActivityDto.Status.CANCELED);
+    remove(dbSession, task, q, activityDto);
+  }
+
+  @Override
+  public int cancelAll() {
+    return cancelAll(false);
+  }
+
+  protected int cancelAll(boolean includeInProgress) {
+    int count = 0;
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      for (CeQueueDto queueDto : dbClient.ceQueueDao().selectAllInAscOrder(dbSession)) {
+        if (includeInProgress || !queueDto.getStatus().equals(CeQueueDto.Status.IN_PROGRESS)) {
+          cancelImpl(dbSession, queueDto);
+          count++;
+        }
+      }
+      return count;
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  protected void remove(DbSession dbSession, CeTask task, CeQueueDto queueDto, CeActivityDto activityDto) {
+    dbClient.ceActivityDao().insert(dbSession, activityDto);
+    dbClient.ceQueueDao().deleteByUuid(dbSession, queueDto.getUuid());
+    dbSession.commit();
+    for (CeQueueListener listener : listeners) {
+      listener.onRemoved(task, activityDto.getStatus());
+    }
+  }
+
+  @Override
+  public void pauseSubmit() {
+    this.submitPaused.set(true);
+  }
+
+  @Override
+  public void resumeSubmit() {
+    this.submitPaused.set(false);
+  }
+
+  @Override
+  public boolean isSubmitPaused() {
+    return submitPaused.get();
+  }
+
+  private static class CeQueueDtoToCeTask implements Function<CeQueueDto, CeTask> {
+    private final Map<String, ComponentDto> componentDtoByUuid;
+
+    public CeQueueDtoToCeTask() {
+      this.componentDtoByUuid = Collections.emptyMap();
+    }
+
+    public CeQueueDtoToCeTask(Map<String, ComponentDto> componentDtoByUuid) {
+      this.componentDtoByUuid = componentDtoByUuid;
+    }
+
+    @Override
+    @Nonnull
+    public CeTask apply(@Nonnull CeQueueDto dto) {
+      CeTask.Builder builder = new CeTask.Builder();
+      builder.setUuid(dto.getUuid());
+      builder.setType(dto.getTaskType());
+      builder.setSubmitterLogin(dto.getSubmitterLogin());
+      String componentUuid = dto.getComponentUuid();
+      if (componentUuid != null) {
+        builder.setComponentUuid(componentUuid);
+        ComponentDto component = componentDtoByUuid.get(componentUuid);
+        if (component != null) {
+          builder.setComponentKey(component.getKey());
+          builder.setComponentName(component.name());
+        }
+      }
+      return builder.build();
+    }
+  }
+
+  private static class CeTaskSubmitToInsertedCeQueueDto implements Function<CeTaskSubmit, CeQueueDto> {
+    private final DbSession dbSession;
+    private final DbClient dbClient;
+
+    public CeTaskSubmitToInsertedCeQueueDto(DbSession dbSession, DbClient dbClient) {
+      this.dbSession = dbSession;
+      this.dbClient = dbClient;
+    }
+
+    @Override
+    @Nonnull
+    public CeQueueDto apply(@Nonnull CeTaskSubmit submission) {
+      CeQueueDto dto = new CeQueueDto();
+      dto.setUuid(submission.getUuid());
+      dto.setTaskType(submission.getType());
+      dto.setComponentUuid(submission.getComponentUuid());
+      dto.setStatus(CeQueueDto.Status.PENDING);
+      dto.setSubmitterLogin(submission.getSubmitterLogin());
+      dto.setStartedAt(null);
+      dbClient.ceQueueDao().insert(dbSession, dto);
+      return dto;
+    }
+  }
+
+  private enum CeQueueDtoToComponentUuid implements Function<CeQueueDto, String> {
+    INSTANCE;
+
+    @Override
+    @Nullable
+    public String apply(@Nonnull CeQueueDto input) {
+      return input.getComponentUuid();
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueListener.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueListener.java
new file mode 100644 (file)
index 0000000..90e3a0a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import org.sonar.db.ce.CeActivityDto;
+
+public interface CeQueueListener {
+
+  void onRemoved(CeTask task, CeActivityDto.Status status);
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeTask.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeTask.java
new file mode 100644 (file)
index 0000000..391a0d5
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import com.google.common.base.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static com.google.common.base.Strings.emptyToNull;
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class CeTask {
+
+  private final String type;
+  private final String uuid;
+  private final String componentUuid;
+  private final String componentKey;
+  private final String componentName;
+  private final String submitterLogin;
+
+  private CeTask(Builder builder) {
+    this.uuid = requireNonNull(emptyToNull(builder.uuid));
+    this.type = requireNonNull(emptyToNull(builder.type));
+    this.componentUuid = emptyToNull(builder.componentUuid);
+    this.componentKey = emptyToNull(builder.componentKey);
+    this.componentName = emptyToNull(builder.componentName);
+    this.submitterLogin = emptyToNull(builder.submitterLogin);
+  }
+
+  public String getUuid() {
+    return uuid;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  @CheckForNull
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  @CheckForNull
+  public String getComponentKey() {
+    return componentKey;
+  }
+
+  @CheckForNull
+  public String getComponentName() {
+    return componentName;
+  }
+
+  @CheckForNull
+  public String getSubmitterLogin() {
+    return submitterLogin;
+  }
+
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("componentUuid", componentUuid)
+      .add("uuid", uuid)
+      .add("type", type)
+      .add("submitterLogin", submitterLogin)
+      .toString();
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    CeTask ceTask = (CeTask) o;
+    return uuid.equals(ceTask.uuid);
+  }
+
+  @Override
+  public int hashCode() {
+    return uuid.hashCode();
+  }
+
+  public static final class Builder {
+    private String uuid;
+    private String type;
+    private String componentUuid;
+    private String componentKey;
+    private String componentName;
+    private String submitterLogin;
+
+    public Builder setUuid(String uuid) {
+      this.uuid = uuid;
+      return this;
+    }
+
+    public Builder setType(String type) {
+      this.type = type;
+      return this;
+    }
+
+    public Builder setComponentUuid(String componentUuid) {
+      this.componentUuid = componentUuid;
+      return this;
+    }
+
+    public Builder setComponentKey(@Nullable String s) {
+      this.componentKey = s;
+      return this;
+    }
+
+    public Builder setComponentName(@Nullable String s) {
+      this.componentName = s;
+      return this;
+    }
+
+    public Builder setSubmitterLogin(@Nullable String s) {
+      this.submitterLogin = s;
+      return this;
+    }
+
+    public CeTask build() {
+      return new CeTask(this);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeTaskResult.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeTaskResult.java
new file mode 100644 (file)
index 0000000..28f106d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import javax.annotation.CheckForNull;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
+
+/**
+ * Represents the result of the processing of a {@link CeTask}.
+ *
+ * @see {@link CeTaskProcessor#process(CeTask)}
+ */
+public interface CeTaskResult {
+  /**
+   * The id of the snapshot created, if any, for the Component in {@link CeTask}
+   */
+  @CheckForNull
+  Long getSnapshotId();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeTaskSubmit.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeTaskSubmit.java
new file mode 100644 (file)
index 0000000..10230be
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static com.google.common.base.Strings.emptyToNull;
+
+@Immutable
+public final class CeTaskSubmit {
+
+  private final String uuid;
+  private final String type;
+  private final String componentUuid;
+  private final String submitterLogin;
+
+  private CeTaskSubmit(Builder builder) {
+    this.uuid = Objects.requireNonNull(emptyToNull(builder.uuid));
+    this.type = Objects.requireNonNull(emptyToNull(builder.type));
+    this.componentUuid = emptyToNull(builder.componentUuid);
+    this.submitterLogin = emptyToNull(builder.submitterLogin);
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public String getUuid() {
+    return uuid;
+  }
+
+  @CheckForNull
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  @CheckForNull
+  public String getSubmitterLogin() {
+    return submitterLogin;
+  }
+
+  public static final class Builder {
+    private final String uuid;
+    private String type;
+    private String componentUuid;
+    private String submitterLogin;
+
+    public Builder(String uuid) {
+      this.uuid = uuid;
+    }
+
+    public String getUuid() {
+      return uuid;
+    }
+
+    public Builder setType(String s) {
+      this.type = s;
+      return this;
+    }
+
+    public Builder setComponentUuid(@Nullable String s) {
+      this.componentUuid = s;
+      return this;
+    }
+
+    public Builder setSubmitterLogin(@Nullable String s) {
+      this.submitterLogin = s;
+      return this;
+    }
+
+    public CeTaskSubmit build() {
+      return new CeTaskSubmit(this);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/package-info.java
new file mode 100644 (file)
index 0000000..f7bf1c7
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce.queue;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/report/ReportFiles.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/report/ReportFiles.java
new file mode 100644 (file)
index 0000000..7efca8e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue.report;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.config.Settings;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.ProcessProperties;
+
+import static java.lang.String.format;
+
+@ServerSide
+public class ReportFiles {
+
+  private static final String ZIP_EXTENSION = "zip";
+
+  private final Settings settings;
+
+  public ReportFiles(Settings settings) {
+    this.settings = settings;
+  }
+
+  public void save(String taskUuid, InputStream reportInput) {
+    File file = fileForUuid(taskUuid);
+    try {
+      FileUtils.copyInputStreamToFile(reportInput, file);
+    } catch (Exception e) {
+      org.sonar.core.util.FileUtils.deleteQuietly(file);
+      IOUtils.closeQuietly(reportInput);
+      throw new IllegalStateException(format("Fail to copy report to file: %s", file.getAbsolutePath()), e);
+    }
+  }
+
+  public void deleteIfExists(String taskUuid) {
+    org.sonar.core.util.FileUtils.deleteQuietly(fileForUuid(taskUuid));
+  }
+
+  public void deleteAll() {
+    File dir = reportDir();
+    if (dir.exists()) {
+      try {
+        org.sonar.core.util.FileUtils.cleanDirectory(dir);
+      } catch (Exception e) {
+        throw new IllegalStateException(format("Fail to clean directory: %s", dir.getAbsolutePath()), e);
+      }
+    }
+  }
+
+  private File reportDir() {
+    return new File(settings.getString(ProcessProperties.PATH_DATA), "ce/reports");
+  }
+
+  /**
+   * The analysis report to be processed. Can't be null
+   * but may no exist on file system.
+   */
+  public File fileForUuid(String taskUuid) {
+    return new File(reportDir(), format("%s.%s", taskUuid, ZIP_EXTENSION));
+  }
+
+  public List<String> listUuids() {
+    List<String> uuids = new ArrayList<>();
+    File dir = reportDir();
+    if (dir.exists()) {
+      Collection<File> files = FileUtils.listFiles(dir, new String[]{ZIP_EXTENSION}, false);
+      for (File file : files) {
+        uuids.add(FilenameUtils.getBaseName(file.getName()));
+      }
+    }
+    return uuids;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/report/ReportSubmitter.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/report/ReportSubmitter.java
new file mode 100644 (file)
index 0000000..e3f357f
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue.report;
+
+import java.io.InputStream;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.server.ServerSide;
+import org.sonar.core.component.ComponentKeys;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.NewComponent;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskSubmit;
+import org.sonar.server.permission.PermissionService;
+import org.sonar.server.user.UserSession;
+
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+
+@ServerSide
+public class ReportSubmitter {
+
+  private final CeQueue queue;
+  private final UserSession userSession;
+  private final ReportFiles reportFiles;
+  private final ComponentService componentService;
+  private final PermissionService permissionService;
+
+  public ReportSubmitter(CeQueue queue, UserSession userSession, ReportFiles reportFiles,
+    ComponentService componentService, PermissionService permissionService) {
+    this.queue = queue;
+    this.userSession = userSession;
+    this.reportFiles = reportFiles;
+    this.componentService = componentService;
+    this.permissionService = permissionService;
+  }
+
+  public CeTask submit(String projectKey, @Nullable String projectBranch, @Nullable String projectName, InputStream reportInput) {
+    String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch);
+    ComponentDto project = componentService.getNullableByKey(effectiveProjectKey);
+    if (project == null) {
+      // the project does not exist -> require global permission
+      userSession.checkPermission(SCAN_EXECUTION);
+
+      // the project does not exist -> requires to provision it
+      NewComponent newProject = new NewComponent(projectKey, StringUtils.defaultIfBlank(projectName, projectKey));
+      newProject.setBranch(projectBranch);
+      newProject.setQualifier(Qualifiers.PROJECT);
+      // no need to verify the permission "provisioning" as it's already handled by componentService
+      project = componentService.create(newProject);
+      permissionService.applyDefaultPermissionTemplate(project.getKey());
+    } else {
+      // the project exists -> require global or project permission
+      userSession.checkComponentPermission(SCAN_EXECUTION, projectKey);
+    }
+
+    // the report file must be saved before submitting the task
+    CeTaskSubmit.Builder submit = queue.prepareSubmit();
+    reportFiles.save(submit.getUuid(), reportInput);
+
+    submit.setType(CeTaskTypes.REPORT);
+    submit.setComponentUuid(project.uuid());
+    submit.setSubmitterLogin(userSession.getLogin());
+    return queue.submit(submit.build());
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/report/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/report/package-info.java
new file mode 100644 (file)
index 0000000..3c197b8
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce.queue.report;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/CeTaskProcessor.java b/server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/CeTaskProcessor.java
new file mode 100644 (file)
index 0000000..eb6d91d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.taskprocessor;
+
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+
+/**
+ * This interface is used to provide the processing code for {@link CeTask}s of one or more type to be called by the
+ * Compute Engine.
+ */
+public interface CeTaskProcessor {
+
+  /**
+   * The {@link CeTask#getType()} for which this {@link CeTaskProcessor} provides the processing code.
+   * <p>
+   * The match of type is done using {@link String#equals(Object)} and if more than one {@link CeTaskProcessor} declares
+   * itself had handler for the same {@link CeTask#getType()}, an error will be raised at startup and startup will
+   * fail.
+   * </p>
+   * <p>
+   * If an empty {@link Set} is returned, the {@link CeTaskProcessor} will be ignored.
+   * </p>
+   */
+  Set<String> getHandledCeTaskTypes();
+
+  /**
+   * Calls the processing code for a specific {@link CeTask} which will optionally return a {@link CeTaskResult}
+   * holding information to be persisted in the processing history of the Compute Engine (currently the {@code CE_ACTIVITY} table).
+   * <p>
+   * The specified is guaranteed to be non {@code null} and its {@link CeTask#getType()} to be one of the values
+   * of {@link #getHandledCeTaskTypes()}.
+   * </p>
+   *
+   * @throws RuntimeException when thrown, it will be caught and logged by the Compute Engine and the processing of the
+   *         specified {@link CeTask} will be flagged as failed.
+   */
+  @CheckForNull
+  CeTaskResult process(CeTask task);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/ReportTaskProcessorDeclaration.java b/server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/ReportTaskProcessorDeclaration.java
new file mode 100644 (file)
index 0000000..af2f851
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.taskprocessor;
+
+import java.util.Collections;
+import java.util.Set;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.db.ce.CeTaskTypes;
+
+/**
+ * CeTaskProcessor without any real implementation used to declare the CeTask type to the WebServer only.
+ */
+public class ReportTaskProcessorDeclaration implements CeTaskProcessor {
+
+  private static final Set<String> HANDLED_TYPES = Collections.singleton(CeTaskTypes.REPORT);
+
+  @Override
+  public Set<String> getHandledCeTaskTypes() {
+    return HANDLED_TYPES;
+  }
+
+  @Override
+  public CeTaskResult process(CeTask task) {
+   throw new UnsupportedOperationException("process must not be called in WebServer");
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/taskprocessor/package-info.java
new file mode 100644 (file)
index 0000000..66451d0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.ce.taskprocessor;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index fbbd8b49f6d088ae3f69662ea5baf0b854bd8691..cca3904252dbf26da47363670f4dd8af14c35119 100644 (file)
@@ -29,8 +29,8 @@ import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.process.LogbackHelper;
 import org.sonar.process.Props;
-import org.sonar.server.computation.log.CeLogDenyFilter;
-import org.sonar.server.computation.log.CeLogging;
+import org.sonar.ce.log.CeLogDenyFilter;
+import org.sonar.ce.log.CeLogging;
 import org.sonar.server.platform.ServerLogging;
 
 /**
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
new file mode 100644 (file)
index 0000000..69781be
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Paging;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskQuery;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentDtoFunctions;
+import org.sonar.db.component.ComponentQuery;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.Common;
+import org.sonarqube.ws.WsCe;
+import org.sonarqube.ws.WsCe.ActivityResponse;
+import org.sonarqube.ws.client.ce.ActivityWsRequest;
+
+import static java.lang.String.format;
+import static java.util.Collections.singletonList;
+import static org.apache.commons.lang.StringUtils.defaultString;
+import static org.sonar.api.utils.DateUtils.parseDateQuietly;
+import static org.sonar.api.utils.DateUtils.parseDateTimeQuietly;
+import static org.sonar.api.utils.Paging.offset;
+import static org.sonar.server.ws.WsUtils.checkRequest;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MAX_EXECUTED_AT;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MIN_SUBMITTED_AT;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_ONLY_CURRENTS;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_STATUS;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_TYPE;
+
+public class ActivityAction implements CeWsAction {
+  private static final int MAX_PAGE_SIZE = 1000;
+
+  private final UserSession userSession;
+  private final DbClient dbClient;
+  private final TaskFormatter formatter;
+  private final Set<String> taskTypes;
+
+  public ActivityAction(UserSession userSession, DbClient dbClient, TaskFormatter formatter, CeTaskProcessor[] taskProcessors) {
+    this.userSession = userSession;
+    this.dbClient = dbClient;
+    this.formatter = formatter;
+
+    this.taskTypes = new LinkedHashSet<>();
+    for (CeTaskProcessor taskProcessor : taskProcessors) {
+      taskTypes.addAll(taskProcessor.getHandledCeTaskTypes());
+    }
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("activity")
+      .setDescription(format("Search for tasks.<br> " +
+        "Requires the system administration permission, " +
+        "or project administration permission if %s is set.", PARAM_COMPONENT_ID))
+      .setResponseExample(getClass().getResource("activity-example.json"))
+      .setHandler(this)
+      .setSince("5.2");
+
+    action.createParam(PARAM_COMPONENT_ID)
+      .setDescription("Id of the component (project) to filter on")
+      .setExampleValue(Uuids.UUID_EXAMPLE_03);
+    action.createParam(PARAM_COMPONENT_QUERY)
+      .setDescription(format("Limit search to: <ul>" +
+        "<li>component names that contain the supplied string</li>" +
+        "<li>component keys that are exactly the same as the supplied string</li>" +
+        "</ul>" +
+        "Must not be set together with %s.<br />" +
+        "Deprecated and replaced by '%s'", PARAM_COMPONENT_ID, Param.TEXT_QUERY))
+      .setExampleValue("Apache")
+      .setDeprecatedSince("5.5");
+    action.createParam(Param.TEXT_QUERY)
+      .setDescription(format("Limit search to: <ul>" +
+        "<li>component names that contain the supplied string</li>" +
+        "<li>component keys that are exactly the same as the supplied string</li>" +
+        "<li>task ids that are exactly the same as the supplied string</li>" +
+        "</ul>" +
+        "Must not be set together with %s", PARAM_COMPONENT_ID))
+      .setExampleValue("Apache")
+      .setSince("5.5");
+    action.createParam(PARAM_STATUS)
+      .setDescription("Comma separated list of task statuses")
+      .setPossibleValues(ImmutableList.builder()
+        .add(CeActivityDto.Status.values())
+        .add(CeQueueDto.Status.values()).build())
+      .setExampleValue(Joiner.on(",").join(CeQueueDto.Status.IN_PROGRESS, CeActivityDto.Status.SUCCESS))
+      // activity statuses by default to be backward compatible
+      // queued tasks have been added in 5.5
+      .setDefaultValue(Joiner.on(",").join(CeActivityDto.Status.values()));
+    action.createParam(PARAM_ONLY_CURRENTS)
+      .setDescription("Filter on the last tasks (only the most recent finished task by project)")
+      .setBooleanPossibleValues()
+      .setDefaultValue("false");
+    action.createParam(PARAM_TYPE)
+      .setDescription("Task type")
+      .setExampleValue(CeTaskTypes.REPORT)
+      .setPossibleValues(taskTypes);
+    action.createParam(PARAM_MIN_SUBMITTED_AT)
+      .setDescription("Minimum date of task submission (inclusive)")
+      .setExampleValue(DateUtils.formatDateTime(new Date()));
+    action.createParam(PARAM_MAX_EXECUTED_AT)
+      .setDescription("Maximum date of end of task processing (inclusive)")
+      .setExampleValue(DateUtils.formatDateTime(new Date()));
+    action.addPagingParams(100, MAX_PAGE_SIZE);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    ActivityResponse activityResponse = doHandle(toSearchWsRequest(wsRequest));
+    writeProtobuf(activityResponse, wsRequest, wsResponse);
+  }
+
+  private ActivityResponse doHandle(ActivityWsRequest request) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      // if a task searched by uuid is found all other parameters are ignored
+      Optional<WsCe.Task> taskSearchedById = searchTaskByUuid(dbSession, request);
+      if (taskSearchedById.isPresent()) {
+        return buildResponse(
+          singletonList(taskSearchedById.get()),
+          Collections.<WsCe.Task>emptyList(),
+          Paging.forPageIndex(1).withPageSize(request.getPageSize()).andTotal(1));
+      }
+
+      CeTaskQuery query = buildQuery(dbSession, request);
+      checkPermissions(query);
+      TaskResult queuedTasks = loadQueuedTasks(dbSession, request, query);
+      TaskResult pastTasks = loadPastTasks(dbSession, request, query, queuedTasks.total);
+
+      return buildResponse(
+        queuedTasks.tasks,
+        pastTasks.tasks,
+        Paging.forPageIndex(request.getPage())
+          .withPageSize(request.getPageSize())
+          .andTotal(queuedTasks.total + pastTasks.total));
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private Optional<WsCe.Task> searchTaskByUuid(DbSession dbSession, ActivityWsRequest request) {
+    String textQuery = request.getQuery();
+    if (textQuery == null) {
+      return Optional.absent();
+    }
+
+    Optional<CeQueueDto> queue = dbClient.ceQueueDao().selectByUuid(dbSession, textQuery);
+    if (queue.isPresent()) {
+      return Optional.of(formatter.formatQueue(dbSession, queue.get()));
+    }
+
+    Optional<CeActivityDto> activity = dbClient.ceActivityDao().selectByUuid(dbSession, textQuery);
+    if (activity.isPresent()) {
+      return Optional.of(formatter.formatActivity(dbSession, activity.get()));
+    }
+
+    return Optional.absent();
+  }
+
+  private CeTaskQuery buildQuery(DbSession dbSession, ActivityWsRequest request) {
+    CeTaskQuery query = new CeTaskQuery();
+    query.setType(request.getType());
+    query.setOnlyCurrents(request.getOnlyCurrents());
+    query.setMinSubmittedAt(parseDateTimeAsLong(request.getMinSubmittedAt()));
+    query.setMaxExecutedAt(parseDateTimeAsLong(request.getMaxExecutedAt()));
+
+    List<String> statuses = request.getStatus();
+    if (statuses != null && !statuses.isEmpty()) {
+      query.setStatuses(request.getStatus());
+    }
+
+    loadComponentUuids(dbSession, request, query);
+    return query;
+  }
+
+  private void loadComponentUuids(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
+    String componentUuid = request.getComponentId();
+    String componentQuery = request.getQuery();
+
+    if (componentUuid != null) {
+      query.setComponentUuid(componentUuid);
+    }
+    if (componentQuery != null) {
+      ComponentQuery componentDtoQuery = ComponentQuery.builder().setNameOrKeyQuery(componentQuery).setQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW).build();
+      List<ComponentDto> componentDtos = dbClient.componentDao().selectByQuery(dbSession, componentDtoQuery, 0, CeTaskQuery.MAX_COMPONENT_UUIDS);
+      query.setComponentUuids(Lists.transform(componentDtos, ComponentDtoFunctions.toUuid()));
+    }
+  }
+
+  private TaskResult loadQueuedTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
+    int total = dbClient.ceQueueDao().countByQuery(dbSession, query);
+    List<CeQueueDto> dtos = dbClient.ceQueueDao().selectByQueryInDescOrder(dbSession, query,
+      Paging.forPageIndex(request.getPage())
+        .withPageSize(request.getPageSize())
+        .andTotal(total));
+    Iterable<WsCe.Task> tasks = formatter.formatQueue(dbSession, dtos);
+    return new TaskResult(tasks, total);
+  }
+
+  private TaskResult loadPastTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query, int totalQueuedTasks) {
+    int total = dbClient.ceActivityDao().countByQuery(dbSession, query);
+    // we have to take into account the total number of queue tasks found
+    int offset = Math.max(0, offset(request.getPage(), request.getPageSize()) - totalQueuedTasks);
+    List<CeActivityDto> dtos = dbClient.ceActivityDao().selectByQuery(dbSession, query, offset, request.getPageSize());
+    Iterable<WsCe.Task> ceTasks = formatter.formatActivity(dbSession, dtos);
+
+    return new TaskResult(ceTasks, total);
+  }
+
+  private void checkPermissions(CeTaskQuery query) {
+    List<String> componentUuids = query.getComponentUuids();
+    if (componentUuids != null && componentUuids.size() == 1) {
+      if (!isAllowedOnComponentUuid(userSession, componentUuids.get(0))) {
+        throw new ForbiddenException("Requires administration permission");
+      }
+    } else {
+      userSession.checkPermission(UserRole.ADMIN);
+    }
+  }
+
+  @CheckForNull
+  private static Long parseDateTimeAsLong(@Nullable String dateAsString) {
+    if (dateAsString == null) {
+      return null;
+    }
+
+    Date date = parseDateTimeQuietly(dateAsString);
+    if (date == null) {
+      date = parseDateQuietly(dateAsString);
+      checkRequest(date != null, "Date '%s' cannot be parsed as either a date or date+time", dateAsString);
+      date = DateUtils.addDays(date, 1);
+    }
+
+    return date.getTime();
+  }
+
+  public static boolean isAllowedOnComponentUuid(UserSession userSession, String componentUuid) {
+    return userSession.hasPermission(GlobalPermissions.SYSTEM_ADMIN) || userSession.hasComponentUuidPermission(UserRole.ADMIN, componentUuid);
+  }
+
+  private static ActivityResponse buildResponse(Iterable<WsCe.Task> queuedTasks, Iterable<WsCe.Task> pastTasks, Paging paging) {
+    WsCe.ActivityResponse.Builder wsResponseBuilder = WsCe.ActivityResponse.newBuilder();
+
+    int nbInsertedTasks = 0;
+    for (WsCe.Task queuedTask : queuedTasks) {
+      if (nbInsertedTasks < paging.pageSize()) {
+        wsResponseBuilder.addTasks(queuedTask);
+        nbInsertedTasks++;
+      }
+    }
+
+    for (WsCe.Task pastTask : pastTasks) {
+      if (nbInsertedTasks < paging.pageSize()) {
+        wsResponseBuilder.addTasks(pastTask);
+        nbInsertedTasks++;
+      }
+    }
+
+    wsResponseBuilder.setPaging(Common.Paging.newBuilder()
+      .setPageIndex(paging.pageIndex())
+      .setPageSize(paging.pageSize())
+      .setTotal(paging.total()));
+
+    return wsResponseBuilder.build();
+  }
+
+  private static ActivityWsRequest toSearchWsRequest(Request request) {
+    ActivityWsRequest activityWsRequest = new ActivityWsRequest()
+      .setComponentId(request.param(PARAM_COMPONENT_ID))
+      .setQuery(defaultString(request.param(Param.TEXT_QUERY), request.param(PARAM_COMPONENT_QUERY)))
+      .setStatus(request.paramAsStrings(PARAM_STATUS))
+      .setType(request.param(PARAM_TYPE))
+      .setMinSubmittedAt(request.param(PARAM_MIN_SUBMITTED_AT))
+      .setMaxExecutedAt(request.param(PARAM_MAX_EXECUTED_AT))
+      .setOnlyCurrents(request.paramAsBoolean(PARAM_ONLY_CURRENTS))
+      .setPage(request.mandatoryParamAsInt(Param.PAGE))
+      .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE));
+
+    checkRequest(activityWsRequest.getComponentId() == null || activityWsRequest.getQuery() == null, "%s and %s must not be set at the same time",
+      PARAM_COMPONENT_ID, PARAM_COMPONENT_QUERY);
+    checkRequest(activityWsRequest.getPageSize() <= MAX_PAGE_SIZE, "The '%s' parameter must be less than %d", Param.PAGE_SIZE, MAX_PAGE_SIZE);
+
+    return activityWsRequest;
+  }
+
+  private static class TaskResult {
+    private final Iterable<WsCe.Task> tasks;
+    private final int total;
+
+    private TaskResult(Iterable<WsCe.Task> tasks, int total) {
+      this.tasks = tasks;
+      this.total = total;
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CancelAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CancelAction.java
new file mode 100644 (file)
index 0000000..fc2ab9b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Uuids;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.server.user.UserSession;
+
+public class CancelAction implements CeWsAction {
+
+  public static final String PARAM_TASK_ID = "id";
+
+  private final UserSession userSession;
+  private final CeQueue queue;
+
+  public CancelAction(UserSession userSession, CeQueue queue) {
+    this.userSession = userSession;
+    this.queue = queue;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("cancel")
+      .setDescription("Cancels a pending task. Requires system administration permission. In-progress tasks can not be canceled.")
+      .setInternal(true)
+      .setPost(true)
+      .setSince("5.2")
+      .setHandler(this);
+
+    action
+      .createParam(PARAM_TASK_ID)
+      .setRequired(true)
+      .setDescription("Id of the task to cancel.")
+      .setExampleValue(Uuids.UUID_EXAMPLE_01);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) {
+    userSession.checkPermission(UserRole.ADMIN);
+    String taskId = wsRequest.mandatoryParam(PARAM_TASK_ID);
+    queue.cancel(taskId);
+    wsResponse.noContent();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CancelAllAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CancelAllAction.java
new file mode 100644 (file)
index 0000000..73457d1
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.server.user.UserSession;
+
+public class CancelAllAction implements CeWsAction {
+
+  private final UserSession userSession;
+  private final CeQueue queue;
+
+  public CancelAllAction(UserSession userSession, CeQueue queue) {
+    this.userSession = userSession;
+    this.queue = queue;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    controller.createAction("cancel_all")
+      .setDescription("Cancels all pending tasks. Requires system administration permission. In-progress tasks are not canceled.")
+      .setInternal(true)
+      .setPost(true)
+      .setSince("5.2")
+      .setHandler(this);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) {
+    userSession.checkPermission(UserRole.ADMIN);
+    queue.cancelAll();
+    wsResponse.noContent();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWs.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWs.java
new file mode 100644 (file)
index 0000000..8b03719
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class CeWs implements WebService {
+
+  public static final String ENDPOINT = "api/ce";
+
+  private final CeWsAction[] actions;
+
+  public CeWs(CeWsAction... actions) {
+    this.actions = actions;
+  }
+
+  @Override
+  public void define(Context context) {
+    NewController controller = context
+      .createController(ENDPOINT)
+      .setDescription("Compute Engine");
+    for (CeWsAction action : actions) {
+      action.define(controller);
+    }
+    controller.done();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsAction.java
new file mode 100644 (file)
index 0000000..6d68c0f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.ws.WsAction;
+
+/**
+ * Used by {@link CeWs} to loop over all its actions
+ */
+interface CeWsAction extends WsAction {
+  @Override
+  void define(WebService.NewController controller);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java
new file mode 100644 (file)
index 0000000..73b04cf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.sonar.core.platform.Module;
+
+public class CeWsModule extends Module {
+  @Override
+  protected void configureModule() {
+    add(
+      CeWs.class,
+      ActivityAction.class,
+      CancelAction.class,
+      CancelAllAction.class,
+      IsQueueEmptyWs.class,
+      LogsAction.class,
+      ComponentAction.class,
+      SubmitAction.class,
+      TaskFormatter.class,
+      TaskAction.class,
+      TaskTypesAction.class);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java
new file mode 100644 (file)
index 0000000..ffb78a2
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import java.util.List;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeTaskQuery;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsUtils;
+
+import static org.sonarqube.ws.WsCe.ProjectResponse;
+
+public class ComponentAction implements CeWsAction {
+
+  public static final String PARAM_COMPONENT_UUID = "componentId";
+
+  private final UserSession userSession;
+  private final DbClient dbClient;
+  private final TaskFormatter formatter;
+
+  public ComponentAction(UserSession userSession, DbClient dbClient, TaskFormatter formatter) {
+    this.userSession = userSession;
+    this.dbClient = dbClient;
+    this.formatter = formatter;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("component")
+      .setDescription("Get the pending tasks, in-progress tasks and the last executed task of a given component " +
+        "(usually a project). Requires the administration permission on the component.")
+      .setSince("5.2")
+      .setResponseExample(getClass().getResource("component-example.json"))
+      .setHandler(this);
+
+    action.createParam(PARAM_COMPONENT_UUID)
+      .setRequired(true)
+      .setExampleValue(Uuids.UUID_EXAMPLE_01);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    String componentUuid = wsRequest.mandatoryParam(PARAM_COMPONENT_UUID);
+    userSession.checkComponentUuidPermission(UserRole.USER, componentUuid);
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      List<CeQueueDto> queueDtos = dbClient.ceQueueDao().selectByComponentUuid(dbSession, componentUuid);
+      CeTaskQuery activityQuery = new CeTaskQuery()
+        .setComponentUuid(componentUuid)
+        .setOnlyCurrents(true);
+      List<CeActivityDto> activityDtos = dbClient.ceActivityDao().selectByQuery(dbSession, activityQuery, 0, 1);
+
+      ProjectResponse.Builder wsResponseBuilder = ProjectResponse.newBuilder();
+      wsResponseBuilder.addAllQueue(formatter.formatQueue(dbSession, queueDtos));
+      if (activityDtos.size() == 1) {
+        wsResponseBuilder.setCurrent(formatter.formatActivity(dbSession, activityDtos.get(0)));
+      }
+      WsUtils.writeProtobuf(wsResponseBuilder.build(), wsRequest, wsResponse);
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/IsQueueEmptyWs.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/IsQueueEmptyWs.java
new file mode 100644 (file)
index 0000000..c1742b6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+
+/**
+ * Internal WebService with one action
+ */
+public class IsQueueEmptyWs implements WebService {
+  public static final String API_ENDPOINT = "api/analysis_reports";
+
+  private final IsQueueEmptyAction action;
+
+  public IsQueueEmptyWs(DbClient dbClient) {
+    this.action = new IsQueueEmptyAction(dbClient);
+  }
+
+  @Override
+  public void define(Context context) {
+    NewController controller = context
+      .createController(API_ENDPOINT)
+      .setDescription("For internal testing - do not use");
+    action.define(controller);
+    controller.done();
+  }
+
+  static class IsQueueEmptyAction implements RequestHandler {
+    private final DbClient dbClient;
+
+    public IsQueueEmptyAction(DbClient dbClient) {
+      this.dbClient = dbClient;
+    }
+
+    public void define(WebService.NewController controller) {
+      controller
+        .createAction("is_queue_empty")
+        .setDescription("Check if the queue of Compute Engine is empty")
+        .setResponseExample(getClass().getResource("is_queue_empty-example.txt"))
+        .setSince("5.1")
+        .setInternal(true)
+        .setHandler(this);
+    }
+
+    @Override
+    public void handle(Request request, Response response) throws Exception {
+      DbSession dbSession = dbClient.openSession(false);
+      try {
+        boolean isQueueEmpty = dbClient.ceQueueDao().selectAllInAscOrder(dbSession).isEmpty();
+        IOUtils.write(String.valueOf(isQueueEmpty), response.stream().output());
+      } finally {
+        dbClient.closeSession(dbSession);
+      }
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/LogsAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/LogsAction.java
new file mode 100644 (file)
index 0000000..f89b3c7
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.MediaTypes;
+
+import static java.lang.String.format;
+
+public class LogsAction implements CeWsAction {
+
+  public static final String ACTION = "logs";
+  public static final String PARAM_TASK_UUID = "taskId";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+  private final CeLogging ceLogging;
+
+  public LogsAction(DbClient dbClient, UserSession userSession, CeLogging ceLogging) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+    this.ceLogging = ceLogging;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction(ACTION)
+      .setDescription("Logs of a task. Format of response is plain text. HTTP code 404 is returned if the task does not " +
+        "exist or if logs are not available. Requires system administration permission.")
+      .setResponseExample(getClass().getResource("logs-example.log"))
+      .setInternal(true)
+      .setSince("5.2")
+      .setHandler(this);
+
+    action
+      .createParam(PARAM_TASK_UUID)
+      .setRequired(true)
+      .setDescription("Id of task")
+      .setExampleValue(Uuids.UUID_EXAMPLE_01);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    userSession.checkPermission(UserRole.ADMIN);
+
+    String taskUuid = wsRequest.mandatoryParam(PARAM_TASK_UUID);
+    LogFileRef ref = loadLogRef(taskUuid);
+    Optional<File> logFile = ceLogging.getFile(ref);
+    if (logFile.isPresent()) {
+      writeFile(logFile.get(), wsResponse);
+    } else {
+      throw new NotFoundException(format("Logs of task %s not found", taskUuid));
+    }
+  }
+
+  private LogFileRef loadLogRef(String taskUuid) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
+      if (queueDto.isPresent()) {
+        return LogFileRef.from(queueDto.get());
+      }
+      Optional<CeActivityDto> activityDto = dbClient.ceActivityDao().selectByUuid(dbSession, taskUuid);
+      if (activityDto.isPresent()) {
+        return LogFileRef.from(activityDto.get());
+      }
+      throw new NotFoundException(format("Task %s not found", taskUuid));
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private static void writeFile(File file, Response wsResponse) {
+    try {
+      Response.Stream stream = wsResponse.stream();
+      stream.setMediaType(MediaTypes.TXT);
+      FileUtils.copyFile(file, stream.output());
+    } catch (IOException e) {
+      throw new IllegalStateException("Fail to copy compute engine log file to HTTP response: " + file.getAbsolutePath(), e);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/SubmitAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/SubmitAction.java
new file mode 100644 (file)
index 0000000..33ca21f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import java.io.InputStream;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.report.ReportSubmitter;
+import org.sonar.server.ws.WsUtils;
+import org.sonarqube.ws.WsCe;
+
+public class SubmitAction implements CeWsAction {
+
+  public static final String PARAM_PROJECT_KEY = "projectKey";
+  public static final String PARAM_PROJECT_BRANCH = "projectBranch";
+  public static final String PARAM_PROJECT_NAME = "projectName";
+  public static final String PARAM_REPORT_DATA = "report";
+
+  private final ReportSubmitter reportSubmitter;
+
+  public SubmitAction(ReportSubmitter reportSubmitter) {
+    this.reportSubmitter = reportSubmitter;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("submit")
+      .setDescription("Submits a scanner report to the queue. Report is processed asynchronously. Requires analysis permission. " +
+        "If the project does not exist, then the provisioning permission is also required.")
+      .setPost(true)
+      .setInternal(true)
+      .setSince("5.2")
+      .setHandler(this)
+      .setResponseExample(getClass().getResource("submit-example.json"));
+
+    action
+      .createParam(PARAM_PROJECT_KEY)
+      .setRequired(true)
+      .setDescription("Key of project")
+      .setExampleValue("my_project");
+
+    action
+      .createParam(PARAM_PROJECT_BRANCH)
+      .setDescription("Optional branch of project")
+      .setExampleValue("branch-1.x");
+
+    action
+      .createParam(PARAM_PROJECT_NAME)
+      .setRequired(false)
+      .setDescription("Optional name of the project, used only if the project does not exist yet.")
+      .setExampleValue("My Project");
+
+    action
+      .createParam(PARAM_REPORT_DATA)
+      .setRequired(true)
+      .setDescription("Report file. Format is not an API, it changes among SonarQube versions.");
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    String projectKey = wsRequest.mandatoryParam(PARAM_PROJECT_KEY);
+    String projectBranch = wsRequest.param(PARAM_PROJECT_BRANCH);
+    String projectName = StringUtils.defaultIfBlank(wsRequest.param(PARAM_PROJECT_NAME), projectKey);
+    InputStream reportInput = wsRequest.paramAsInputStream(PARAM_REPORT_DATA);
+
+    CeTask task = reportSubmitter.submit(projectKey, projectBranch, projectName, reportInput);
+
+    WsCe.SubmitResponse submitResponse = WsCe.SubmitResponse.newBuilder()
+      .setTaskId(task.getUuid())
+      .setProjectId(task.getComponentUuid())
+      .build();
+    WsUtils.writeProtobuf(submitResponse, wsRequest, wsResponse);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java
new file mode 100644 (file)
index 0000000..55b61f8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.WsCe;
+
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class TaskAction implements CeWsAction {
+
+  public static final String ACTION = "task";
+  public static final String PARAM_TASK_UUID = "id";
+
+  private final DbClient dbClient;
+  private final TaskFormatter wsTaskFormatter;
+  private final UserSession userSession;
+
+  public TaskAction(DbClient dbClient, TaskFormatter wsTaskFormatter, UserSession userSession) {
+    this.dbClient = dbClient;
+    this.wsTaskFormatter = wsTaskFormatter;
+    this.userSession = userSession;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction(ACTION)
+      .setDescription("Give Compute Engine task details such as type, status, duration and associated component.<br />" +
+        "Requires 'Administer System' or 'Execute Analysis' permission.")
+      .setResponseExample(getClass().getResource("task-example.json"))
+      .setSince("5.2")
+      .setHandler(this);
+
+    action
+      .createParam(PARAM_TASK_UUID)
+      .setRequired(true)
+      .setDescription("Id of task")
+      .setExampleValue(Uuids.UUID_EXAMPLE_01);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    String taskUuid = wsRequest.mandatoryParam(PARAM_TASK_UUID);
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      WsCe.TaskResponse.Builder wsTaskResponse = WsCe.TaskResponse.newBuilder();
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
+      if (queueDto.isPresent()) {
+        checkPermission(queueDto.get().getComponentUuid());
+        wsTaskResponse.setTask(wsTaskFormatter.formatQueue(dbSession, queueDto.get()));
+      } else {
+        Optional<CeActivityDto> activityDto = dbClient.ceActivityDao().selectByUuid(dbSession, taskUuid);
+        if (activityDto.isPresent()) {
+          checkPermission(activityDto.get().getComponentUuid());
+          wsTaskResponse.setTask(wsTaskFormatter.formatActivity(dbSession, activityDto.get()));
+        } else {
+          throw new NotFoundException();
+        }
+      }
+      writeProtobuf(wsTaskResponse.build(), wsRequest, wsResponse);
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private void checkPermission(@Nullable String projectUuid) {
+    if (!userSession.hasPermission(SYSTEM_ADMIN)
+      && !userSession.hasPermission(SCAN_EXECUTION)
+      && (projectUuid == null || !userSession.hasComponentUuidPermission(SCAN_EXECUTION, projectUuid))
+      ) {
+      throw insufficientPrivilegesException();
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java
new file mode 100644 (file)
index 0000000..9e1fb53
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentDtoFunctions;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonarqube.ws.WsCe;
+
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.FluentIterable.from;
+
+/**
+ * Converts {@link CeActivityDto} and {@link CeQueueDto} to the protobuf objects
+ * used to write WS responses (see ws-ce.proto in module sonar-ws)
+ */
+public class TaskFormatter {
+
+  private final DbClient dbClient;
+  private final CeLogging ceLogging;
+  private final System2 system2;
+
+  public TaskFormatter(DbClient dbClient, CeLogging ceLogging, System2 system2) {
+    this.dbClient = dbClient;
+    this.ceLogging = ceLogging;
+    this.system2 = system2;
+  }
+
+  public Iterable<WsCe.Task> formatQueue(DbSession dbSession, List<CeQueueDto> dtos) {
+    ComponentDtoCache cache = new ComponentDtoCache(dbSession, ceQueueDtoToComponentUuids(dtos));
+    return from(dtos)
+      .transform(new CeQueueDtoToTask(cache));
+  }
+
+  public WsCe.Task formatQueue(DbSession dbSession, CeQueueDto dto) {
+    return formatQueue(dto, new ComponentDtoCache(dbSession, dto.getComponentUuid()));
+  }
+
+  private WsCe.Task formatQueue(CeQueueDto dto, ComponentDtoCache componentDtoCache) {
+    WsCe.Task.Builder builder = WsCe.Task.newBuilder();
+    builder.setId(dto.getUuid());
+    builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
+    builder.setType(dto.getTaskType());
+    builder.setLogs(ceLogging.getFile(LogFileRef.from(dto)).isPresent());
+    if (dto.getComponentUuid() != null) {
+      builder.setComponentId(dto.getComponentUuid());
+      buildComponent(builder, componentDtoCache.get(dto.getComponentUuid()));
+    }
+    if (dto.getSubmitterLogin() != null) {
+      builder.setSubmitterLogin(dto.getSubmitterLogin());
+    }
+    builder.setSubmittedAt(DateUtils.formatDateTime(new Date(dto.getCreatedAt())));
+    if (dto.getStartedAt() != null) {
+      builder.setStartedAt(DateUtils.formatDateTime(new Date(dto.getStartedAt())));
+    }
+    //
+    Long executionTimeMs = computeExecutionTimeMs(dto);
+    if (executionTimeMs != null) {
+      builder.setExecutionTimeMs(executionTimeMs);
+    }
+    return builder.build();
+  }
+
+  public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto dto) {
+    return formatActivity(dto, new ComponentDtoCache(dbSession, dto.getComponentUuid()));
+  }
+
+  public Iterable<WsCe.Task> formatActivity(DbSession dbSession, List<CeActivityDto> dtos) {
+    ComponentDtoCache cache = new ComponentDtoCache(dbSession, ceActivityDtoToComponentUuids(dtos));
+    return from(dtos).transform(new CeActivityDtoToTask(cache));
+  }
+
+  private WsCe.Task formatActivity(CeActivityDto dto, ComponentDtoCache componentDtoCache) {
+    WsCe.Task.Builder builder = WsCe.Task.newBuilder();
+    builder.setId(dto.getUuid());
+    builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
+    builder.setType(dto.getTaskType());
+    builder.setLogs(ceLogging.getFile(LogFileRef.from(dto)).isPresent());
+    if (dto.getComponentUuid() != null) {
+      builder.setComponentId(dto.getComponentUuid());
+      buildComponent(builder, componentDtoCache.get(dto.getComponentUuid()));
+    }
+    if (dto.getSnapshotId() != null) {
+      builder.setAnalysisId(String.valueOf(dto.getSnapshotId()));
+    }
+    if (dto.getSubmitterLogin() != null) {
+      builder.setSubmitterLogin(dto.getSubmitterLogin());
+    }
+    builder.setSubmittedAt(DateUtils.formatDateTime(new Date(dto.getSubmittedAt())));
+    if (dto.getStartedAt() != null) {
+      builder.setStartedAt(DateUtils.formatDateTime(new Date(dto.getStartedAt())));
+    }
+    if (dto.getExecutedAt() != null) {
+      builder.setExecutedAt(DateUtils.formatDateTime(new Date(dto.getExecutedAt())));
+    }
+    if (dto.getExecutionTimeMs() != null) {
+      builder.setExecutionTimeMs(dto.getExecutionTimeMs());
+    }
+    return builder.build();
+  }
+
+  private static void buildComponent(WsCe.Task.Builder builder, @Nullable ComponentDto componentDto) {
+    if (componentDto != null) {
+      builder.setComponentKey(componentDto.getKey());
+      builder.setComponentName(componentDto.name());
+      builder.setComponentQualifier(componentDto.qualifier());
+    }
+  }
+
+  private static Set<String> ceQueueDtoToComponentUuids(Iterable<CeQueueDto> dtos) {
+    return from(dtos)
+      .transform(CeQueueDtoToComponentUuid.INSTANCE)
+      .filter(notNull())
+      .toSet();
+  }
+
+  private static Set<String> ceActivityDtoToComponentUuids(Iterable<CeActivityDto> dtos) {
+    return from(dtos)
+      .transform(CeActivityDtoToComponentUuid.INSTANCE)
+      .filter(notNull())
+      .toSet();
+  }
+
+  private enum CeQueueDtoToComponentUuid implements Function<CeQueueDto, String> {
+    INSTANCE;
+
+    @Override
+    @Nullable
+    public String apply(@Nonnull CeQueueDto input) {
+      return input.getComponentUuid();
+    }
+  }
+
+  private enum CeActivityDtoToComponentUuid implements Function<CeActivityDto, String> {
+    INSTANCE;
+
+    @Override
+    @Nullable
+    public String apply(@Nonnull CeActivityDto input) {
+      return input.getComponentUuid();
+    }
+  }
+
+  private class ComponentDtoCache {
+    private final Map<String, ComponentDto> componentsByUuid;
+
+    public ComponentDtoCache(DbSession dbSession, Set<String> uuids) {
+      this.componentsByUuid = from(dbClient.componentDao().selectByUuids(dbSession, uuids)).uniqueIndex(ComponentDtoFunctions.toUuid());
+    }
+
+    public ComponentDtoCache(DbSession dbSession, String uuid) {
+      Optional<ComponentDto> componentDto = dbClient.componentDao().selectByUuid(dbSession, uuid);
+      this.componentsByUuid = componentDto.isPresent() ? ImmutableMap.of(uuid, componentDto.get()) : Collections.<String, ComponentDto>emptyMap();
+    }
+
+    @CheckForNull
+    ComponentDto get(@Nullable String uuid) {
+      if (uuid == null) {
+        return null;
+      }
+      return componentsByUuid.get(uuid);
+    }
+  }
+
+  /**
+   * now - startedAt
+   */
+  @CheckForNull
+  Long computeExecutionTimeMs(CeQueueDto dto) {
+    Long startedAt = dto.getStartedAt();
+    if (startedAt == null) {
+      return null;
+    }
+    return system2.now() - startedAt;
+  }
+
+  private final class CeActivityDtoToTask implements Function<CeActivityDto, WsCe.Task> {
+    private final ComponentDtoCache cache;
+
+    public CeActivityDtoToTask(ComponentDtoCache cache) {
+      this.cache = cache;
+    }
+
+    @Override
+    @Nonnull
+    public WsCe.Task apply(@Nonnull CeActivityDto input) {
+      return formatActivity(input, cache);
+    }
+  }
+
+  private final class CeQueueDtoToTask implements Function<CeQueueDto, WsCe.Task> {
+    private final ComponentDtoCache cache;
+
+    public CeQueueDtoToTask(ComponentDtoCache cache) {
+      this.cache = cache;
+    }
+
+    @Override
+    @Nonnull
+    public WsCe.Task apply(@Nonnull CeQueueDto input) {
+      return formatQueue(input, cache);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskTypesAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskTypesAction.java
new file mode 100644 (file)
index 0000000..b2ae749
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
+import org.sonarqube.ws.WsCe;
+
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class TaskTypesAction implements CeWsAction {
+  private final Set<String> taskTypes;
+
+  public TaskTypesAction(CeTaskProcessor[] taskProcessors) {
+    ImmutableSet.Builder<String> taskTypesBuilder = ImmutableSet.builder();
+    for (CeTaskProcessor taskProcessor : taskProcessors) {
+      taskTypesBuilder.addAll(taskProcessor.getHandledCeTaskTypes());
+    }
+    this.taskTypes = taskTypesBuilder.build();
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    controller.createAction("task_types")
+      .setDescription("List available task types")
+      .setResponseExample(getClass().getResource("task_types-example.json"))
+      .setSince("5.5")
+      .setInternal(true)
+      .setHandler(this);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    WsCe.TaskTypesWsResponse taskTypesWsResponse = WsCe.TaskTypesWsResponse.newBuilder()
+      .addAllTaskTypes(taskTypes)
+      .build();
+
+    writeProtobuf(taskTypesWsResponse, request, response);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/package-info.java
new file mode 100644 (file)
index 0000000..9526585
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.ce.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
index d6b35a77a0a22146720605bca89cee3694e7f092..25c04f2e25bd73854efe91ebde10fd061127f331 100644 (file)
  */
 package org.sonar.server.computation;
 
+import org.sonar.ce.log.CeLogging;
 import org.sonar.core.platform.Module;
 import org.sonar.db.purge.period.DefaultPeriodCleaner;
 import org.sonar.server.computation.configuration.CeConfigurationImpl;
 import org.sonar.server.computation.dbcleaner.IndexPurgeListener;
 import org.sonar.server.computation.dbcleaner.ProjectCleaner;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.properties.ProjectSettingsFactory;
 
 /**
  * Globally available components in CE
@@ -39,7 +38,6 @@ public class CeModule extends Module {
 
       DefaultPeriodCleaner.class,
       ProjectCleaner.class,
-      ProjectSettingsFactory.class,
       IndexPurgeListener.class);
   }
 }
index 72feb3e379685d85df04c17e1dee574f8200e421..d4f010d5cf390ee359b88077c2d2f20dfb21c5be 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.computation.batch;
 
 import java.io.File;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 
 public interface BatchReportDirectoryHolder {
   /**
index abf817809add5c1a8bde2be6f4d7feba660ee014..89d644ea212612bac60a5759bcef9265a1fa9e62 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.computation.container;
 
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.ContainerPopulator;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 
 /**
  * The Compute Engine container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}.
index d31a0d11f9147df2b6bd5c4cd707a7fdf9acd969..8893ab2c885d3467ff043f698424fdb9441bc40b 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.computation.container;
 
 import javax.annotation.Nullable;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 import org.sonar.server.devcockpit.DevCockpitBridge;
 
 public interface ContainerFactory {
index 9b3890e41427e4d70446ba7bfcd3faa7d5306506..78d2f863f01169f0233e9e762cd97d1991f6dd77 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.computation.container;
 
 import javax.annotation.Nullable;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 import org.sonar.server.devcockpit.DevCockpitBridge;
 
 public class ContainerFactoryImpl implements ContainerFactory {
index 09e4e6b01e7172cabbe708a0e48d5fa65d4a8d22..82ed25a8009f0a603e5a7c29591086e70f889e80 100644 (file)
@@ -81,7 +81,7 @@ import org.sonar.server.computation.qualitymodel.NewQualityModelMeasuresVisitor;
 import org.sonar.server.computation.qualitymodel.QualityModelMeasuresVisitor;
 import org.sonar.server.computation.qualitymodel.RatingSettings;
 import org.sonar.server.computation.qualityprofile.ActiveRulesHolderImpl;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 import org.sonar.server.computation.scm.ScmInfoRepositoryImpl;
 import org.sonar.server.computation.source.LastCommitVisitor;
 import org.sonar.server.computation.source.SourceHashRepositoryImpl;
index 38a881a375252cd1f469cbd32458d5c9cbcc3cb7..1efe1b093808a1a423515ce01642b5418c4877ce 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.computation.container;
 
 import org.sonar.core.platform.Module;
-import org.sonar.server.computation.queue.report.ReportSubmitter;
+import org.sonar.ce.queue.report.ReportSubmitter;
 import org.sonar.server.computation.taskprocessor.report.ReportTaskProcessor;
 import org.sonar.server.computation.step.ComputationStepExecutor;
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeFileAppenderFactory.java b/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeFileAppenderFactory.java
deleted file mode 100644 (file)
index fc8ffab..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
-import ch.qos.logback.core.Context;
-import ch.qos.logback.core.FileAppender;
-import ch.qos.logback.core.sift.AppenderFactory;
-import com.google.common.annotations.VisibleForTesting;
-import java.io.File;
-import org.sonar.server.computation.queue.CeTask;
-
-import static java.lang.String.format;
-
-/**
- * Creates a Logback appender for a Compute Engine task. See
- * http://logback.qos.ch/manual/loggingSeparation.html
- */
-public class CeFileAppenderFactory<E> implements AppenderFactory<E> {
-
-  private static final String ENCODER_PATTERN = "%d{yyyy.MM.dd HH:mm:ss} %-5level [%logger{20}] %msg%n";
-
-  private final File ceLogsDir;
-
-  @VisibleForTesting
-  CeFileAppenderFactory(File ceLogsDir) {
-    this.ceLogsDir = ceLogsDir;
-  }
-
-  /**
-   * @param context
-   * @param discriminatingValue path of log file relative to the directory data/ce/logs
-   * @see CeLogging#initForTask(CeTask) 
-   */
-  @Override
-  public FileAppender<E> buildAppender(Context context, String discriminatingValue) {
-    PatternLayoutEncoder consoleEncoder = new PatternLayoutEncoder();
-    consoleEncoder.setContext(context);
-    consoleEncoder.setPattern(ENCODER_PATTERN);
-    consoleEncoder.start();
-    FileAppender appender = new FileAppender<>();
-    appender.setContext(context);
-    appender.setEncoder(consoleEncoder);
-    appender.setName(format("ce-%s", discriminatingValue));
-    appender.setFile(new File(ceLogsDir, discriminatingValue).getAbsolutePath());
-    appender.start();
-    return appender;
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogAcceptFilter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogAcceptFilter.java
deleted file mode 100644 (file)
index 8381879..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.core.filter.Filter;
-import ch.qos.logback.core.spi.FilterReply;
-import org.slf4j.MDC;
-
-/**
- * Keeps only the Compute Engine logs.
- */
-public class CeLogAcceptFilter<E> extends Filter<E> {
-
-  @Override
-  public FilterReply decide(E o) {
-    return MDC.get(CeLogging.MDC_LOG_PATH) == null ? FilterReply.DENY : FilterReply.ACCEPT;
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogDenyFilter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogDenyFilter.java
deleted file mode 100644 (file)
index c1d564e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.core.filter.Filter;
-import ch.qos.logback.core.spi.FilterReply;
-import org.slf4j.MDC;
-
-/**
- * Filters out the Compute Engine logs.
- */
-public class CeLogDenyFilter<E> extends Filter<E> {
-
-  @Override
-  public FilterReply decide(E o) {
-    return MDC.get(CeLogging.MDC_LOG_PATH) == null ? FilterReply.ACCEPT : FilterReply.DENY;
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogging.java b/server/sonar-server/src/main/java/org/sonar/server/computation/log/CeLogging.java
deleted file mode 100644 (file)
index 1b746df..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
-import ch.qos.logback.classic.sift.SiftingAppender;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.Appender;
-import ch.qos.logback.core.sift.AppenderTracker;
-import ch.qos.logback.core.util.Duration;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.comparator.LastModifiedFileComparator;
-import org.apache.commons.io.filefilter.FileFilterUtils;
-import org.apache.log4j.MDC;
-import org.sonar.api.config.Settings;
-import org.sonar.process.LogbackHelper;
-import org.sonar.process.ProcessProperties;
-import org.sonar.process.Props;
-import org.sonar.server.computation.queue.CeTask;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.FluentIterable.from;
-import static com.google.common.collect.Lists.newArrayList;
-import static java.lang.String.format;
-
-/**
- * Manages the logs written by Compute Engine:
- * <ul>
- *   <li>access to existing logs</li>
- *   <li>configure logback when CE worker starts and stops processing a task</li>
- * </ul>
- */
-public class CeLogging {
-
-  private static final long TIMEOUT_2_MINUTES = 1000 * 60 * 2L;
-  private static final String CE_APPENDER_NAME = "ce";
-  // using 0L as timestamp when retrieving appender to stop it will make it instantly eligible for removal
-  private static final long STOPPING_TRACKER_TIMESTAMP = 0L;
-
-  @VisibleForTesting
-  static final String MDC_LOG_PATH = "ceLogPath";
-  public static final String MAX_LOGS_PROPERTY = "sonar.ce.maxLogsPerTask";
-
-  private final LogbackHelper helper = new LogbackHelper();
-  private final File logsDir;
-  private final Settings settings;
-
-  public CeLogging(Settings settings) {
-    String dataDir = settings.getString(ProcessProperties.PATH_DATA);
-    checkArgument(dataDir != null, "Property %s is not set", ProcessProperties.PATH_DATA);
-    this.logsDir = logsDirFromDataDir(new File(dataDir));
-    this.settings = settings;
-  }
-
-  /**
-   * Gets the log file of a given task. It may not exist if it
-   * was purged or if the task does not exist.
-   */
-  public Optional<File> getFile(LogFileRef ref) {
-    File logFile = new File(logsDir, ref.getRelativePath());
-    if (logFile.exists()) {
-      return Optional.of(logFile);
-    }
-    return Optional.absent();
-  }
-
-  public void deleteIfExists(LogFileRef ref) {
-    File logFile = new File(logsDir, ref.getRelativePath());
-    logFile.delete();
-  }
-
-  /**
-   * Initialize logging of a Compute Engine task. Must be called
-   * before first writing of log.
-   * <p>After this method is executed, then Compute Engine logs are
-   * written to a dedicated appender and are removed from sonar.log.</p>
-   */
-  public void initForTask(CeTask task) {
-    LogFileRef ref = LogFileRef.from(task);
-    // Logback SiftingAppender requires to use a String, so
-    // the path is put but not the object LogFileRef
-    MDC.put(MDC_LOG_PATH, ref.getRelativePath());
-  }
-
-  /**
-   * Clean-up the logging of a task. Must be called after the last writing
-   * of log.
-   * <p>After this method is executed, then Compute Engine logs are
-   * written to sonar.log only.</p>
-   */
-  public void clearForTask() {
-    String relativePath = (String) MDC.get(MDC_LOG_PATH);
-    MDC.remove(MDC_LOG_PATH);
-
-    if (relativePath != null) {
-      stopAppender(relativePath);
-      purgeDir(new File(logsDir, relativePath).getParentFile());
-    }
-  }
-
-  private void stopAppender(String relativePath) {
-    Appender<ILoggingEvent> appender = helper.getRootContext().getLogger(Logger.ROOT_LOGGER_NAME).getAppender(CE_APPENDER_NAME);
-    checkState(appender instanceof SiftingAppender, "Appender with name %s is null or not a SiftingAppender", CE_APPENDER_NAME);
-    AppenderTracker<ILoggingEvent> ceAppender = ((SiftingAppender) appender).getAppenderTracker();
-    ceAppender.getOrCreate(relativePath, STOPPING_TRACKER_TIMESTAMP).stop();
-  }
-
-  @VisibleForTesting
-  void purgeDir(File dir) {
-    if (dir.exists()) {
-      int maxLogs = settings.getInt(MAX_LOGS_PROPERTY);
-      if (maxLogs < 0) {
-        throw new IllegalArgumentException(format("Property %s must be positive. Got: %d", MAX_LOGS_PROPERTY, maxLogs));
-      }
-      List<File> logFiles = newArrayList(FileUtils.listFiles(dir, FileFilterUtils.fileFileFilter(), FileFilterUtils.falseFileFilter()));
-      if (logFiles.size() > maxLogs) {
-        Collections.sort(logFiles, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
-        for (File logFile : from(logFiles).limit(logFiles.size() - maxLogs)) {
-          logFile.delete();
-        }
-      }
-    }
-  }
-
-  /**
-   * Directory which contains all the compute engine logs.
-   * Log files must be persistent among server restarts and upgrades, so they are
-   * stored into directory data/ but not into directories logs/ or temp/.
-   * @return the non-null directory. It may not exist at startup.
-   */
-  static File logsDirFromDataDir(File dataDir) {
-    return new File(dataDir, "ce/logs");
-  }
-
-  /**
-   * Create Logback configuration for enabling sift appender.
-   * A new log file is created for each task. It is based on MDC as long
-   * as Compute Engine is not executed in its
-   * own process but in the same process as web server.
-   */
-  public static Appender<ILoggingEvent> createAppenderConfiguration(LoggerContext ctx, Props processProps) {
-    File dataDir = new File(processProps.nonNullValue(ProcessProperties.PATH_DATA));
-    File logsDir = logsDirFromDataDir(dataDir);
-    return createAppenderConfiguration(ctx, logsDir);
-  }
-
-  static SiftingAppender createAppenderConfiguration(LoggerContext ctx, File logsDir) {
-    SiftingAppender siftingAppender = new SiftingAppender();
-    siftingAppender.addFilter(new CeLogAcceptFilter<ILoggingEvent>());
-    MDCBasedDiscriminator mdcDiscriminator = new MDCBasedDiscriminator();
-    mdcDiscriminator.setContext(ctx);
-    mdcDiscriminator.setKey(MDC_LOG_PATH);
-    mdcDiscriminator.setDefaultValue("error");
-    mdcDiscriminator.start();
-    siftingAppender.setContext(ctx);
-    siftingAppender.setDiscriminator(mdcDiscriminator);
-    siftingAppender.setAppenderFactory(new CeFileAppenderFactory(logsDir));
-    siftingAppender.setName(CE_APPENDER_NAME);
-    siftingAppender.setTimeout(new Duration(TIMEOUT_2_MINUTES));
-    siftingAppender.start();
-    return siftingAppender;
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/log/LogFileRef.java b/server/sonar-server/src/main/java/org/sonar/server/computation/log/LogFileRef.java
deleted file mode 100644 (file)
index 141eeba..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.util.regex.Pattern;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.server.computation.queue.CeTask;
-
-import static java.lang.String.format;
-
-public class LogFileRef {
-
-  // restricted white-list for now
-  private static final Pattern FILENAME_PATTERN = Pattern.compile("^[\\w\\-]*$");
-  private final String taskType;
-  private final String taskUuid;
-
-  @CheckForNull
-  private final String componentUuid;
-
-  public LogFileRef(String taskType, String taskUuid, @Nullable String componentUuid) {
-    this.taskType = requireValidFilename(taskType);
-    this.taskUuid = requireValidFilename(taskUuid);
-    this.componentUuid = requireValidFilename(componentUuid);
-  }
-
-  @VisibleForTesting
-  @CheckForNull
-  static String requireValidFilename(@Nullable String s) {
-    if (s != null && !FILENAME_PATTERN.matcher(s).matches()) {
-      throw new IllegalArgumentException(String.format("'%s' is not a valid filename for Compute Engine logs", s));
-    }
-    return s;
-  }
-
-  /**
-   * Path relative to the CE logs directory
-   */
-  public String getRelativePath() {
-    if (componentUuid == null) {
-      return format("%s/%s.log", taskType, taskUuid);
-    }
-    return format("%s/%s/%s.log", taskType, componentUuid, taskUuid);
-  }
-
-  @Override
-  public boolean equals(@Nullable Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    LogFileRef that = (LogFileRef) o;
-    if (!taskType.equals(that.taskType)) {
-      return false;
-    }
-    if (!taskUuid.equals(that.taskUuid)) {
-      return false;
-    }
-    return componentUuid == null ? (that.componentUuid == null) : componentUuid.equals(that.componentUuid);
-
-  }
-
-  @Override
-  public int hashCode() {
-    int result = taskType.hashCode();
-    result = 31 * result + taskUuid.hashCode();
-    result = 31 * result + (componentUuid != null ? componentUuid.hashCode() : 0);
-    return result;
-  }
-
-  public static LogFileRef from(CeActivityDto dto) {
-    return new LogFileRef(dto.getTaskType(), dto.getUuid(), dto.getComponentUuid());
-  }
-
-  public static LogFileRef from(CeQueueDto dto) {
-    return new LogFileRef(dto.getTaskType(), dto.getUuid(), dto.getComponentUuid());
-  }
-
-  public static LogFileRef from(CeTask task) {
-    return new LogFileRef(task.getType(), task.getUuid(), task.getComponentUuid());
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/log/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/log/package-info.java
deleted file mode 100644 (file)
index f5eb150..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.computation.log;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatus.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatus.java
deleted file mode 100644 (file)
index 0dcab1a..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.monitoring;
-
-public interface CEQueueStatus {
-
-  /**
-   * Sets the count of reports waiting for processing at startup. This method can be called only once.
-   *
-   * @param initialPendingCount the count of reports, must be {@literal >=} 0
-   *
-   * @return the new count of batch reports waiting for processing (which is the same as the argument)
-   *
-   * @throws IllegalStateException if this method has already been called or is called after {@link #getPendingCount()}
-   * @throws IllegalArgumentException if the argument is {@literal <} 0
-   */
-  long initPendingCount(long initialPendingCount);
-
-  /**
-   * Adds 1 to the count of received batch reports and 1 to the count of batch reports waiting for processing.
-   * <p>
-   * Calling this method is equivalent to calling {@link #addReceived(long)} with {@code 1} as argument but will
-   * trigger no parameter check. So, it can be faster.
-   * </p>
-   *
-   * @return the new count of received batch reports
-   *
-   * @see #getReceivedCount()
-   * @see #getPendingCount()
-   *
-   * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
-   */
-  long addReceived();
-
-  /**
-   * Adds {@code numberOfReceived} to the count of received batch reports and {@code numberOfReceived} to the count of
-   * batch reports waiting for processing.
-   *
-   * @return the new count of received batch reports
-   *
-   * @see #getReceivedCount()
-   * @see #getPendingCount()
-   *
-   * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
-   * @throws IllegalArgumentException if {@code numberOfReceived} is less or equal to 0
-   */
-  long addReceived(long numberOfReceived);
-
-  /**
-   * Adds 1 to the count of batch reports under processing and removes 1 from the count of batch reports waiting for
-   * processing.
-   *
-   * @return the new count of batch reports under processing
-   *
-   * @see #getInProgressCount()
-   * @see #getPendingCount()
-   *
-   * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
-   */
-  long addInProgress();
-
-  /**
-   * Adds 1 to the count of batch reports which processing ended successfully and removes 1 from the count of batch
-   * reports under processing. Adds the specified time to the processing time counter.
-   *
-   * @param processingTime duration of processing in ms
-   *
-   * @return the new count of batch reports which processing ended successfully
-   *
-   * @see #getSuccessCount()
-   * @see #getInProgressCount()
-   *
-   * @throws IllegalArgumentException if processingTime is < 0
-   */
-  long addSuccess(long processingTime);
-
-  /**
-   * Adds 1 to the count of batch reports which processing ended with an error and removes 1 from the count of batch
-   * reports under processing. Adds the specified time to the processing time counter.
-   *
-   * @param processingTime duration of processing in ms
-   *
-   * @return the new count of batch reports which processing ended with an error
-   *
-   * @see #getErrorCount()
-   * @see #getInProgressCount()
-   *
-   * @throws IllegalArgumentException if processingTime is < 0
-   */
-  long addError(long processingTime);
-
-  /**
-   * Count of received batch reports since instance startup
-   */
-  long getReceivedCount();
-
-  /**
-   * Count of batch reports waiting for processing since startup, including reports received before instance startup.
-   */
-  long getPendingCount();
-
-  /**
-   * Count of batch reports under processing.
-   */
-  long getInProgressCount();
-
-  /**
-   * Count of batch reports which processing ended with an error since instance startup.
-   */
-  long getErrorCount();
-
-  /**
-   * Count of batch reports which processing ended successfully since instance startup.
-   */
-  long getSuccessCount();
-
-  /**
-   * Time spent processing batch reports since startup.
-   */
-  long getProcessingTime();
-}
index e786e5997eba018faac812df855e5bef6cb7f56f..d9e61e25e15f30fb757742a82825694ebca37762 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.computation.monitoring;
 
 import java.util.concurrent.atomic.AtomicLong;
+import org.sonar.ce.monitoring.CEQueueStatus;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
index 4820eb964a7fc6e4300fc4d083c0d54a83e0463f..94d2322dc1c9b209db2c246e617d172a5664409d 100644 (file)
@@ -20,8 +20,9 @@
 package org.sonar.server.computation.monitoring;
 
 import java.util.LinkedHashMap;
+import org.sonar.ce.monitoring.CEQueueStatus;
 import org.sonar.server.computation.configuration.CeConfiguration;
-import org.sonar.server.computation.queue.CeQueue;
+import org.sonar.ce.queue.CeQueue;
 import org.sonar.server.platform.monitoring.BaseMonitorMBean;
 
 public class ComputeEngineQueueMonitor extends BaseMonitorMBean implements ComputeEngineQueueMonitorMBean {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/property/CePropertyDefinitions.java b/server/sonar-server/src/main/java/org/sonar/server/computation/property/CePropertyDefinitions.java
deleted file mode 100644 (file)
index dcb94aa..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.property;
-
-import java.util.List;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.PropertyType;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.server.computation.log.CeLogging;
-
-import static java.util.Arrays.asList;
-
-public class CePropertyDefinitions {
-  private CePropertyDefinitions() {
-    // only statics
-  }
-
-  public static List<PropertyDefinition> all() {
-    return asList(
-      PropertyDefinition.builder(CeLogging.MAX_LOGS_PROPERTY)
-        .name("Compute Engine Log Retention")
-        .description("Number of tasks to keep logs for a given project. Once the number of logs exceeds this limit, oldest logs are purged.")
-        .type(PropertyType.INTEGER)
-        .defaultValue("10")
-        .category(CoreProperties.CATEGORY_GENERAL)
-        .build());
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/property/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/property/package-info.java
deleted file mode 100644 (file)
index a789ce7..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.computation.property;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueue.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueue.java
deleted file mode 100644 (file)
index dfedb00..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import com.google.common.base.Optional;
-import java.util.Collection;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.sonar.db.ce.CeActivityDto;
-
-/**
- * Queue of pending Compute Engine tasks. Both producer and consumer actions
- * are implemented.
- * <p>
- *   This class is decoupled from the regular task type {@link org.sonar.db.ce.CeTaskTypes#REPORT}.
- * </p>
- */
-public interface CeQueue {
-  /**
-   * Build an instance of {@link CeTaskSubmit} required for {@link #submit(CeTaskSubmit)}. It allows
-   * to enforce that task ids are generated by the queue. It's used also for having access
-   * to the id before submitting the task to the queue.
-   */
-  CeTaskSubmit.Builder prepareSubmit();
-
-  /**
-   * Submits a task to the queue. The task is processed asynchronously.
-   * <p>
-   * This method is equivalent to calling {@code massSubmit(Collections.singletonList(submission))}.
-   * </p>
-   *
-   * @throws IllegalStateException If submits are paused (see {@link #isSubmitPaused()})
-   */
-  CeTask submit(CeTaskSubmit submission);
-
-  /**
-   * Submits multiple tasks to the queue at once. All tasks are processed asynchronously.
-   * <p>
-   * This method will perform significantly better that calling {@link #submit(CeTaskSubmit)} in a loop.
-   * </p>
-   *
-   * @throws IllegalStateException If submits are paused (see {@link #isSubmitPaused()})
-   */
-  List<CeTask> massSubmit(Collection<CeTaskSubmit> submissions);
-
-  /**
-   * Peek the oldest task in status {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}.
-   * The task status is changed to {@link org.sonar.db.ce.CeQueueDto.Status#IN_PROGRESS}.
-   * Does not return anything if the queue is paused (see {@link #isPeekPaused()}.
-   *
-   * <p>Only a single task can be peeked by project.</p>
-   *
-   * <p>An unchecked exception may be thrown on technical errors (db connection, ...).</p>
-   */
-  Optional<CeTask> peek();
-
-  /**
-   * Cancels a task in status {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}. An unchecked
-   * exception is thrown if the status is not {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}.
-   * The method does nothing and returns {@code false} if the task does not exist.
-   *
-   * @return true if the task exists and is successfully canceled.
-   */
-  boolean cancel(String taskUuid);
-
-  /**
-   * Removes all the tasks from the queue, whatever their status. They are marked
-   * as {@link org.sonar.db.ce.CeActivityDto.Status#CANCELED} in past activity.
-   * This method can NOT be called when  workers are being executed, as in progress
-   * tasks can't be killed.
-   *
-   * @return the number of canceled tasks
-   */
-  int clear();
-
-  /**
-   * Similar as {@link #clear()}, except that the tasks with status
-   * {@link org.sonar.db.ce.CeQueueDto.Status#IN_PROGRESS} are ignored. This method
-   * can be called at runtime, even if workers are being executed.
-   *
-   * @return the number of canceled tasks
-   */
-  int cancelAll();
-
-  /**
-   * Removes a task from the queue and registers it to past activities. This method
-   * is called by Compute Engine workers when task is processed and can include an option {@link CeTaskResult} object.
-   *
-   * @throws IllegalStateException if the task does not exist in the queue
-   */
-  void remove(CeTask task, CeActivityDto.Status status, @Nullable CeTaskResult taskResult);
-
-  void pauseSubmit();
-
-  void resumeSubmit();
-
-  boolean isSubmitPaused();
-
-  void pausePeek();
-
-  void resumePeek();
-
-  boolean isPeekPaused();
-}
index 4f725e38d4ff519b7be37c9c1c58fecb7079ae78..339eb7127ca06a149b37f22ab95acb12b7e96565 100644 (file)
@@ -25,11 +25,11 @@ import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.queue.report.ReportFiles;
 
 /**
  * Cleans-up the Compute Engine queue and resets the JMX counters.
@@ -43,9 +43,9 @@ public class CeQueueCleaner {
   private final DbClient dbClient;
   private final ServerUpgradeStatus serverUpgradeStatus;
   private final ReportFiles reportFiles;
-  private final CeQueueImpl queue;
+  private final InternalCeQueue queue;
 
-  public CeQueueCleaner(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, ReportFiles reportFiles, CeQueueImpl queue) {
+  public CeQueueCleaner(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, ReportFiles reportFiles, InternalCeQueue queue) {
     this.dbClient = dbClient;
     this.serverUpgradeStatus = serverUpgradeStatus;
     this.reportFiles = reportFiles;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueImpl.java
deleted file mode 100644 (file)
index 5d4cc55..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Predicates.notNull;
-import static com.google.common.collect.FluentIterable.from;
-import static java.lang.String.format;
-import static org.sonar.db.component.ComponentDtoFunctions.toUuid;
-
-@ServerSide
-public class CeQueueImpl implements CeQueue {
-
-  private final System2 system2;
-  private final DbClient dbClient;
-  private final UuidFactory uuidFactory;
-  private final CEQueueStatus queueStatus;
-  private final CeQueueListener[] listeners;
-
-  // state
-  private AtomicBoolean submitPaused = new AtomicBoolean(false);
-  private AtomicBoolean peekPaused = new AtomicBoolean(false);
-
-  public CeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory,
-    CEQueueStatus queueStatus, CeQueueListener[] listeners) {
-    this.system2 = system2;
-    this.dbClient = dbClient;
-    this.uuidFactory = uuidFactory;
-    this.queueStatus = queueStatus;
-    this.listeners = listeners;
-  }
-
-  @Override
-  public CeTaskSubmit.Builder prepareSubmit() {
-    return new CeTaskSubmit.Builder(uuidFactory.create());
-  }
-
-  @Override
-  public CeTask submit(CeTaskSubmit submission) {
-    checkState(!submitPaused.get(), "Compute Engine does not currently accept new tasks");
-
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      CeQueueDto dto = new CeTaskSubmitToInsertedCeQueueDto(dbSession, dbClient).apply(submission);
-      CeTask task = loadTask(dbSession, dto);
-      dbSession.commit();
-      queueStatus.addReceived();
-      return task;
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  @Override
-  public List<CeTask> massSubmit(Collection<CeTaskSubmit> submissions) {
-    checkState(!submitPaused.get(), "Compute Engine does not currently accept new tasks");
-    if (submissions.isEmpty()) {
-      return Collections.emptyList();
-    }
-
-    DbSession dbSession = dbClient.openSession(true);
-    try {
-      List<CeQueueDto> ceQueueDtos = from(submissions)
-        .transform(new CeTaskSubmitToInsertedCeQueueDto(dbSession, dbClient))
-        .toList();
-      List<CeTask> tasks = loadTasks(dbSession, ceQueueDtos);
-      dbSession.commit();
-      queueStatus.addReceived(tasks.size());
-      return tasks;
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  @Override
-  public Optional<CeTask> peek() {
-    if (peekPaused.get()) {
-      return Optional.absent();
-    }
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      Optional<CeQueueDto> dto = dbClient.ceQueueDao().peek(dbSession);
-      CeTask task = null;
-      if (dto.isPresent()) {
-        task = loadTask(dbSession, dto.get());
-        queueStatus.addInProgress();
-      }
-      return Optional.fromNullable(task);
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  private CeTask loadTask(DbSession dbSession, CeQueueDto dto) {
-    if (dto.getComponentUuid() == null) {
-      return new CeQueueDtoToCeTask().apply(dto);
-    }
-    Optional<ComponentDto> componentDto = dbClient.componentDao().selectByUuid(dbSession, dto.getComponentUuid());
-    if (componentDto.isPresent()) {
-      return new CeQueueDtoToCeTask(ImmutableMap.of(dto.getComponentUuid(), componentDto.get())).apply(dto);
-    }
-    return new CeQueueDtoToCeTask().apply(dto);
-  }
-
-  private List<CeTask> loadTasks(DbSession dbSession, List<CeQueueDto> dtos) {
-    Set<String> componentUuids = from(dtos)
-      .transform(CeQueueDtoToComponentUuid.INSTANCE)
-      .filter(notNull())
-      .toSet();
-    Map<String, ComponentDto> componentDtoByUuid = from(dbClient.componentDao()
-      .selectByUuids(dbSession, componentUuids))
-      .uniqueIndex(toUuid());
-
-    return from(dtos)
-      .transform(new CeQueueDtoToCeTask(componentDtoByUuid))
-      .toList();
-  }
-
-  @Override
-  public boolean cancel(String taskUuid) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
-      if (queueDto.isPresent()) {
-        checkState(CeQueueDto.Status.PENDING.equals(queueDto.get().getStatus()), "Task is in progress and can't be canceled [uuid=%s]", taskUuid);
-        cancel(dbSession, queueDto.get());
-        return true;
-      }
-      return false;
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  void cancel(DbSession dbSession, CeQueueDto q) {
-    CeTask task = loadTask(dbSession, q);
-    CeActivityDto activityDto = new CeActivityDto(q);
-    activityDto.setStatus(CeActivityDto.Status.CANCELED);
-    remove(dbSession, task, q, activityDto);
-  }
-
-  @Override
-  public int clear() {
-    return cancelAll(true);
-  }
-
-  @Override
-  public int cancelAll() {
-    return cancelAll(false);
-  }
-
-  private int cancelAll(boolean includeInProgress) {
-    int count = 0;
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      for (CeQueueDto queueDto : dbClient.ceQueueDao().selectAllInAscOrder(dbSession)) {
-        if (includeInProgress || !queueDto.getStatus().equals(CeQueueDto.Status.IN_PROGRESS)) {
-          cancel(dbSession, queueDto);
-          count++;
-        }
-      }
-      return count;
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  @Override
-  public void remove(CeTask task, CeActivityDto.Status status, CeTaskResult taskResult) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, task.getUuid());
-      if (!queueDto.isPresent()) {
-        throw new IllegalStateException(format("Task does not exist anymore: %s", task));
-      }
-      CeActivityDto activityDto = new CeActivityDto(queueDto.get());
-      activityDto.setStatus(status);
-      updateQueueStatus(status, activityDto);
-      updateTaskResult(activityDto, taskResult);
-      remove(dbSession, task, queueDto.get(), activityDto);
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  private static void updateTaskResult(CeActivityDto activityDto, @Nullable CeTaskResult taskResult) {
-    if (taskResult != null) {
-      Long snapshotId = taskResult.getSnapshotId();
-      if (snapshotId != null) {
-        activityDto.setSnapshotId(snapshotId);
-      }
-    }
-  }
-
-  private void updateQueueStatus(CeActivityDto.Status status, CeActivityDto activityDto) {
-    Long startedAt = activityDto.getStartedAt();
-    if (startedAt == null) {
-      return;
-    }
-    activityDto.setExecutedAt(system2.now());
-    long executionTime = activityDto.getExecutedAt() - startedAt;
-    activityDto.setExecutionTimeMs(executionTime);
-    if (status == CeActivityDto.Status.SUCCESS) {
-      queueStatus.addSuccess(executionTime);
-    } else {
-      queueStatus.addError(executionTime);
-    }
-  }
-
-  private void remove(DbSession dbSession, CeTask task, CeQueueDto queueDto, CeActivityDto activityDto) {
-    dbClient.ceActivityDao().insert(dbSession, activityDto);
-    dbClient.ceQueueDao().deleteByUuid(dbSession, queueDto.getUuid());
-    dbSession.commit();
-    for (CeQueueListener listener : listeners) {
-      listener.onRemoved(task, activityDto.getStatus());
-    }
-  }
-
-  @Override
-  public void pauseSubmit() {
-    this.submitPaused.set(true);
-  }
-
-  @Override
-  public void resumeSubmit() {
-    this.submitPaused.set(false);
-  }
-
-  @Override
-  public boolean isSubmitPaused() {
-    return submitPaused.get();
-  }
-
-  @Override
-  public void pausePeek() {
-    this.peekPaused.set(true);
-  }
-
-  @Override
-  public void resumePeek() {
-    this.peekPaused.set(false);
-  }
-
-  @Override
-  public boolean isPeekPaused() {
-    return peekPaused.get();
-  }
-
-  private static class CeQueueDtoToCeTask implements Function<CeQueueDto, CeTask> {
-    private final Map<String, ComponentDto> componentDtoByUuid;
-
-    public CeQueueDtoToCeTask() {
-      this.componentDtoByUuid = Collections.emptyMap();
-    }
-
-    public CeQueueDtoToCeTask(Map<String, ComponentDto> componentDtoByUuid) {
-      this.componentDtoByUuid = componentDtoByUuid;
-    }
-
-    @Override
-    @Nonnull
-    public CeTask apply(@Nonnull CeQueueDto dto) {
-      CeTask.Builder builder = new CeTask.Builder();
-      builder.setUuid(dto.getUuid());
-      builder.setType(dto.getTaskType());
-      builder.setSubmitterLogin(dto.getSubmitterLogin());
-      String componentUuid = dto.getComponentUuid();
-      if (componentUuid != null) {
-        builder.setComponentUuid(componentUuid);
-        ComponentDto component = componentDtoByUuid.get(componentUuid);
-        if (component != null) {
-          builder.setComponentKey(component.getKey());
-          builder.setComponentName(component.name());
-        }
-      }
-      return builder.build();
-    }
-  }
-
-  private static class CeTaskSubmitToInsertedCeQueueDto implements Function<CeTaskSubmit, CeQueueDto> {
-    private final DbSession dbSession;
-    private final DbClient dbClient;
-
-    public CeTaskSubmitToInsertedCeQueueDto(DbSession dbSession, DbClient dbClient) {
-      this.dbSession = dbSession;
-      this.dbClient = dbClient;
-    }
-
-    @Override
-    @Nonnull
-    public CeQueueDto apply(@Nonnull CeTaskSubmit submission) {
-      CeQueueDto dto = new CeQueueDto();
-      dto.setUuid(submission.getUuid());
-      dto.setTaskType(submission.getType());
-      dto.setComponentUuid(submission.getComponentUuid());
-      dto.setStatus(CeQueueDto.Status.PENDING);
-      dto.setSubmitterLogin(submission.getSubmitterLogin());
-      dto.setStartedAt(null);
-      dbClient.ceQueueDao().insert(dbSession, dto);
-      return dto;
-    }
-  }
-
-  private enum CeQueueDtoToComponentUuid implements Function<CeQueueDto, String> {
-    INSTANCE;
-
-    @Override
-    @Nullable
-    public String apply(@Nonnull CeQueueDto input) {
-      return input.getComponentUuid();
-    }
-  }
-}
index 63ec0786528c0ee9649e7ea6c3a44b17da7a8946..b6f277f8f8f34ebc22f36bf4fbcf81080882a3cf 100644 (file)
@@ -24,7 +24,7 @@ import org.sonar.api.platform.ServerStartHandler;
 import org.sonar.api.server.ServerSide;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
+import org.sonar.ce.monitoring.CEQueueStatus;
 import org.sonar.server.computation.taskprocessor.CeProcessingScheduler;
 
 /**
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueListener.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueListener.java
deleted file mode 100644 (file)
index 3c837c9..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import org.sonar.db.ce.CeActivityDto;
-
-public interface CeQueueListener {
-
-  void onRemoved(CeTask task, CeActivityDto.Status status);
-
-}
index 4087720e41126cea614d916e1a98562e277ef4da..4be44d6936bdc7429356283ae2a0cc83a1b86b39 100644 (file)
  */
 package org.sonar.server.computation.queue;
 
+import org.sonar.server.computation.queue.report.CleanReportQueueListener;
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.core.platform.Module;
 import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
 import org.sonar.server.computation.monitoring.ComputeEngineQueueMonitor;
-import org.sonar.server.computation.queue.report.CleanReportQueueListener;
-import org.sonar.server.computation.queue.report.ReportFiles;
 
 public class CeQueueModule extends Module {
   @Override
   protected void configureModule() {
     add(
       // queue state
-      CeQueueImpl.class,
+      InternalCeQueueImpl.class,
 
       // queue monitoring
       CEQueueStatusImpl.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTask.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTask.java
deleted file mode 100644 (file)
index e81ec1a..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import com.google.common.base.Objects;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-
-import static com.google.common.base.Strings.emptyToNull;
-import static java.util.Objects.requireNonNull;
-
-@Immutable
-public class CeTask {
-
-  private final String type;
-  private final String uuid;
-  private final String componentUuid;
-  private final String componentKey;
-  private final String componentName;
-  private final String submitterLogin;
-
-  private CeTask(Builder builder) {
-    this.uuid = requireNonNull(emptyToNull(builder.uuid));
-    this.type = requireNonNull(emptyToNull(builder.type));
-    this.componentUuid = emptyToNull(builder.componentUuid);
-    this.componentKey = emptyToNull(builder.componentKey);
-    this.componentName = emptyToNull(builder.componentName);
-    this.submitterLogin = emptyToNull(builder.submitterLogin);
-  }
-
-  public String getUuid() {
-    return uuid;
-  }
-
-  public String getType() {
-    return type;
-  }
-
-  @CheckForNull
-  public String getComponentUuid() {
-    return componentUuid;
-  }
-
-  @CheckForNull
-  public String getComponentKey() {
-    return componentKey;
-  }
-
-  @CheckForNull
-  public String getComponentName() {
-    return componentName;
-  }
-
-  @CheckForNull
-  public String getSubmitterLogin() {
-    return submitterLogin;
-  }
-
-  @Override
-  public String toString() {
-    return Objects.toStringHelper(this)
-      .add("componentUuid", componentUuid)
-      .add("uuid", uuid)
-      .add("type", type)
-      .add("submitterLogin", submitterLogin)
-      .toString();
-  }
-
-  @Override
-  public boolean equals(@Nullable Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    CeTask ceTask = (CeTask) o;
-    return uuid.equals(ceTask.uuid);
-  }
-
-  @Override
-  public int hashCode() {
-    return uuid.hashCode();
-  }
-
-  public static final class Builder {
-    private String uuid;
-    private String type;
-    private String componentUuid;
-    private String componentKey;
-    private String componentName;
-    private String submitterLogin;
-
-    public Builder setUuid(String uuid) {
-      this.uuid = uuid;
-      return this;
-    }
-
-    public Builder setType(String type) {
-      this.type = type;
-      return this;
-    }
-
-    public Builder setComponentUuid(String componentUuid) {
-      this.componentUuid = componentUuid;
-      return this;
-    }
-
-    public Builder setComponentKey(@Nullable String s) {
-      this.componentKey = s;
-      return this;
-    }
-
-    public Builder setComponentName(@Nullable String s) {
-      this.componentName = s;
-      return this;
-    }
-
-    public Builder setSubmitterLogin(@Nullable String s) {
-      this.submitterLogin = s;
-      return this;
-    }
-
-    public CeTask build() {
-      return new CeTask(this);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTaskResult.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTaskResult.java
deleted file mode 100644 (file)
index 6035bb4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import javax.annotation.CheckForNull;
-
-/**
- * Represents the result of the processing of a {@link CeTask}.
- *
- * @see {@link org.sonar.server.computation.taskprocessor.CeTaskProcessor#process(CeTask)}
- */
-public interface CeTaskResult {
-  /**
-   * The id of the snapshot created, if any, for the Component in {@link CeTask}
-   */
-  @CheckForNull
-  Long getSnapshotId();
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTaskSubmit.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeTaskSubmit.java
deleted file mode 100644 (file)
index 0d621eb..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import java.util.Objects;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-
-import static com.google.common.base.Strings.emptyToNull;
-
-@Immutable
-public final class CeTaskSubmit {
-
-  private final String uuid;
-  private final String type;
-  private final String componentUuid;
-  private final String submitterLogin;
-
-  private CeTaskSubmit(Builder builder) {
-    this.uuid = Objects.requireNonNull(emptyToNull(builder.uuid));
-    this.type = Objects.requireNonNull(emptyToNull(builder.type));
-    this.componentUuid = emptyToNull(builder.componentUuid);
-    this.submitterLogin = emptyToNull(builder.submitterLogin);
-  }
-
-  public String getType() {
-    return type;
-  }
-
-  public String getUuid() {
-    return uuid;
-  }
-
-  @CheckForNull
-  public String getComponentUuid() {
-    return componentUuid;
-  }
-
-  @CheckForNull
-  public String getSubmitterLogin() {
-    return submitterLogin;
-  }
-
-  public static final class Builder {
-    private final String uuid;
-    private String type;
-    private String componentUuid;
-    private String submitterLogin;
-
-    public Builder(String uuid) {
-      this.uuid = uuid;
-    }
-
-    public String getUuid() {
-      return uuid;
-    }
-
-    public Builder setType(String s) {
-      this.type = s;
-      return this;
-    }
-
-    public Builder setComponentUuid(@Nullable String s) {
-      this.componentUuid = s;
-      return this;
-    }
-
-    public Builder setSubmitterLogin(@Nullable String s) {
-      this.submitterLogin = s;
-      return this;
-    }
-
-    public CeTaskSubmit build() {
-      return new CeTaskSubmit(this);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueue.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueue.java
new file mode 100644 (file)
index 0000000..b0526f4
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.computation.queue;
+
+import com.google.common.base.Optional;
+import javax.annotation.Nullable;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+
+/**
+ * Queue of pending Compute Engine tasks. Both producer and consumer actions
+ * are implemented.
+ * <p>
+ *   This class is decoupled from the regular task type {@link org.sonar.db.ce.CeTaskTypes#REPORT}.
+ * </p>
+ */
+public interface InternalCeQueue extends CeQueue {
+
+  /**
+   * Peek the oldest task in status {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}.
+   * The task status is changed to {@link org.sonar.db.ce.CeQueueDto.Status#IN_PROGRESS}.
+   * Does not return anything if the queue is paused (see {@link #isPeekPaused()}.
+   *
+   * <p>Only a single task can be peeked by project.</p>
+   *
+   * <p>An unchecked exception may be thrown on technical errors (db connection, ...).</p>
+   */
+  Optional<CeTask> peek();
+
+  /**
+   * Removes all the tasks from the queue, whatever their status. They are marked
+   * as {@link CeActivityDto.Status#CANCELED} in past activity.
+   * This method can NOT be called when  workers are being executed, as in progress
+   * tasks can't be killed.
+   *
+   * @return the number of canceled tasks
+   */
+  int clear();
+
+  /**
+   * Removes a task from the queue and registers it to past activities. This method
+   * is called by Compute Engine workers when task is processed and can include an option {@link CeTaskResult} object.
+   *
+   * @throws IllegalStateException if the task does not exist in the queue
+   */
+  void remove(CeTask task, CeActivityDto.Status status, @Nullable CeTaskResult taskResult);
+
+  void cancel(DbSession dbSession, CeQueueDto ceQueueDto);
+
+  void pausePeek();
+
+  void resumePeek();
+
+  boolean isPeekPaused();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java
new file mode 100644 (file)
index 0000000..d8b10f5
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.computation.queue;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.System2;
+import org.sonar.ce.queue.CeQueueImpl;
+import org.sonar.ce.queue.CeQueueListener;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.ce.monitoring.CEQueueStatus;
+
+import static java.lang.String.format;
+
+@ServerSide
+public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue {
+
+  private final System2 system2;
+  private final DbClient dbClient;
+  private final CEQueueStatus queueStatus;
+
+  // state
+  private AtomicBoolean peekPaused = new AtomicBoolean(false);
+
+  public InternalCeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory,
+    CEQueueStatus queueStatus, CeQueueListener[] listeners) {
+    super(dbClient, uuidFactory, queueStatus, listeners);
+    this.system2 = system2;
+    this.dbClient = dbClient;
+    this.queueStatus = queueStatus;
+  }
+
+  @Override
+  public Optional<CeTask> peek() {
+    if (peekPaused.get()) {
+      return Optional.absent();
+    }
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> dto = dbClient.ceQueueDao().peek(dbSession);
+      CeTask task = null;
+      if (dto.isPresent()) {
+        task = loadTask(dbSession, dto.get());
+        queueStatus.addInProgress();
+      }
+      return Optional.fromNullable(task);
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  @Override
+  public int clear() {
+    return cancelAll(true);
+  }
+
+  @Override
+  public void remove(CeTask task, CeActivityDto.Status status, CeTaskResult taskResult) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, task.getUuid());
+      if (!queueDto.isPresent()) {
+        throw new IllegalStateException(format("Task does not exist anymore: %s", task));
+      }
+      CeActivityDto activityDto = new CeActivityDto(queueDto.get());
+      activityDto.setStatus(status);
+      updateQueueStatus(status, activityDto);
+      updateTaskResult(activityDto, taskResult);
+      remove(dbSession, task, queueDto.get(), activityDto);
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private static void updateTaskResult(CeActivityDto activityDto, @Nullable CeTaskResult taskResult) {
+    if (taskResult != null) {
+      Long snapshotId = taskResult.getSnapshotId();
+      if (snapshotId != null) {
+        activityDto.setSnapshotId(snapshotId);
+      }
+    }
+  }
+
+  private void updateQueueStatus(CeActivityDto.Status status, CeActivityDto activityDto) {
+    Long startedAt = activityDto.getStartedAt();
+    if (startedAt == null) {
+      return;
+    }
+    activityDto.setExecutedAt(system2.now());
+    long executionTime = activityDto.getExecutedAt() - startedAt;
+    activityDto.setExecutionTimeMs(executionTime);
+    if (status == CeActivityDto.Status.SUCCESS) {
+      queueStatus.addSuccess(executionTime);
+    } else {
+      queueStatus.addError(executionTime);
+    }
+  }
+
+  @Override
+  public void cancel(DbSession dbSession, CeQueueDto ceQueueDto) {
+    cancelImpl(dbSession, ceQueueDto);
+  }
+
+  @Override
+  public void pausePeek() {
+    this.peekPaused.set(true);
+  }
+
+  @Override
+  public void resumePeek() {
+    this.peekPaused.set(false);
+  }
+
+  @Override
+  public boolean isPeekPaused() {
+    return peekPaused.get();
+  }
+
+}
index a7df49284f5934438eabfe82c4bf65d1d2fd775f..690fc23759a7e6a92891cceac6e5c32935e04352 100644 (file)
@@ -30,8 +30,8 @@ import org.sonar.api.utils.log.Loggers;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.ce.CeActivityDto;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
 
 @ServerSide
 public class PurgeCeActivities implements ServerStartHandler {
index ceca86aedd007b5c9e5e80737b7ef9bcb093e36c..e8a1d63c9179a0bc4dcf3085fddb0a3e4a4006f6 100644 (file)
  */
 package org.sonar.server.computation.queue.report;
 
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.db.ce.CeActivityDto;
-import org.sonar.server.computation.queue.CeQueueListener;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeQueueListener;
+import org.sonar.ce.queue.CeTask;
 
 public class CleanReportQueueListener implements CeQueueListener {
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java
deleted file mode 100644 (file)
index 1bc74ab..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue.report;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.config.Settings;
-import org.sonar.api.server.ServerSide;
-import org.sonar.process.ProcessProperties;
-
-import static java.lang.String.format;
-
-@ServerSide
-public class ReportFiles {
-
-  private static final String ZIP_EXTENSION = "zip";
-
-  private final Settings settings;
-
-  public ReportFiles(Settings settings) {
-    this.settings = settings;
-  }
-
-  public void save(String taskUuid, InputStream reportInput) {
-    File file = fileForUuid(taskUuid);
-    try {
-      FileUtils.copyInputStreamToFile(reportInput, file);
-    } catch (Exception e) {
-      org.sonar.core.util.FileUtils.deleteQuietly(file);
-      IOUtils.closeQuietly(reportInput);
-      throw new IllegalStateException(format("Fail to copy report to file: %s", file.getAbsolutePath()), e);
-    }
-  }
-
-  public void deleteIfExists(String taskUuid) {
-    org.sonar.core.util.FileUtils.deleteQuietly(fileForUuid(taskUuid));
-  }
-
-  public void deleteAll() {
-    File dir = reportDir();
-    if (dir.exists()) {
-      try {
-        org.sonar.core.util.FileUtils.cleanDirectory(dir);
-      } catch (Exception e) {
-        throw new IllegalStateException(format("Fail to clean directory: %s", dir.getAbsolutePath()), e);
-      }
-    }
-  }
-
-  private File reportDir() {
-    return new File(settings.getString(ProcessProperties.PATH_DATA), "ce/reports");
-  }
-
-  /**
-   * The analysis report to be processed. Can't be null
-   * but may no exist on file system.
-   */
-  public File fileForUuid(String taskUuid) {
-    return new File(reportDir(), format("%s.%s", taskUuid, ZIP_EXTENSION));
-  }
-
-  public List<String> listUuids() {
-    List<String> uuids = new ArrayList<>();
-    File dir = reportDir();
-    if (dir.exists()) {
-      Collection<File> files = FileUtils.listFiles(dir, new String[]{ZIP_EXTENSION}, false);
-      for (File file : files) {
-        uuids.add(FilenameUtils.getBaseName(file.getName()));
-      }
-    }
-    return uuids;
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportSubmitter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportSubmitter.java
deleted file mode 100644 (file)
index 5e2ec49..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue.report;
-
-import java.io.InputStream;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.server.ServerSide;
-import org.sonar.core.component.ComponentKeys;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.server.component.ComponentService;
-import org.sonar.server.component.NewComponent;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskSubmit;
-import org.sonar.server.permission.PermissionService;
-import org.sonar.server.user.UserSession;
-
-import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
-
-@ServerSide
-public class ReportSubmitter {
-
-  private final CeQueue queue;
-  private final UserSession userSession;
-  private final ReportFiles reportFiles;
-  private final ComponentService componentService;
-  private final PermissionService permissionService;
-
-  public ReportSubmitter(CeQueue queue, UserSession userSession, ReportFiles reportFiles,
-    ComponentService componentService, PermissionService permissionService) {
-    this.queue = queue;
-    this.userSession = userSession;
-    this.reportFiles = reportFiles;
-    this.componentService = componentService;
-    this.permissionService = permissionService;
-  }
-
-  public CeTask submit(String projectKey, @Nullable String projectBranch, @Nullable String projectName, InputStream reportInput) {
-    String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch);
-    ComponentDto project = componentService.getNullableByKey(effectiveProjectKey);
-    if (project == null) {
-      // the project does not exist -> require global permission
-      userSession.checkPermission(SCAN_EXECUTION);
-
-      // the project does not exist -> requires to provision it
-      NewComponent newProject = new NewComponent(projectKey, StringUtils.defaultIfBlank(projectName, projectKey));
-      newProject.setBranch(projectBranch);
-      newProject.setQualifier(Qualifiers.PROJECT);
-      // no need to verify the permission "provisioning" as it's already handled by componentService
-      project = componentService.create(newProject);
-      permissionService.applyDefaultPermissionTemplate(project.getKey());
-    } else {
-      // the project exists -> require global or project permission
-      userSession.checkComponentPermission(SCAN_EXECUTION, projectKey);
-    }
-
-    // the report file must be saved before submitting the task
-    CeTaskSubmit.Builder submit = queue.prepareSubmit();
-    reportFiles.save(submit.getUuid(), reportInput);
-
-    submit.setType(CeTaskTypes.REPORT);
-    submit.setComponentUuid(project.uuid());
-    submit.setSubmitterLogin(userSession.getLogin());
-    return queue.submit(submit.build());
-  }
-}
index 26ebaba65a04b364eb5f0cb0098e7667544f40a7..959926289ef00de3c2bd3f53ea07440ecab7a1a1 100644 (file)
@@ -26,8 +26,8 @@ import org.sonar.api.utils.TempFolder;
 import org.sonar.api.utils.ZipUtils;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.report.ReportFiles;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.server.computation.batch.MutableBatchReportDirectoryHolder;
 
 /**
index 53b7d7e106d9b498434e67ddf436c5d3a53b9337..d34e2c627f50d8745edad571dfbe74b0278907a6 100644 (file)
@@ -23,7 +23,7 @@ import org.sonar.api.utils.MessageException;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.server.computation.analysis.MutableAnalysisMetadataHolder;
 import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 
 import static java.lang.String.format;
 
index 7a52801b4a7757bdc5f456daecf7d6e44c45669f..656d96759d22b150b0397dac9e8c1b9955a77c45 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.computation.step;
 import javax.annotation.concurrent.Immutable;
 import org.sonar.server.computation.component.DbIdsRepository;
 import org.sonar.server.computation.component.TreeRootHolder;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
 import org.sonar.server.computation.taskprocessor.MutableTaskResultHolder;
 
 public class PublishTaskResultStep implements ComputationStep {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeTaskProcessor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/CeTaskProcessor.java
deleted file mode 100644 (file)
index 48fb7e0..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.taskprocessor;
-
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskResult;
-
-/**
- * This interface is used to provide the processing code for {@link CeTask}s of one or more type to be called by the
- * Compute Engine.
- */
-public interface CeTaskProcessor {
-
-  /**
-   * The {@link CeTask#getType()} for which this {@link CeTaskProcessor} provides the processing code.
-   * <p>
-   * The match of type is done using {@link String#equals(Object)} and if more than one {@link CeTaskProcessor} declares
-   * itself had handler for the same {@link CeTask#getType()}, an error will be raised at startup and startup will
-   * fail.
-   * </p>
-   * <p>
-   * If an empty {@link Set} is returned, the {@link CeTaskProcessor} will be ignored.
-   * </p>
-   */
-  Set<String> getHandledCeTaskTypes();
-
-  /**
-   * Calls the processing code for a specific {@link CeTask} which will optionally return a {@link CeTaskResult}
-   * holding information to be persisted in the processing history of the Compute Engine (currently the {@code CE_ACTIVITY} table).
-   * <p>
-   * The specified is guaranteed to be non {@code null} and its {@link CeTask#getType()} to be one of the values
-   * of {@link #getHandledCeTaskTypes()}.
-   * </p>
-   *
-   * @throws RuntimeException when thrown, it will be caught and logged by the Compute Engine and the processing of the
-   *         specified {@link CeTask} will be flagged as failed.
-   */
-  @CheckForNull
-  CeTaskResult process(CeTask task);
-}
index 42878bb65c831044a77bc1bb502bfe0c16ca1a7e..a59368765172df95b7966821751f8902a6fd5127 100644 (file)
@@ -20,7 +20,8 @@
 package org.sonar.server.computation.taskprocessor;
 
 import com.google.common.base.Optional;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
 
 public interface CeTaskProcessorRepository {
 
index 5451c765b8f3361534c4e8da1641025e19ba5e0f..b014847989c17adffe1e8ed2c533f2498c3295d2 100644 (file)
@@ -29,7 +29,8 @@ import com.google.common.collect.Multimap;
 import java.util.Collection;
 import java.util.Map;
 import javax.annotation.Nonnull;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.FluentIterable.from;
index 4c367beffe1ff9f6cb66f1c16dd9e3b79535a0e1..2f5760f7ac5544960c3b8b75f4cf9715103d3a7b 100644 (file)
@@ -20,8 +20,8 @@
 package org.sonar.server.computation.taskprocessor;
 
 import java.util.concurrent.Callable;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeTask;
 
 /**
  * Marker interface of the runnable in charge of polling the {@link CeQueue} and executing {@link CeTask}.
index 835ac3d6a8ca94a18130835fbca7e7a930a11c0b..b0c0e599b8830b884272fa4a42e95e8ae65cac64 100644 (file)
@@ -22,12 +22,14 @@ package org.sonar.server.computation.taskprocessor;
 import com.google.common.base.Optional;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
 import org.sonar.core.util.logs.Profiler;
 import org.sonar.db.ce.CeActivityDto;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.server.computation.queue.InternalCeQueue;
 
 import static java.lang.String.format;
 
@@ -35,11 +37,11 @@ public class CeWorkerCallableImpl implements CeWorkerCallable {
 
   private static final Logger LOG = Loggers.get(CeWorkerCallableImpl.class);
 
-  private final CeQueue queue;
+  private final InternalCeQueue queue;
   private final CeLogging ceLogging;
   private final CeTaskProcessorRepository taskProcessorRepository;
 
-  public CeWorkerCallableImpl(CeQueue queue, CeLogging ceLogging, CeTaskProcessorRepository taskProcessorRepository) {
+  public CeWorkerCallableImpl(InternalCeQueue queue, CeLogging ceLogging, CeTaskProcessorRepository taskProcessorRepository) {
     this.queue = queue;
     this.ceLogging = ceLogging;
     this.taskProcessorRepository = taskProcessorRepository;
index d27b9ec69d2f6e87ed836d62d584ebaa9ae567a2..4b3674184d5e67b73c83f9c7e55d81880515a15c 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.computation.taskprocessor;
 
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
 
 public interface MutableTaskResultHolder extends TaskResultHolder {
   /**
index 82121c9f78db9936991cca63178a803c3cac6ba8..aa1ce365b7127c8322b920ad83b55e358ec00c63 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.computation.taskprocessor;
 
 import javax.annotation.CheckForNull;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
index 905cdd6d490d031fbf737f5a6a658a8c0d4a72ec..793e00fa7e5990b59e4a3bc261cd66976b4c9bc4 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.computation.taskprocessor;
 
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
 
 public interface TaskResultHolder {
   /**
index a940f3be5a9d0f4f8323672b781c33e59f1752ac..22c5f350121f8c91e9b7858fb63e03f8a73e3aa2 100644 (file)
@@ -26,10 +26,10 @@ import org.sonar.core.platform.ComponentContainer;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.server.computation.container.ComputeEngineContainer;
 import org.sonar.server.computation.container.ContainerFactory;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
 import org.sonar.server.computation.step.ComputationStepExecutor;
-import org.sonar.server.computation.taskprocessor.CeTaskProcessor;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
 import org.sonar.server.computation.taskprocessor.TaskResultHolder;
 import org.sonar.server.devcockpit.DevCockpitBridge;
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java
deleted file mode 100644 (file)
index a318964..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.Paging;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.util.Uuids;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskQuery;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentDtoFunctions;
-import org.sonar.db.component.ComponentQuery;
-import org.sonar.server.computation.taskprocessor.CeTaskProcessor;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.Common;
-import org.sonarqube.ws.WsCe;
-import org.sonarqube.ws.WsCe.ActivityResponse;
-import org.sonarqube.ws.client.ce.ActivityWsRequest;
-
-import static java.lang.String.format;
-import static java.util.Collections.singletonList;
-import static org.apache.commons.lang.StringUtils.defaultString;
-import static org.sonar.api.utils.DateUtils.parseDateQuietly;
-import static org.sonar.api.utils.DateUtils.parseDateTimeQuietly;
-import static org.sonar.api.utils.Paging.offset;
-import static org.sonar.server.ws.WsUtils.checkRequest;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MAX_EXECUTED_AT;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MIN_SUBMITTED_AT;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_ONLY_CURRENTS;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_STATUS;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_TYPE;
-
-public class ActivityAction implements CeWsAction {
-  private static final int MAX_PAGE_SIZE = 1000;
-
-  private final UserSession userSession;
-  private final DbClient dbClient;
-  private final TaskFormatter formatter;
-  private final Set<String> taskTypes;
-
-  public ActivityAction(UserSession userSession, DbClient dbClient, TaskFormatter formatter, CeTaskProcessor[] taskProcessors) {
-    this.userSession = userSession;
-    this.dbClient = dbClient;
-    this.formatter = formatter;
-
-    this.taskTypes = new LinkedHashSet<>();
-    for (CeTaskProcessor taskProcessor : taskProcessors) {
-      taskTypes.addAll(taskProcessor.getHandledCeTaskTypes());
-    }
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("activity")
-      .setDescription(format("Search for tasks.<br> " +
-        "Requires the system administration permission, " +
-        "or project administration permission if %s is set.", PARAM_COMPONENT_ID))
-      .setResponseExample(getClass().getResource("activity-example.json"))
-      .setHandler(this)
-      .setSince("5.2");
-
-    action.createParam(PARAM_COMPONENT_ID)
-      .setDescription("Id of the component (project) to filter on")
-      .setExampleValue(Uuids.UUID_EXAMPLE_03);
-    action.createParam(PARAM_COMPONENT_QUERY)
-      .setDescription(format("Limit search to: <ul>" +
-        "<li>component names that contain the supplied string</li>" +
-        "<li>component keys that are exactly the same as the supplied string</li>" +
-        "</ul>" +
-        "Must not be set together with %s.<br />" +
-        "Deprecated and replaced by '%s'", PARAM_COMPONENT_ID, Param.TEXT_QUERY))
-      .setExampleValue("Apache")
-      .setDeprecatedSince("5.5");
-    action.createParam(Param.TEXT_QUERY)
-      .setDescription(format("Limit search to: <ul>" +
-        "<li>component names that contain the supplied string</li>" +
-        "<li>component keys that are exactly the same as the supplied string</li>" +
-        "<li>task ids that are exactly the same as the supplied string</li>" +
-        "</ul>" +
-        "Must not be set together with %s", PARAM_COMPONENT_ID))
-      .setExampleValue("Apache")
-      .setSince("5.5");
-    action.createParam(PARAM_STATUS)
-      .setDescription("Comma separated list of task statuses")
-      .setPossibleValues(ImmutableList.builder()
-        .add(CeActivityDto.Status.values())
-        .add(CeQueueDto.Status.values()).build())
-      .setExampleValue(Joiner.on(",").join(CeQueueDto.Status.IN_PROGRESS, CeActivityDto.Status.SUCCESS))
-      // activity statuses by default to be backward compatible
-      // queued tasks have been added in 5.5
-      .setDefaultValue(Joiner.on(",").join(CeActivityDto.Status.values()));
-    action.createParam(PARAM_ONLY_CURRENTS)
-      .setDescription("Filter on the last tasks (only the most recent finished task by project)")
-      .setBooleanPossibleValues()
-      .setDefaultValue("false");
-    action.createParam(PARAM_TYPE)
-      .setDescription("Task type")
-      .setExampleValue(CeTaskTypes.REPORT)
-      .setPossibleValues(taskTypes);
-    action.createParam(PARAM_MIN_SUBMITTED_AT)
-      .setDescription("Minimum date of task submission (inclusive)")
-      .setExampleValue(DateUtils.formatDateTime(new Date()));
-    action.createParam(PARAM_MAX_EXECUTED_AT)
-      .setDescription("Maximum date of end of task processing (inclusive)")
-      .setExampleValue(DateUtils.formatDateTime(new Date()));
-    action.addPagingParams(100, MAX_PAGE_SIZE);
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) throws Exception {
-    ActivityResponse activityResponse = doHandle(toSearchWsRequest(wsRequest));
-    writeProtobuf(activityResponse, wsRequest, wsResponse);
-  }
-
-  private ActivityResponse doHandle(ActivityWsRequest request) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      // if a task searched by uuid is found all other parameters are ignored
-      Optional<WsCe.Task> taskSearchedById = searchTaskByUuid(dbSession, request);
-      if (taskSearchedById.isPresent()) {
-        return buildResponse(
-          singletonList(taskSearchedById.get()),
-          Collections.<WsCe.Task>emptyList(),
-          Paging.forPageIndex(1).withPageSize(request.getPageSize()).andTotal(1));
-      }
-
-      CeTaskQuery query = buildQuery(dbSession, request);
-      checkPermissions(query);
-      TaskResult queuedTasks = loadQueuedTasks(dbSession, request, query);
-      TaskResult pastTasks = loadPastTasks(dbSession, request, query, queuedTasks.total);
-
-      return buildResponse(
-        queuedTasks.tasks,
-        pastTasks.tasks,
-        Paging.forPageIndex(request.getPage())
-          .withPageSize(request.getPageSize())
-          .andTotal(queuedTasks.total + pastTasks.total));
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  private Optional<WsCe.Task> searchTaskByUuid(DbSession dbSession, ActivityWsRequest request) {
-    String textQuery = request.getQuery();
-    if (textQuery == null) {
-      return Optional.absent();
-    }
-
-    Optional<CeQueueDto> queue = dbClient.ceQueueDao().selectByUuid(dbSession, textQuery);
-    if (queue.isPresent()) {
-      return Optional.of(formatter.formatQueue(dbSession, queue.get()));
-    }
-
-    Optional<CeActivityDto> activity = dbClient.ceActivityDao().selectByUuid(dbSession, textQuery);
-    if (activity.isPresent()) {
-      return Optional.of(formatter.formatActivity(dbSession, activity.get()));
-    }
-
-    return Optional.absent();
-  }
-
-  private CeTaskQuery buildQuery(DbSession dbSession, ActivityWsRequest request) {
-    CeTaskQuery query = new CeTaskQuery();
-    query.setType(request.getType());
-    query.setOnlyCurrents(request.getOnlyCurrents());
-    query.setMinSubmittedAt(parseDateTimeAsLong(request.getMinSubmittedAt()));
-    query.setMaxExecutedAt(parseDateTimeAsLong(request.getMaxExecutedAt()));
-
-    List<String> statuses = request.getStatus();
-    if (statuses != null && !statuses.isEmpty()) {
-      query.setStatuses(request.getStatus());
-    }
-
-    loadComponentUuids(dbSession, request, query);
-    return query;
-  }
-
-  private void loadComponentUuids(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
-    String componentUuid = request.getComponentId();
-    String componentQuery = request.getQuery();
-
-    if (componentUuid != null) {
-      query.setComponentUuid(componentUuid);
-    }
-    if (componentQuery != null) {
-      ComponentQuery componentDtoQuery = ComponentQuery.builder().setNameOrKeyQuery(componentQuery).setQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW).build();
-      List<ComponentDto> componentDtos = dbClient.componentDao().selectByQuery(dbSession, componentDtoQuery, 0, CeTaskQuery.MAX_COMPONENT_UUIDS);
-      query.setComponentUuids(Lists.transform(componentDtos, ComponentDtoFunctions.toUuid()));
-    }
-  }
-
-  private TaskResult loadQueuedTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
-    int total = dbClient.ceQueueDao().countByQuery(dbSession, query);
-    List<CeQueueDto> dtos = dbClient.ceQueueDao().selectByQueryInDescOrder(dbSession, query,
-      Paging.forPageIndex(request.getPage())
-        .withPageSize(request.getPageSize())
-        .andTotal(total));
-    Iterable<WsCe.Task> tasks = formatter.formatQueue(dbSession, dtos);
-    return new TaskResult(tasks, total);
-  }
-
-  private TaskResult loadPastTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query, int totalQueuedTasks) {
-    int total = dbClient.ceActivityDao().countByQuery(dbSession, query);
-    // we have to take into account the total number of queue tasks found
-    int offset = Math.max(0, offset(request.getPage(), request.getPageSize()) - totalQueuedTasks);
-    List<CeActivityDto> dtos = dbClient.ceActivityDao().selectByQuery(dbSession, query, offset, request.getPageSize());
-    Iterable<WsCe.Task> ceTasks = formatter.formatActivity(dbSession, dtos);
-
-    return new TaskResult(ceTasks, total);
-  }
-
-  private void checkPermissions(CeTaskQuery query) {
-    List<String> componentUuids = query.getComponentUuids();
-    if (componentUuids != null && componentUuids.size() == 1) {
-      if (!isAllowedOnComponentUuid(userSession, componentUuids.get(0))) {
-        throw new ForbiddenException("Requires administration permission");
-      }
-    } else {
-      userSession.checkPermission(UserRole.ADMIN);
-    }
-  }
-
-  @CheckForNull
-  private static Long parseDateTimeAsLong(@Nullable String dateAsString) {
-    if (dateAsString == null) {
-      return null;
-    }
-
-    Date date = parseDateTimeQuietly(dateAsString);
-    if (date == null) {
-      date = parseDateQuietly(dateAsString);
-      checkRequest(date != null, "Date '%s' cannot be parsed as either a date or date+time", dateAsString);
-      date = DateUtils.addDays(date, 1);
-    }
-
-    return date.getTime();
-  }
-
-  public static boolean isAllowedOnComponentUuid(UserSession userSession, String componentUuid) {
-    return userSession.hasPermission(GlobalPermissions.SYSTEM_ADMIN) || userSession.hasComponentUuidPermission(UserRole.ADMIN, componentUuid);
-  }
-
-  private static ActivityResponse buildResponse(Iterable<WsCe.Task> queuedTasks, Iterable<WsCe.Task> pastTasks, Paging paging) {
-    WsCe.ActivityResponse.Builder wsResponseBuilder = WsCe.ActivityResponse.newBuilder();
-
-    int nbInsertedTasks = 0;
-    for (WsCe.Task queuedTask : queuedTasks) {
-      if (nbInsertedTasks < paging.pageSize()) {
-        wsResponseBuilder.addTasks(queuedTask);
-        nbInsertedTasks++;
-      }
-    }
-
-    for (WsCe.Task pastTask : pastTasks) {
-      if (nbInsertedTasks < paging.pageSize()) {
-        wsResponseBuilder.addTasks(pastTask);
-        nbInsertedTasks++;
-      }
-    }
-
-    wsResponseBuilder.setPaging(Common.Paging.newBuilder()
-      .setPageIndex(paging.pageIndex())
-      .setPageSize(paging.pageSize())
-      .setTotal(paging.total()));
-
-    return wsResponseBuilder.build();
-  }
-
-  private static ActivityWsRequest toSearchWsRequest(Request request) {
-    ActivityWsRequest activityWsRequest = new ActivityWsRequest()
-      .setComponentId(request.param(PARAM_COMPONENT_ID))
-      .setQuery(defaultString(request.param(Param.TEXT_QUERY), request.param(PARAM_COMPONENT_QUERY)))
-      .setStatus(request.paramAsStrings(PARAM_STATUS))
-      .setType(request.param(PARAM_TYPE))
-      .setMinSubmittedAt(request.param(PARAM_MIN_SUBMITTED_AT))
-      .setMaxExecutedAt(request.param(PARAM_MAX_EXECUTED_AT))
-      .setOnlyCurrents(request.paramAsBoolean(PARAM_ONLY_CURRENTS))
-      .setPage(request.mandatoryParamAsInt(Param.PAGE))
-      .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE));
-
-    checkRequest(activityWsRequest.getComponentId() == null || activityWsRequest.getQuery() == null, "%s and %s must not be set at the same time",
-      PARAM_COMPONENT_ID, PARAM_COMPONENT_QUERY);
-    checkRequest(activityWsRequest.getPageSize() <= MAX_PAGE_SIZE, "The '%s' parameter must be less than %d", Param.PAGE_SIZE, MAX_PAGE_SIZE);
-
-    return activityWsRequest;
-  }
-
-  private static class TaskResult {
-    private final Iterable<WsCe.Task> tasks;
-    private final int total;
-
-    private TaskResult(Iterable<WsCe.Task> tasks, int total) {
-      this.tasks = tasks;
-      this.total = total;
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CancelAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CancelAction.java
deleted file mode 100644 (file)
index 7c3caf9..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.util.Uuids;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.user.UserSession;
-
-public class CancelAction implements CeWsAction {
-
-  public static final String PARAM_TASK_ID = "id";
-
-  private final UserSession userSession;
-  private final CeQueue queue;
-
-  public CancelAction(UserSession userSession, CeQueue queue) {
-    this.userSession = userSession;
-    this.queue = queue;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("cancel")
-      .setDescription("Cancels a pending task. Requires system administration permission. In-progress tasks can not be canceled.")
-      .setInternal(true)
-      .setPost(true)
-      .setSince("5.2")
-      .setHandler(this);
-
-    action
-      .createParam(PARAM_TASK_ID)
-      .setRequired(true)
-      .setDescription("Id of the task to cancel.")
-      .setExampleValue(Uuids.UUID_EXAMPLE_01);
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) {
-    userSession.checkPermission(UserRole.ADMIN);
-    String taskId = wsRequest.mandatoryParam(PARAM_TASK_ID);
-    queue.cancel(taskId);
-    wsResponse.noContent();
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CancelAllAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CancelAllAction.java
deleted file mode 100644 (file)
index 547a687..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.web.UserRole;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.user.UserSession;
-
-public class CancelAllAction implements CeWsAction {
-
-  private final UserSession userSession;
-  private final CeQueue queue;
-
-  public CancelAllAction(UserSession userSession, CeQueue queue) {
-    this.userSession = userSession;
-    this.queue = queue;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    controller.createAction("cancel_all")
-      .setDescription("Cancels all pending tasks. Requires system administration permission. In-progress tasks are not canceled.")
-      .setInternal(true)
-      .setPost(true)
-      .setSince("5.2")
-      .setHandler(this);
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) {
-    userSession.checkPermission(UserRole.ADMIN);
-    queue.cancelAll();
-    wsResponse.noContent();
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWs.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWs.java
deleted file mode 100644 (file)
index 7ebc8f6..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.sonar.api.server.ws.WebService;
-
-public class CeWs implements WebService {
-
-  public static final String ENDPOINT = "api/ce";
-
-  private final CeWsAction[] actions;
-
-  public CeWs(CeWsAction... actions) {
-    this.actions = actions;
-  }
-
-  @Override
-  public void define(Context context) {
-    NewController controller = context
-      .createController(ENDPOINT)
-      .setDescription("Compute Engine");
-    for (CeWsAction action : actions) {
-      action.define(controller);
-    }
-    controller.done();
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsAction.java
deleted file mode 100644 (file)
index 0748073..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.ws.WsAction;
-
-/**
- * Used by {@link CeWs} to loop over all its actions
- */
-interface CeWsAction extends WsAction {
-  @Override
-  void define(WebService.NewController controller);
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java
deleted file mode 100644 (file)
index dacfb59..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.sonar.core.platform.Module;
-
-public class CeWsModule extends Module {
-  @Override
-  protected void configureModule() {
-    add(
-      CeWs.class,
-      ActivityAction.class,
-      CancelAction.class,
-      CancelAllAction.class,
-      IsQueueEmptyWs.class,
-      LogsAction.class,
-      ComponentAction.class,
-      SubmitAction.class,
-      TaskFormatter.class,
-      TaskAction.class,
-      TaskTypesAction.class);
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java
deleted file mode 100644 (file)
index f4a946a..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import java.util.List;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.util.Uuids;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeTaskQuery;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.server.user.UserSession;
-import org.sonar.server.ws.WsUtils;
-
-import static org.sonarqube.ws.WsCe.ProjectResponse;
-
-public class ComponentAction implements CeWsAction {
-
-  public static final String PARAM_COMPONENT_UUID = "componentId";
-
-  private final UserSession userSession;
-  private final DbClient dbClient;
-  private final TaskFormatter formatter;
-
-  public ComponentAction(UserSession userSession, DbClient dbClient, TaskFormatter formatter) {
-    this.userSession = userSession;
-    this.dbClient = dbClient;
-    this.formatter = formatter;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("component")
-      .setDescription("Get the pending tasks, in-progress tasks and the last executed task of a given component " +
-        "(usually a project). Requires the administration permission on the component.")
-      .setSince("5.2")
-      .setResponseExample(getClass().getResource("component-example.json"))
-      .setHandler(this);
-
-    action.createParam(PARAM_COMPONENT_UUID)
-      .setRequired(true)
-      .setExampleValue(Uuids.UUID_EXAMPLE_01);
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) throws Exception {
-    String componentUuid = wsRequest.mandatoryParam(PARAM_COMPONENT_UUID);
-    userSession.checkComponentUuidPermission(UserRole.USER, componentUuid);
-
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      List<CeQueueDto> queueDtos = dbClient.ceQueueDao().selectByComponentUuid(dbSession, componentUuid);
-      CeTaskQuery activityQuery = new CeTaskQuery()
-        .setComponentUuid(componentUuid)
-        .setOnlyCurrents(true);
-      List<CeActivityDto> activityDtos = dbClient.ceActivityDao().selectByQuery(dbSession, activityQuery, 0, 1);
-
-      ProjectResponse.Builder wsResponseBuilder = ProjectResponse.newBuilder();
-      wsResponseBuilder.addAllQueue(formatter.formatQueue(dbSession, queueDtos));
-      if (activityDtos.size() == 1) {
-        wsResponseBuilder.setCurrent(formatter.formatActivity(dbSession, activityDtos.get(0)));
-      }
-      WsUtils.writeProtobuf(wsResponseBuilder.build(), wsRequest, wsResponse);
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWs.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWs.java
deleted file mode 100644 (file)
index 459aa43..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-
-/**
- * Internal WebService with one action
- */
-public class IsQueueEmptyWs implements WebService {
-  public static final String API_ENDPOINT = "api/analysis_reports";
-
-  private final IsQueueEmptyAction action;
-
-  public IsQueueEmptyWs(DbClient dbClient) {
-    this.action = new IsQueueEmptyAction(dbClient);
-  }
-
-  @Override
-  public void define(Context context) {
-    NewController controller = context
-      .createController(API_ENDPOINT)
-      .setDescription("For internal testing - do not use");
-    action.define(controller);
-    controller.done();
-  }
-
-  static class IsQueueEmptyAction implements RequestHandler {
-    private final DbClient dbClient;
-
-    public IsQueueEmptyAction(DbClient dbClient) {
-      this.dbClient = dbClient;
-    }
-
-    public void define(WebService.NewController controller) {
-      controller
-        .createAction("is_queue_empty")
-        .setDescription("Check if the queue of Compute Engine is empty")
-        .setResponseExample(getClass().getResource("is_queue_empty-example.txt"))
-        .setSince("5.1")
-        .setInternal(true)
-        .setHandler(this);
-    }
-
-    @Override
-    public void handle(Request request, Response response) throws Exception {
-      DbSession dbSession = dbClient.openSession(false);
-      try {
-        boolean isQueueEmpty = dbClient.ceQueueDao().selectAllInAscOrder(dbSession).isEmpty();
-        IOUtils.write(String.valueOf(isQueueEmpty), response.stream().output());
-      } finally {
-        dbClient.closeSession(dbSession);
-      }
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/LogsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/LogsAction.java
deleted file mode 100644 (file)
index 36c3fd4..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.util.Uuids;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.MediaTypes;
-
-import static java.lang.String.format;
-
-public class LogsAction implements CeWsAction {
-
-  public static final String ACTION = "logs";
-  public static final String PARAM_TASK_UUID = "taskId";
-
-  private final DbClient dbClient;
-  private final UserSession userSession;
-  private final CeLogging ceLogging;
-
-  public LogsAction(DbClient dbClient, UserSession userSession, CeLogging ceLogging) {
-    this.dbClient = dbClient;
-    this.userSession = userSession;
-    this.ceLogging = ceLogging;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction(ACTION)
-      .setDescription("Logs of a task. Format of response is plain text. HTTP code 404 is returned if the task does not " +
-        "exist or if logs are not available. Requires system administration permission.")
-      .setResponseExample(getClass().getResource("logs-example.log"))
-      .setInternal(true)
-      .setSince("5.2")
-      .setHandler(this);
-
-    action
-      .createParam(PARAM_TASK_UUID)
-      .setRequired(true)
-      .setDescription("Id of task")
-      .setExampleValue(Uuids.UUID_EXAMPLE_01);
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) throws Exception {
-    userSession.checkPermission(UserRole.ADMIN);
-
-    String taskUuid = wsRequest.mandatoryParam(PARAM_TASK_UUID);
-    LogFileRef ref = loadLogRef(taskUuid);
-    Optional<File> logFile = ceLogging.getFile(ref);
-    if (logFile.isPresent()) {
-      writeFile(logFile.get(), wsResponse);
-    } else {
-      throw new NotFoundException(format("Logs of task %s not found", taskUuid));
-    }
-  }
-
-  private LogFileRef loadLogRef(String taskUuid) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
-      if (queueDto.isPresent()) {
-        return LogFileRef.from(queueDto.get());
-      }
-      Optional<CeActivityDto> activityDto = dbClient.ceActivityDao().selectByUuid(dbSession, taskUuid);
-      if (activityDto.isPresent()) {
-        return LogFileRef.from(activityDto.get());
-      }
-      throw new NotFoundException(format("Task %s not found", taskUuid));
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  private static void writeFile(File file, Response wsResponse) {
-    try {
-      Response.Stream stream = wsResponse.stream();
-      stream.setMediaType(MediaTypes.TXT);
-      FileUtils.copyFile(file, stream.output());
-    } catch (IOException e) {
-      throw new IllegalStateException("Fail to copy compute engine log file to HTTP response: " + file.getAbsolutePath(), e);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitAction.java
deleted file mode 100644 (file)
index 943f886..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import java.io.InputStream;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.report.ReportSubmitter;
-import org.sonar.server.ws.WsUtils;
-import org.sonarqube.ws.WsCe;
-
-public class SubmitAction implements CeWsAction {
-
-  public static final String PARAM_PROJECT_KEY = "projectKey";
-  public static final String PARAM_PROJECT_BRANCH = "projectBranch";
-  public static final String PARAM_PROJECT_NAME = "projectName";
-  public static final String PARAM_REPORT_DATA = "report";
-
-  private final ReportSubmitter reportSubmitter;
-
-  public SubmitAction(ReportSubmitter reportSubmitter) {
-    this.reportSubmitter = reportSubmitter;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("submit")
-      .setDescription("Submits a scanner report to the queue. Report is processed asynchronously. Requires analysis permission. " +
-        "If the project does not exist, then the provisioning permission is also required.")
-      .setPost(true)
-      .setInternal(true)
-      .setSince("5.2")
-      .setHandler(this)
-      .setResponseExample(getClass().getResource("submit-example.json"));
-
-    action
-      .createParam(PARAM_PROJECT_KEY)
-      .setRequired(true)
-      .setDescription("Key of project")
-      .setExampleValue("my_project");
-
-    action
-      .createParam(PARAM_PROJECT_BRANCH)
-      .setDescription("Optional branch of project")
-      .setExampleValue("branch-1.x");
-
-    action
-      .createParam(PARAM_PROJECT_NAME)
-      .setRequired(false)
-      .setDescription("Optional name of the project, used only if the project does not exist yet.")
-      .setExampleValue("My Project");
-
-    action
-      .createParam(PARAM_REPORT_DATA)
-      .setRequired(true)
-      .setDescription("Report file. Format is not an API, it changes among SonarQube versions.");
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) throws Exception {
-    String projectKey = wsRequest.mandatoryParam(PARAM_PROJECT_KEY);
-    String projectBranch = wsRequest.param(PARAM_PROJECT_BRANCH);
-    String projectName = StringUtils.defaultIfBlank(wsRequest.param(PARAM_PROJECT_NAME), projectKey);
-    InputStream reportInput = wsRequest.paramAsInputStream(PARAM_REPORT_DATA);
-
-    CeTask task = reportSubmitter.submit(projectKey, projectBranch, projectName, reportInput);
-
-    WsCe.SubmitResponse submitResponse = WsCe.SubmitResponse.newBuilder()
-      .setTaskId(task.getUuid())
-      .setProjectId(task.getComponentUuid())
-      .build();
-    WsUtils.writeProtobuf(submitResponse, wsRequest, wsResponse);
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java
deleted file mode 100644 (file)
index fdd0332..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import javax.annotation.Nullable;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.core.util.Uuids;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.WsCe;
-
-import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
-import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
-import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
-
-public class TaskAction implements CeWsAction {
-
-  public static final String ACTION = "task";
-  public static final String PARAM_TASK_UUID = "id";
-
-  private final DbClient dbClient;
-  private final TaskFormatter wsTaskFormatter;
-  private final UserSession userSession;
-
-  public TaskAction(DbClient dbClient, TaskFormatter wsTaskFormatter, UserSession userSession) {
-    this.dbClient = dbClient;
-    this.wsTaskFormatter = wsTaskFormatter;
-    this.userSession = userSession;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction(ACTION)
-      .setDescription("Give Compute Engine task details such as type, status, duration and associated component.<br />" +
-        "Requires 'Administer System' or 'Execute Analysis' permission.")
-      .setResponseExample(getClass().getResource("task-example.json"))
-      .setSince("5.2")
-      .setHandler(this);
-
-    action
-      .createParam(PARAM_TASK_UUID)
-      .setRequired(true)
-      .setDescription("Id of task")
-      .setExampleValue(Uuids.UUID_EXAMPLE_01);
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) throws Exception {
-    String taskUuid = wsRequest.mandatoryParam(PARAM_TASK_UUID);
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      WsCe.TaskResponse.Builder wsTaskResponse = WsCe.TaskResponse.newBuilder();
-      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
-      if (queueDto.isPresent()) {
-        checkPermission(queueDto.get().getComponentUuid());
-        wsTaskResponse.setTask(wsTaskFormatter.formatQueue(dbSession, queueDto.get()));
-      } else {
-        Optional<CeActivityDto> activityDto = dbClient.ceActivityDao().selectByUuid(dbSession, taskUuid);
-        if (activityDto.isPresent()) {
-          checkPermission(activityDto.get().getComponentUuid());
-          wsTaskResponse.setTask(wsTaskFormatter.formatActivity(dbSession, activityDto.get()));
-        } else {
-          throw new NotFoundException();
-        }
-      }
-      writeProtobuf(wsTaskResponse.build(), wsRequest, wsResponse);
-
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
-  }
-
-  private void checkPermission(@Nullable String projectUuid) {
-    if (!userSession.hasPermission(SYSTEM_ADMIN)
-      && !userSession.hasPermission(SCAN_EXECUTION)
-      && (projectUuid == null || !userSession.hasComponentUuidPermission(SCAN_EXECUTION, projectUuid))
-      ) {
-      throw insufficientPrivilegesException();
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java
deleted file mode 100644 (file)
index bfb9be8..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentDtoFunctions;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonarqube.ws.WsCe;
-
-import static com.google.common.base.Predicates.notNull;
-import static com.google.common.collect.FluentIterable.from;
-
-/**
- * Converts {@link CeActivityDto} and {@link CeQueueDto} to the protobuf objects
- * used to write WS responses (see ws-ce.proto in module sonar-ws)
- */
-public class TaskFormatter {
-
-  private final DbClient dbClient;
-  private final CeLogging ceLogging;
-  private final System2 system2;
-
-  public TaskFormatter(DbClient dbClient, CeLogging ceLogging, System2 system2) {
-    this.dbClient = dbClient;
-    this.ceLogging = ceLogging;
-    this.system2 = system2;
-  }
-
-  public Iterable<WsCe.Task> formatQueue(DbSession dbSession, List<CeQueueDto> dtos) {
-    ComponentDtoCache cache = new ComponentDtoCache(dbSession, ceQueueDtoToComponentUuids(dtos));
-    return from(dtos)
-      .transform(new CeQueueDtoToTask(cache));
-  }
-
-  public WsCe.Task formatQueue(DbSession dbSession, CeQueueDto dto) {
-    return formatQueue(dto, new ComponentDtoCache(dbSession, dto.getComponentUuid()));
-  }
-
-  private WsCe.Task formatQueue(CeQueueDto dto, ComponentDtoCache componentDtoCache) {
-    WsCe.Task.Builder builder = WsCe.Task.newBuilder();
-    builder.setId(dto.getUuid());
-    builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
-    builder.setType(dto.getTaskType());
-    builder.setLogs(ceLogging.getFile(LogFileRef.from(dto)).isPresent());
-    if (dto.getComponentUuid() != null) {
-      builder.setComponentId(dto.getComponentUuid());
-      buildComponent(builder, componentDtoCache.get(dto.getComponentUuid()));
-    }
-    if (dto.getSubmitterLogin() != null) {
-      builder.setSubmitterLogin(dto.getSubmitterLogin());
-    }
-    builder.setSubmittedAt(DateUtils.formatDateTime(new Date(dto.getCreatedAt())));
-    if (dto.getStartedAt() != null) {
-      builder.setStartedAt(DateUtils.formatDateTime(new Date(dto.getStartedAt())));
-    }
-    //
-    Long executionTimeMs = computeExecutionTimeMs(dto);
-    if (executionTimeMs != null) {
-      builder.setExecutionTimeMs(executionTimeMs);
-    }
-    return builder.build();
-  }
-
-  public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto dto) {
-    return formatActivity(dto, new ComponentDtoCache(dbSession, dto.getComponentUuid()));
-  }
-
-  public Iterable<WsCe.Task> formatActivity(DbSession dbSession, List<CeActivityDto> dtos) {
-    ComponentDtoCache cache = new ComponentDtoCache(dbSession, ceActivityDtoToComponentUuids(dtos));
-    return from(dtos).transform(new CeActivityDtoToTask(cache));
-  }
-
-  private WsCe.Task formatActivity(CeActivityDto dto, ComponentDtoCache componentDtoCache) {
-    WsCe.Task.Builder builder = WsCe.Task.newBuilder();
-    builder.setId(dto.getUuid());
-    builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
-    builder.setType(dto.getTaskType());
-    builder.setLogs(ceLogging.getFile(LogFileRef.from(dto)).isPresent());
-    if (dto.getComponentUuid() != null) {
-      builder.setComponentId(dto.getComponentUuid());
-      buildComponent(builder, componentDtoCache.get(dto.getComponentUuid()));
-    }
-    if (dto.getSnapshotId() != null) {
-      builder.setAnalysisId(String.valueOf(dto.getSnapshotId()));
-    }
-    if (dto.getSubmitterLogin() != null) {
-      builder.setSubmitterLogin(dto.getSubmitterLogin());
-    }
-    builder.setSubmittedAt(DateUtils.formatDateTime(new Date(dto.getSubmittedAt())));
-    if (dto.getStartedAt() != null) {
-      builder.setStartedAt(DateUtils.formatDateTime(new Date(dto.getStartedAt())));
-    }
-    if (dto.getExecutedAt() != null) {
-      builder.setExecutedAt(DateUtils.formatDateTime(new Date(dto.getExecutedAt())));
-    }
-    if (dto.getExecutionTimeMs() != null) {
-      builder.setExecutionTimeMs(dto.getExecutionTimeMs());
-    }
-    return builder.build();
-  }
-
-  private static void buildComponent(WsCe.Task.Builder builder, @Nullable ComponentDto componentDto) {
-    if (componentDto != null) {
-      builder.setComponentKey(componentDto.getKey());
-      builder.setComponentName(componentDto.name());
-      builder.setComponentQualifier(componentDto.qualifier());
-    }
-  }
-
-  private static Set<String> ceQueueDtoToComponentUuids(Iterable<CeQueueDto> dtos) {
-    return from(dtos)
-      .transform(CeQueueDtoToComponentUuid.INSTANCE)
-      .filter(notNull())
-      .toSet();
-  }
-
-  private static Set<String> ceActivityDtoToComponentUuids(Iterable<CeActivityDto> dtos) {
-    return from(dtos)
-      .transform(CeActivityDtoToComponentUuid.INSTANCE)
-      .filter(notNull())
-      .toSet();
-  }
-
-  private enum CeQueueDtoToComponentUuid implements Function<CeQueueDto, String> {
-    INSTANCE;
-
-    @Override
-    @Nullable
-    public String apply(@Nonnull CeQueueDto input) {
-      return input.getComponentUuid();
-    }
-  }
-
-  private enum CeActivityDtoToComponentUuid implements Function<CeActivityDto, String> {
-    INSTANCE;
-
-    @Override
-    @Nullable
-    public String apply(@Nonnull CeActivityDto input) {
-      return input.getComponentUuid();
-    }
-  }
-
-  private class ComponentDtoCache {
-    private final Map<String, ComponentDto> componentsByUuid;
-
-    public ComponentDtoCache(DbSession dbSession, Set<String> uuids) {
-      this.componentsByUuid = from(dbClient.componentDao().selectByUuids(dbSession, uuids)).uniqueIndex(ComponentDtoFunctions.toUuid());
-    }
-
-    public ComponentDtoCache(DbSession dbSession, String uuid) {
-      Optional<ComponentDto> componentDto = dbClient.componentDao().selectByUuid(dbSession, uuid);
-      this.componentsByUuid = componentDto.isPresent() ? ImmutableMap.of(uuid, componentDto.get()) : Collections.<String, ComponentDto>emptyMap();
-    }
-
-    @CheckForNull
-    ComponentDto get(@Nullable String uuid) {
-      if (uuid == null) {
-        return null;
-      }
-      return componentsByUuid.get(uuid);
-    }
-  }
-
-  /**
-   * now - startedAt
-   */
-  @CheckForNull
-  Long computeExecutionTimeMs(CeQueueDto dto) {
-    Long startedAt = dto.getStartedAt();
-    if (startedAt == null) {
-      return null;
-    }
-    return system2.now() - startedAt;
-  }
-
-  private final class CeActivityDtoToTask implements Function<CeActivityDto, WsCe.Task> {
-    private final ComponentDtoCache cache;
-
-    public CeActivityDtoToTask(ComponentDtoCache cache) {
-      this.cache = cache;
-    }
-
-    @Override
-    @Nonnull
-    public WsCe.Task apply(@Nonnull CeActivityDto input) {
-      return formatActivity(input, cache);
-    }
-  }
-
-  private final class CeQueueDtoToTask implements Function<CeQueueDto, WsCe.Task> {
-    private final ComponentDtoCache cache;
-
-    public CeQueueDtoToTask(ComponentDtoCache cache) {
-      this.cache = cache;
-    }
-
-    @Override
-    @Nonnull
-    public WsCe.Task apply(@Nonnull CeQueueDto input) {
-      return formatQueue(input, cache);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskTypesAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskTypesAction.java
deleted file mode 100644 (file)
index 392c844..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Set;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.computation.taskprocessor.CeTaskProcessor;
-import org.sonarqube.ws.WsCe;
-
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
-
-public class TaskTypesAction implements CeWsAction {
-  private final Set<String> taskTypes;
-
-  public TaskTypesAction(CeTaskProcessor[] taskProcessors) {
-    ImmutableSet.Builder<String> taskTypesBuilder = ImmutableSet.builder();
-    for (CeTaskProcessor taskProcessor : taskProcessors) {
-      taskTypesBuilder.addAll(taskProcessor.getHandledCeTaskTypes());
-    }
-    this.taskTypes = taskTypesBuilder.build();
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    controller.createAction("task_types")
-      .setDescription("List available task types")
-      .setResponseExample(getClass().getResource("task_types-example.json"))
-      .setSince("5.5")
-      .setInternal(true)
-      .setHandler(this);
-  }
-
-  @Override
-  public void handle(Request request, Response response) throws Exception {
-    WsCe.TaskTypesWsResponse taskTypesWsResponse = WsCe.TaskTypesWsResponse.newBuilder()
-      .addAllTaskTypes(taskTypes)
-      .build();
-
-    writeProtobuf(taskTypesWsResponse, request, response);
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/package-info.java
deleted file mode 100644 (file)
index 8e9e42e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.computation.ws;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
index e2984c1595872846c372523b3f458bbe08dcffd7..9a3b3ae3fe5aae09f7c4dc181738f00402342786 100644 (file)
@@ -35,7 +35,7 @@ import org.sonar.db.semaphore.SemaphoresImpl;
 import org.sonar.db.version.DatabaseVersion;
 import org.sonar.db.version.MigrationStepModule;
 import org.sonar.server.app.ProcessCommandWrapperImpl;
-import org.sonar.server.computation.property.CePropertyDefinitions;
+import org.sonar.ce.property.CePropertyDefinitions;
 import org.sonar.server.db.EmbeddedDatabaseFactory;
 import org.sonar.server.issue.index.IssueIndex;
 import org.sonar.server.platform.DatabaseServerCompatibility;
index cf14654aaecfa41dba09544250f5b82d81d1dbd3..9aecf57ae574b3cd59c3225e7ef0392e93a698fa 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.resources.ResourceTypes;
 import org.sonar.api.rules.AnnotationRuleParser;
 import org.sonar.api.rules.XMLRuleParser;
 import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
+import org.sonar.ce.CeModule;
 import org.sonar.core.component.DefaultResourceTypes;
 import org.sonar.core.timemachine.Periods;
 import org.sonar.core.user.DefaultUserFinder;
@@ -44,17 +45,13 @@ import org.sonar.server.activity.ws.ActivitiesWs;
 import org.sonar.server.activity.ws.ActivityMapping;
 import org.sonar.server.authentication.AuthenticationModule;
 import org.sonar.server.batch.BatchWsModule;
+import org.sonar.server.ce.ws.CeWsModule;
 import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentService;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.ws.ComponentsWsModule;
-import org.sonar.server.computation.CeModule;
-import org.sonar.server.computation.container.ReportProcessingModule;
-import org.sonar.server.computation.queue.CeQueueModule;
-import org.sonar.server.computation.taskprocessor.CeTaskProcessorModule;
-import org.sonar.server.computation.ws.CeWsModule;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.dashboard.template.GlobalDefaultDashboard;
 import org.sonar.server.dashboard.template.ProjectCustomDashboard;
@@ -193,6 +190,7 @@ import org.sonar.server.plugins.ws.PluginsWs;
 import org.sonar.server.plugins.ws.UninstallAction;
 import org.sonar.server.plugins.ws.UpdatesAction;
 import org.sonar.server.project.ws.ProjectsWsModule;
+import org.sonar.server.properties.ProjectSettingsFactory;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QualityGates;
 import org.sonar.server.qualitygate.ws.CreateConditionAction;
@@ -706,10 +704,9 @@ public class PlatformLevel4 extends PlatformLevel {
 
       // Compute engine (must be after Views and Developer Cockpit)
       CeModule.class,
-      CeQueueModule.class,
-      CeTaskProcessorModule.class,
       CeWsModule.class,
-      ReportProcessingModule.class,
+
+      ProjectSettingsFactory.class,
 
       // UI
       GlobalNavigationAction.class,
index fe68d914ed85376babc9df4ecbd7603cabe21e98..3ad05d77909182a2e44b10a609c0c9f09e889f75 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.server.platform.platformlevel;
 
 import org.sonar.server.app.ProcessCommandWrapper;
-import org.sonar.server.computation.queue.PurgeCeActivities;
 import org.sonar.server.issue.filter.RegisterIssueFilters;
 import org.sonar.server.platform.ServerLifecycleNotifier;
 import org.sonar.server.qualitygate.RegisterQualityGates;
@@ -65,7 +64,6 @@ public class PlatformLevelStartup extends PlatformLevel {
       RegisterIssueFilters.class,
       RenameIssueWidgets.class,
       ServerLifecycleNotifier.class,
-      PurgeCeActivities.class,
       DisplayLogOnDeprecatedProjects.class,
       ClearRulesOverloadedDebt.class,
       FeedUsersLocalStartupTask.class
index 6880edf560546d5800d11b2176f38bdca391d2f9..31926da662cc026cea07fe796c0f0b4e6574459a 100644 (file)
@@ -50,7 +50,7 @@ import org.sonar.db.dashboard.DashboardDto;
 import org.sonar.db.property.PropertyDto;
 import org.sonar.db.property.PropertyQuery;
 import org.sonar.server.component.ComponentFinder;
-import org.sonar.server.computation.ws.ActivityAction;
+import org.sonar.server.ce.ws.ActivityAction;
 import org.sonar.server.ui.ViewProxy;
 import org.sonar.server.ui.Views;
 import org.sonar.server.user.UserSession;
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity-example.json
new file mode 100644 (file)
index 0000000..93d300b
--- /dev/null
@@ -0,0 +1,39 @@
+{
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 10,
+    "total": 233
+  },
+  "tasks": [
+    {
+      "id": "BU_dO1vsORa8_beWCwsP",
+      "type": "REPORT",
+      "componentId": "AU-Tpxb--iU5OvuD2FLy",
+      "componentKey": "project_1",
+      "componentName": "Project One",
+      "componentQualifier": "TRK",
+      "analysisId": "123456",
+      "status": "SUCCESS",
+      "submittedAt": "2015-08-13T23:34:59+0200",
+      "submitterLogin": "john",
+      "startedAt": "2015-08-13T23:35:00+0200",
+      "executedAt": "2015-08-13T23:35:10+0200",
+      "executionTimeMs": 10000,
+      "logs": true
+    },
+    {
+      "id": "AU_dO1vsORa8_beWCwmP",
+      "taskType": "REPORT",
+      "componentId": "AU_dO1vlORa8_beWCwmO",
+      "componentKey": "project_2",
+      "componentName": "Project Two",
+      "componentQualifier": "TRK",
+      "status": "FAILED",
+      "submittedAt": "2015-09-17T23:34:59+0200",
+      "startedAt": "2015-09-17T23:35:00+0200",
+      "executedAt": "2015-08-13T23:37:00+0200",
+      "executionTimeMs": 120000,
+      "logs": false
+    }
+  ]
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/component-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/component-example.json
new file mode 100644 (file)
index 0000000..6adb3f0
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "queue": [
+    {
+      "id": "AU_w84A6gAS1Hm6h4_ih",
+      "type": "REPORT",
+      "componentId": "AU_w74XMgAS1Hm6h4-Y-",
+      "componentKey": "com.github.kevinsawicki:http-request-parent",
+      "componentName": "HttpRequest",
+      "componentQualifier": "TRK",
+      "status": "PENDING",
+      "submittedAt": "2015-09-21T19:28:54+0200",
+      "logs": true
+    }
+  ],
+  "current": {
+    "id": "AU_w8LDjgAS1Hm6h4-aY",
+    "type": "REPORT",
+    "componentId": "AU_w74XMgAS1Hm6h4-Y-",
+    "componentKey": "com.github.kevinsawicki:http-request-parent",
+    "componentName": "HttpRequest",
+    "componentQualifier": "TRK",
+    "analysisId": "123456",
+    "status": "SUCCESS",
+    "submittedAt": "2015-09-21T19:25:49+0200",
+    "startedAt": "2015-09-21T19:25:57+0200",
+    "finishedAt": "2015-09-21T19:25:58+0200",
+    "executionTimeMs": 1371,
+    "logs": true
+  }
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/is_queue_empty-example.txt b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/is_queue_empty-example.txt
new file mode 100644 (file)
index 0000000..27ba77d
--- /dev/null
@@ -0,0 +1 @@
+true
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/logs-example.log b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/logs-example.log
new file mode 100644 (file)
index 0000000..054509a
--- /dev/null
@@ -0,0 +1,84 @@
+2015.11.02 10:25:16 INFO  [o.s.s.c.t.CeWorkerRunnableImpl] Execute task | project=com.sonarsource:java-markdown | id=AVDHg9OnLPOCEbN7mM58
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExtractReportStep] Analysis report extracted | compressedSize=63 KB
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Extract report | time=75ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep] SonarQube plugins:
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - Git 1.0 (scmgit)
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - SVN 1.2 (scmsvn)
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - Java 3.6 (java)
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep] Settings for module: com.sonarsource:java-markdown
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.binaries=/Users/teryk/Projects/java-markdown/target/classes
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.core.id=20151102092209
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.core.startTime=2015-11-02T09:22:09+0100
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.core.version=5.3-SNAPSHOT
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.host.url=http://localhost:9000
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.java.binaries=/Users/teryk/Projects/java-markdown/target/classes
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.java.libraries=/Users/teryk/.m2/repository/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar,/Users/teryk/.m2/repository/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.java.test.libraries=/Users/teryk/Projects/java-markdown/target/classes,/Users/teryk/.m2/repository/junit/junit/4.11/junit-4.11.jar,/Users/teryk/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar,/Users/teryk/.m2/repository/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar,/Users/teryk/.m2/repository/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.libraries=/Users/teryk/.m2/repository/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar,/Users/teryk/.m2/repository/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.ci=
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.homepage=http://maven.apache.org
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.issue=
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.scm=
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.scm_dev=
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.maven.projectDependencies=[{"k":"junit:junit","v":"4.11","s":"test","d":[{"k":"org.hamcrest:hamcrest-core","v":"1.3","s":"test","d":[]}]},{"k":"org.easytesting:fest-assert","v":"1.4","s":"compile","d":[{"k":"org.easytesting:fest-util","v":"1.1.6","s":"compile","d":[]}]}]
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.moduleKey=com.sonarsource:java-markdown
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.mojoUseRunner=true
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.permission.template.default=default_template
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectBaseDir=/Users/teryk/Projects/java-markdown
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectBuildDir=/Users/teryk/Projects/java-markdown/target
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectKey=com.sonarsource:java-markdown
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectName=Java Markdown
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectVersion=1.0-SNAPSHOT
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.qualitygate=1
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.sourceEncoding=UTF-8
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.sources=/Users/teryk/Projects/java-markdown/pom.xml,/Users/teryk/Projects/java-markdown/src/main/java
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.tests=/Users/teryk/Projects/java-markdown/src/test/java
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.working.directory=/Users/teryk/Projects/java-markdown/target/sonar
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Log scanner context | time=3ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Build tree of components | time=36ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Validate project | time=4ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load debt model | time=5ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load quality profiles | time=121ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load Quality gate | time=8ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load differential periods | time=30ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute size measures | time=29ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute new coverage | time=39ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute coverage measures | time=11ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute comment measures | time=6ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Copy custom measures | time=29ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute duplication measures | time=3ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute language distribution | time=17ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute test measures | time=2ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute complexity measures | time=24ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load measure computers | time=2ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   Execution time for each component visitor:
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - LoadComponentUuidsHavingOpenIssuesVisitor | time=5ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - IntegrateIssuesVisitor | time=182ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - CloseIssuesOnRemovedComponentsVisitor | time=0ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - SqaleMeasuresVisitor | time=4ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - SqaleNewMeasuresVisitor | time=0ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - LastCommitVisitor | time=0ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - MeasureComputersVisitor | time=3ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Execute component visitors | time=198ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute measure variations | time=3ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Computes Quality Gate measures | time=6ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute Quality profile measures | time=1ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Generate Quality profile events | time=4ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Generate Quality gate events | time=2ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist components | time=25ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist snapshots | time=26ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist measures | time=212ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist issues | time=59ms
+2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist project links | time=6ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist events | time=4ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist duplications | time=2ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist sources | time=286ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist tests | time=16ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Enable snapshot | time=8ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Index components | time=60ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Purge db | time=27ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Apply permissions | time=2ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Index issues | time=77ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Index tests | time=50ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Send issue notifications | time=2ms
+2015.11.02 10:25:18 INFO  [o.s.s.c.t.CeWorkerRunnableImpl] Executed task | project=com.sonarsource:java-markdown | id=AVDHg9OnLPOCEbN7mM58 | time=1706ms
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/submit-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/submit-example.json
new file mode 100644 (file)
index 0000000..7cee04f
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "taskId": "TASK_1",
+  "projectId": "PROJECT_1"
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/task-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/task-example.json
new file mode 100644 (file)
index 0000000..089e277
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "task": {
+    "id": "AVAn5RKqYwETbXvgas-I",
+    "type": "REPORT",
+    "componentId": "AVAn5RJmYwETbXvgas-H",
+    "componentKey": "project_1",
+    "componentName": "Project One",
+    "componentQualifier": "TRK",
+    "analysisId": "123456",
+    "status": "SUCCESS",
+    "submittedAt": "2015-10-02T11:32:15+0200",
+    "startedAt": "2015-10-02T11:32:16+0200",
+    "executedAt": "2015-10-02T11:32:22+0200",
+    "executionTimeMs": 5286,
+    "logs": true
+  }
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/task_types-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/task_types-example.json
new file mode 100644 (file)
index 0000000..6dd3019
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "taskTypes": [
+    "REPORT",
+    "DEV_REFRESH",
+    "DEV_PURGE",
+    "VIEW_REFRESH"
+  ]
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json
deleted file mode 100644 (file)
index 93d300b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "paging": {
-    "pageIndex": 1,
-    "pageSize": 10,
-    "total": 233
-  },
-  "tasks": [
-    {
-      "id": "BU_dO1vsORa8_beWCwsP",
-      "type": "REPORT",
-      "componentId": "AU-Tpxb--iU5OvuD2FLy",
-      "componentKey": "project_1",
-      "componentName": "Project One",
-      "componentQualifier": "TRK",
-      "analysisId": "123456",
-      "status": "SUCCESS",
-      "submittedAt": "2015-08-13T23:34:59+0200",
-      "submitterLogin": "john",
-      "startedAt": "2015-08-13T23:35:00+0200",
-      "executedAt": "2015-08-13T23:35:10+0200",
-      "executionTimeMs": 10000,
-      "logs": true
-    },
-    {
-      "id": "AU_dO1vsORa8_beWCwmP",
-      "taskType": "REPORT",
-      "componentId": "AU_dO1vlORa8_beWCwmO",
-      "componentKey": "project_2",
-      "componentName": "Project Two",
-      "componentQualifier": "TRK",
-      "status": "FAILED",
-      "submittedAt": "2015-09-17T23:34:59+0200",
-      "startedAt": "2015-09-17T23:35:00+0200",
-      "executedAt": "2015-08-13T23:37:00+0200",
-      "executionTimeMs": 120000,
-      "logs": false
-    }
-  ]
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json
deleted file mode 100644 (file)
index 6adb3f0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "queue": [
-    {
-      "id": "AU_w84A6gAS1Hm6h4_ih",
-      "type": "REPORT",
-      "componentId": "AU_w74XMgAS1Hm6h4-Y-",
-      "componentKey": "com.github.kevinsawicki:http-request-parent",
-      "componentName": "HttpRequest",
-      "componentQualifier": "TRK",
-      "status": "PENDING",
-      "submittedAt": "2015-09-21T19:28:54+0200",
-      "logs": true
-    }
-  ],
-  "current": {
-    "id": "AU_w8LDjgAS1Hm6h4-aY",
-    "type": "REPORT",
-    "componentId": "AU_w74XMgAS1Hm6h4-Y-",
-    "componentKey": "com.github.kevinsawicki:http-request-parent",
-    "componentName": "HttpRequest",
-    "componentQualifier": "TRK",
-    "analysisId": "123456",
-    "status": "SUCCESS",
-    "submittedAt": "2015-09-21T19:25:49+0200",
-    "startedAt": "2015-09-21T19:25:57+0200",
-    "finishedAt": "2015-09-21T19:25:58+0200",
-    "executionTimeMs": 1371,
-    "logs": true
-  }
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/is_queue_empty-example.txt b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/is_queue_empty-example.txt
deleted file mode 100644 (file)
index 27ba77d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-true
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/logs-example.log b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/logs-example.log
deleted file mode 100644 (file)
index 054509a..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-2015.11.02 10:25:16 INFO  [o.s.s.c.t.CeWorkerRunnableImpl] Execute task | project=com.sonarsource:java-markdown | id=AVDHg9OnLPOCEbN7mM58
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExtractReportStep] Analysis report extracted | compressedSize=63 KB
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Extract report | time=75ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep] SonarQube plugins:
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - Git 1.0 (scmgit)
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - SVN 1.2 (scmsvn)
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - Java 3.6 (java)
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep] Settings for module: com.sonarsource:java-markdown
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.binaries=/Users/teryk/Projects/java-markdown/target/classes
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.core.id=20151102092209
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.core.startTime=2015-11-02T09:22:09+0100
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.core.version=5.3-SNAPSHOT
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.host.url=http://localhost:9000
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.java.binaries=/Users/teryk/Projects/java-markdown/target/classes
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.java.libraries=/Users/teryk/.m2/repository/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar,/Users/teryk/.m2/repository/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.java.test.libraries=/Users/teryk/Projects/java-markdown/target/classes,/Users/teryk/.m2/repository/junit/junit/4.11/junit-4.11.jar,/Users/teryk/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar,/Users/teryk/.m2/repository/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar,/Users/teryk/.m2/repository/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.libraries=/Users/teryk/.m2/repository/org/easytesting/fest-assert/1.4/fest-assert-1.4.jar,/Users/teryk/.m2/repository/org/easytesting/fest-util/1.1.6/fest-util-1.1.6.jar
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.ci=
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.homepage=http://maven.apache.org
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.issue=
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.scm=
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.links.scm_dev=
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.maven.projectDependencies=[{"k":"junit:junit","v":"4.11","s":"test","d":[{"k":"org.hamcrest:hamcrest-core","v":"1.3","s":"test","d":[]}]},{"k":"org.easytesting:fest-assert","v":"1.4","s":"compile","d":[{"k":"org.easytesting:fest-util","v":"1.1.6","s":"compile","d":[]}]}]
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.moduleKey=com.sonarsource:java-markdown
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.mojoUseRunner=true
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.permission.template.default=default_template
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectBaseDir=/Users/teryk/Projects/java-markdown
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectBuildDir=/Users/teryk/Projects/java-markdown/target
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectKey=com.sonarsource:java-markdown
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectName=Java Markdown
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.projectVersion=1.0-SNAPSHOT
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.qualitygate=1
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.sourceEncoding=UTF-8
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.sources=/Users/teryk/Projects/java-markdown/pom.xml,/Users/teryk/Projects/java-markdown/src/main/java
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.tests=/Users/teryk/Projects/java-markdown/src/test/java
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.LogScannerContextStep]   - sonar.working.directory=/Users/teryk/Projects/java-markdown/target/sonar
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Log scanner context | time=3ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Build tree of components | time=36ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Validate project | time=4ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load debt model | time=5ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load quality profiles | time=121ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load Quality gate | time=8ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load differential periods | time=30ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute size measures | time=29ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute new coverage | time=39ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute coverage measures | time=11ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute comment measures | time=6ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Copy custom measures | time=29ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute duplication measures | time=3ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute language distribution | time=17ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute test measures | time=2ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute complexity measures | time=24ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Load measure computers | time=2ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   Execution time for each component visitor:
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - LoadComponentUuidsHavingOpenIssuesVisitor | time=5ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - IntegrateIssuesVisitor | time=182ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - CloseIssuesOnRemovedComponentsVisitor | time=0ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - SqaleMeasuresVisitor | time=4ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - SqaleNewMeasuresVisitor | time=0ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - LastCommitVisitor | time=0ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ExecuteVisitorsStep]   - MeasureComputersVisitor | time=3ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Execute component visitors | time=198ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute measure variations | time=3ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Computes Quality Gate measures | time=6ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Compute Quality profile measures | time=1ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Generate Quality profile events | time=4ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Generate Quality gate events | time=2ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist components | time=25ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist snapshots | time=26ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist measures | time=212ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist issues | time=59ms
-2015.11.02 10:25:17 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist project links | time=6ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist events | time=4ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist duplications | time=2ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist sources | time=286ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Persist tests | time=16ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Enable snapshot | time=8ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Index components | time=60ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Purge db | time=27ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Apply permissions | time=2ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Index issues | time=77ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Index tests | time=50ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.s.ComputationStepExecutor] Send issue notifications | time=2ms
-2015.11.02 10:25:18 INFO  [o.s.s.c.t.CeWorkerRunnableImpl] Executed task | project=com.sonarsource:java-markdown | id=AVDHg9OnLPOCEbN7mM58 | time=1706ms
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/submit-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/submit-example.json
deleted file mode 100644 (file)
index 7cee04f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "taskId": "TASK_1",
-  "projectId": "PROJECT_1"
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json
deleted file mode 100644 (file)
index 089e277..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "task": {
-    "id": "AVAn5RKqYwETbXvgas-I",
-    "type": "REPORT",
-    "componentId": "AVAn5RJmYwETbXvgas-H",
-    "componentKey": "project_1",
-    "componentName": "Project One",
-    "componentQualifier": "TRK",
-    "analysisId": "123456",
-    "status": "SUCCESS",
-    "submittedAt": "2015-10-02T11:32:15+0200",
-    "startedAt": "2015-10-02T11:32:16+0200",
-    "executedAt": "2015-10-02T11:32:22+0200",
-    "executionTimeMs": 5286,
-    "logs": true
-  }
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task_types-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task_types-example.json
deleted file mode 100644 (file)
index 6dd3019..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "taskTypes": [
-    "REPORT",
-    "DEV_REFRESH",
-    "DEV_PURGE",
-    "VIEW_REFRESH"
-  ]
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/log/CeFileAppenderFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/ce/log/CeFileAppenderFactoryTest.java
new file mode 100644 (file)
index 0000000..e39e96c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.core.FileAppender;
+import java.io.File;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CeFileAppenderFactoryTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Test
+  public void buildAppender() throws Exception {
+    File logsDir = temp.newFolder();
+    CeFileAppenderFactory factory = new CeFileAppenderFactory(logsDir);
+
+    FileAppender underTest = factory.buildAppender(new LoggerContext(), "uuid_1.log");
+
+    assertThat(new File(underTest.getFile())).isEqualTo(new File(logsDir, "uuid_1.log"));
+
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/log/CeLogAcceptFilterTest.java b/server/sonar-server/src/test/java/org/sonar/ce/log/CeLogAcceptFilterTest.java
new file mode 100644 (file)
index 0000000..87d9c6d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+import org.apache.log4j.MDC;
+import org.junit.After;
+import org.junit.Test;
+import org.sonar.ce.log.CeLogAcceptFilter;
+import org.sonar.ce.log.CeLogging;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CeLogAcceptFilterTest {
+
+  private static final Object UNUSED = "";
+
+  Filter underTest = new CeLogAcceptFilter();
+
+  @After
+  public void tearDown() {
+    MDC.clear();
+  }
+
+  @Test
+  public void reject_non_ce_logs() {
+    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.DENY);
+  }
+
+  @Test
+  public void accept_ce_logs() {
+    MDC.put(CeLogging.MDC_LOG_PATH, "abc.log");
+    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.ACCEPT);
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/log/CeLogDenyFilterTest.java b/server/sonar-server/src/test/java/org/sonar/ce/log/CeLogDenyFilterTest.java
new file mode 100644 (file)
index 0000000..e115892
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+import org.apache.log4j.MDC;
+import org.junit.After;
+import org.junit.Test;
+import org.sonar.ce.log.CeLogDenyFilter;
+import org.sonar.ce.log.CeLogging;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CeLogDenyFilterTest {
+
+  private static final Object UNUSED = "";
+
+  Filter underTest = new CeLogDenyFilter();
+
+  @After
+  public void tearDown() {
+    MDC.clear();
+  }
+
+  @Test
+  public void accept_non_ce_logs() {
+    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.ACCEPT);
+  }
+
+  @Test
+  public void deny_ce_logs() {
+    MDC.put(CeLogging.MDC_LOG_PATH, "abc.log");
+    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.DENY);
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/log/CeLoggingTest.java b/server/sonar-server/src/test/java/org/sonar/ce/log/CeLoggingTest.java
new file mode 100644 (file)
index 0000000..f0dbe0a
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.sift.SiftingAppender;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.joran.spi.JoranException;
+import com.google.common.base.Optional;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.sonar.api.config.Settings;
+import org.sonar.ce.log.CeLogAcceptFilter;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.process.LogbackHelper;
+import org.sonar.process.ProcessProperties;
+import org.sonar.ce.queue.CeTask;
+
+import static java.lang.String.format;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.ce.log.CeLogging.MDC_LOG_PATH;
+
+public class CeLoggingTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  private LogbackHelper helper = new LogbackHelper();
+  private File dataDir;
+
+  @Before
+  public void setUp() throws Exception {
+    this.dataDir = temp.newFolder();
+  }
+
+  @After
+  public void resetLogback() throws JoranException {
+    helper.resetFromXml("/logback-test.xml");
+  }
+
+  @After
+  public void cleanMDC() throws Exception {
+    MDC.clear();
+  }
+
+  @Test
+  public void getFile() throws IOException {
+    Settings settings = newSettings(dataDir, 10);
+
+    CeLogging underTest = new CeLogging(settings);
+    LogFileRef ref = new LogFileRef("TYPE1", "TASK1", "COMPONENT1");
+
+    // file does not exist
+    Optional<File> file = underTest.getFile(ref);
+    assertThat(file.isPresent()).isFalse();
+
+    File logFile = new File(dataDir, "ce/logs/" + ref.getRelativePath());
+    FileUtils.touch(logFile);
+    file = underTest.getFile(ref);
+    assertThat(file.isPresent()).isTrue();
+    assertThat(file.get()).isEqualTo(logFile);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_if_data_dir_is_not_set() {
+    new CeLogging(new Settings());
+  }
+
+  @Test
+  public void initForTask_adds_path_of_ce_log_file_in_MDC() throws IOException {
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
+
+    CeTask task = createCeTask("TYPE1", "U1");
+    underTest.initForTask(task);
+    assertThat(MDC.get(MDC_LOG_PATH)).isNotEmpty().isEqualTo(LogFileRef.from(task).getRelativePath());
+  }
+
+  @Test
+  public void clearForTask_throws_ISE_if_CE_appender_is_not_configured() throws IOException {
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
+
+    CeTask task = createCeTask("TYPE1", "U1");
+    underTest.initForTask(task);
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Appender with name ce is null or not a SiftingAppender");
+
+    underTest.clearForTask();
+  }
+
+  @Test
+  public void clearForTask_throws_ISE_if_CE_appender_is_not_a_SiftingAppender() throws IOException {
+    Appender<ILoggingEvent> mockCeAppender = mock(Appender.class);
+    when(mockCeAppender.getName()).thenReturn("ce");
+    helper.getRootContext().getLogger(Logger.ROOT_LOGGER_NAME).addAppender(mockCeAppender);
+
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
+
+    CeTask task = createCeTask("TYPE1", "U1");
+    underTest.initForTask(task);
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Appender with name ce is null or not a SiftingAppender");
+
+    underTest.clearForTask();
+  }
+
+  @Test
+  public void clearForTask_clears_MDC() throws IOException {
+    setupCeAppender();
+
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
+
+    CeTask task = createCeTask("TYPE1", "U1");
+    underTest.initForTask(task);
+    assertThat(MDC.get(MDC_LOG_PATH)).isNotEmpty().isEqualTo(LogFileRef.from(task).getRelativePath());
+
+    underTest.clearForTask();
+    assertThat(MDC.get(MDC_LOG_PATH)).isNull();
+  }
+
+  @Test
+  public void cleanForTask_stops_only_appender_for_MDC_value() throws IOException {
+    Logger rootLogger = setupCeAppender();
+
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
+
+    // init MDC
+    underTest.initForTask(createCeTask("TYPE1", "U1"));
+    verifyNoAppender(rootLogger);
+
+    // logging will create and start the appender
+    LoggerFactory.getLogger(getClass()).info("some log!");
+    verifyAllAppenderStarted(rootLogger, 1);
+
+    // init MDC and create appender for another task
+    // (in the same thread, which should not happen, but it's good enough for our test)
+    CeTask ceTask = createCeTask("TYPE1", "U2");
+    underTest.initForTask(ceTask);
+    LoggerFactory.getLogger(getClass()).info("some other log!");
+    verifyAllAppenderStarted(rootLogger, 2);
+
+    // stop appender which is currently referenced in MDC
+    underTest.clearForTask();
+
+    Appender appender = verifySingleAppenderIsStopped(rootLogger, 2);
+    assertThat(appender.getName()).isEqualTo("ce-" + LogFileRef.from(ceTask).getRelativePath());
+  }
+
+  @Test
+  public void delete_oldest_files_of_same_directory_to_keep_only_max_allowed_files() throws IOException {
+    for (int i = 1; i <= 5; i++) {
+      File file = new File(dataDir, format("U%d.log", i));
+      FileUtils.touch(file);
+      // see javadoc: "all platforms support file-modification times to the nearest second,
+      // but some provide more precision" --> increment by second, not by millisecond
+      file.setLastModified(1_450_000_000_000L + i * 1000);
+    }
+    assertThat(dataDir.listFiles()).hasSize(5);
+
+    // keep 3 files in each dir
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 3));
+    underTest.purgeDir(dataDir);
+
+    assertThat(dataDir.listFiles()).hasSize(3);
+    assertThat(dataDir.listFiles()).extracting("name")
+      .containsOnly("U3.log", "U4.log", "U5.log");
+  }
+
+  @Test
+  public void do_not_delete_files_if_dir_has_less_files_than_max_allowed() throws IOException {
+    FileUtils.touch(new File(dataDir, "U1.log"));
+
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
+    underTest.purgeDir(dataDir);
+
+    assertThat(dataDir.listFiles()).extracting("name").containsOnly("U1.log");
+  }
+
+  @Test
+  public void do_not_keep_any_logs() throws IOException {
+    FileUtils.touch(new File(dataDir, "U1.log"));
+
+    CeLogging underTest = new CeLogging(newSettings(dataDir, 0));
+    underTest.purgeDir(dataDir);
+
+    assertThat(dataDir.listFiles()).isEmpty();
+  }
+
+  @Test
+  public void fail_if_max_logs_settings_is_negative() throws IOException {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Property sonar.ce.maxLogsPerTask must be positive. Got: -1");
+
+    Settings settings = newSettings(dataDir, -1);
+    CeLogging logging = new CeLogging(settings);
+    logging.purgeDir(dataDir);
+  }
+
+  @Test
+  public void createConfiguration() throws Exception {
+    SiftingAppender siftingAppender = CeLogging.createAppenderConfiguration(new LoggerContext(), dataDir);
+
+    // filter on CE logs
+    List<Filter<ILoggingEvent>> filters = siftingAppender.getCopyOfAttachedFiltersList();
+    assertThat(filters).hasSize(1);
+    assertThat(filters.get(0)).isInstanceOf(CeLogAcceptFilter.class);
+
+    assertThat(siftingAppender.getDiscriminator().getKey()).isEqualTo(MDC_LOG_PATH);
+    assertThat(siftingAppender.getTimeout().getMilliseconds()).isEqualTo(1000 * 60 * 2);
+  }
+
+  private Logger setupCeAppender() {
+    Logger rootLogger = helper.getRootContext().getLogger(Logger.ROOT_LOGGER_NAME);
+    rootLogger.addAppender(CeLogging.createAppenderConfiguration(helper.getRootContext(), dataDir));
+    return rootLogger;
+  }
+
+  private void verifyNoAppender(Logger rootLogger) {
+    Collection<Appender<ILoggingEvent>> allAppenders = getAllAppenders(rootLogger);
+    assertThat(allAppenders).isEmpty();
+  }
+
+  private void verifyAllAppenderStarted(Logger rootLogger, int expectedSize) {
+    Collection<Appender<ILoggingEvent>> allAppenders = getAllAppenders(rootLogger);
+    assertThat(allAppenders).hasSize(expectedSize);
+    for (Appender<ILoggingEvent> appender : allAppenders) {
+      assertThat(appender.isStarted()).isTrue();
+    }
+  }
+
+  private Appender verifySingleAppenderIsStopped(Logger rootLogger, int expectedSize) {
+    Collection<Appender<ILoggingEvent>> allAppenders = getAllAppenders(rootLogger);
+    assertThat(allAppenders).hasSize(expectedSize);
+    Appender res = null;
+    for (Appender<ILoggingEvent> appender : allAppenders) {
+      if (!appender.isStarted()) {
+        assertThat(res).describedAs("More than one appender found stopped").isNull();
+        res = appender;
+      }
+    }
+    assertThat(res).describedAs("There should be one stopped appender").isNotNull();
+    return res;
+  }
+
+  private Collection<Appender<ILoggingEvent>> getAllAppenders(Logger rootLogger) {
+    Appender<ILoggingEvent> ceAppender = rootLogger.getAppender("ce");
+    assertThat(ceAppender).isInstanceOf(SiftingAppender.class);
+    return ((SiftingAppender) ceAppender).getAppenderTracker().allComponents();
+  }
+
+  private static Settings newSettings(File dataDir, int maxLogs) {
+    Settings settings = new Settings();
+    settings.setProperty(ProcessProperties.PATH_DATA, dataDir.getAbsolutePath());
+    settings.setProperty(CeLogging.MAX_LOGS_PROPERTY, maxLogs);
+    return settings;
+  }
+
+  private static CeTask createCeTask(String type, String uuid) {
+    return new CeTask.Builder().setType(type).setUuid(uuid).build();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/log/LogFileRefTest.java b/server/sonar-server/src/test/java/org/sonar/ce/log/LogFileRefTest.java
new file mode 100644 (file)
index 0000000..cbd9088
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.log;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.db.ce.CeTaskTypes;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class LogFileRefTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Test
+  public void equals_hashCode() {
+    LogFileRef ref1 = new LogFileRef(CeTaskTypes.REPORT, "UUID_1", "COMPONENT_1");
+    LogFileRef ref1bis = new LogFileRef(CeTaskTypes.REPORT, "UUID_1", "COMPONENT_1");
+    LogFileRef ref2 = new LogFileRef(CeTaskTypes.REPORT, "UUID_2", "COMPONENT_1");
+
+    assertThat(ref1.equals(ref1)).isTrue();
+    assertThat(ref1.equals(ref1bis)).isTrue();
+    assertThat(ref1.equals(ref2)).isFalse();
+    assertThat(ref1.equals(null)).isFalse();
+    assertThat(ref1.equals("UUID_1")).isFalse();
+
+    assertThat(ref1.hashCode()).isEqualTo(ref1bis.hashCode());
+  }
+
+  @Test
+  public void getRelativePath() {
+    assertThat(new LogFileRef("TYPE_1", "UUID_1", "COMPONENT_1").getRelativePath()).isEqualTo("TYPE_1/COMPONENT_1/UUID_1.log");
+    assertThat(new LogFileRef("TYPE_1", "UUID_1", null).getRelativePath()).isEqualTo("TYPE_1/UUID_1.log");
+  }
+
+  @Test
+  public void do_not_accept_invalid_task_type() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("'foo/bar' is not a valid filename for Compute Engine logs");
+
+    new LogFileRef("foo/bar", "UUID", null);
+  }
+
+  @Test
+  public void do_not_accept_invalid_uuid() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("'foo/bar' is not a valid filename for Compute Engine logs");
+
+    new LogFileRef("REPORT", "foo/bar", null);
+  }
+
+  @Test
+  public void do_not_accept_invalid_component_uuid() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("'foo/bar' is not a valid filename for Compute Engine logs");
+
+    new LogFileRef("REPORT", "UUID", "foo/bar");
+  }
+
+  @Test
+  public void filename_must_support_uuid() {
+    String uuid = "AU-Tpxb-_iU5OvuD2FLy";
+    assertThat(LogFileRef.requireValidFilename(uuid)).isEqualTo(uuid);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java b/server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java
new file mode 100644 (file)
index 0000000..edaaf9c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.monitoring;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Test;
+import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CEQueueStatusImplConcurrentTest {
+  private ExecutorService executorService = Executors.newFixedThreadPool(10, new ThreadFactory() {
+    private int cnt = 0;
+
+    @Override
+    public Thread newThread(Runnable r) {
+      return new Thread(r, CEQueueStatusImplConcurrentTest.class.getSimpleName() + cnt++);
+    }
+  });
+  private CEQueueStatusImpl underTest = new CEQueueStatusImpl();
+
+  @After
+  public void tearDown() throws Exception {
+    executorService.shutdownNow();
+  }
+
+  @Test
+  public void test_concurrent_modifications_in_any_order() throws InterruptedException {
+    long initialPendingCount = 9963L;
+    underTest.initPendingCount(initialPendingCount);
+
+    for (Runnable runnable : buildShuffleCallsToUnderTest()) {
+      executorService.submit(runnable);
+    }
+
+    executorService.awaitTermination(1, TimeUnit.SECONDS);
+
+    assertThat(underTest.getReceivedCount()).isEqualTo(100);
+    assertThat(underTest.getPendingCount()).isEqualTo(initialPendingCount + 2);
+    assertThat(underTest.getInProgressCount()).isEqualTo(1);
+    assertThat(underTest.getErrorCount()).isEqualTo(17);
+    assertThat(underTest.getSuccessCount()).isEqualTo(80);
+    assertThat(underTest.getProcessingTime()).isEqualTo(177);
+  }
+
+  private List<Runnable> buildShuffleCallsToUnderTest() {
+    List<Runnable> res = new ArrayList<>();
+    for (int i = 0; i < 100; i++) {
+      res.add(new AddReceivedRunnable());
+    }
+    for (int i = 0; i < 98; i++) {
+      res.add(new AddInProgressRunnable());
+    }
+    for (int i = 0; i < 80; i++) {
+      res.add(new AddSuccessRunnable());
+    }
+    for (int i = 0; i < 17; i++) {
+      res.add(new AddErrorRunnable());
+    }
+    Collections.shuffle(res);
+    return res;
+  }
+
+  private class AddReceivedRunnable implements Runnable {
+    @Override
+    public void run() {
+      underTest.addReceived();
+    }
+  }
+
+  private class AddInProgressRunnable implements Runnable {
+    @Override
+    public void run() {
+      underTest.addInProgress();
+    }
+  }
+
+  private class AddErrorRunnable implements Runnable {
+    @Override
+    public void run() {
+      underTest.addError(1);
+    }
+  }
+
+  private class AddSuccessRunnable implements Runnable {
+    @Override
+    public void run() {
+      underTest.addSuccess(2);
+    }
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/property/CePropertyDefinitionsTest.java b/server/sonar-server/src/test/java/org/sonar/ce/property/CePropertyDefinitionsTest.java
new file mode 100644 (file)
index 0000000..bd21696
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.property;
+
+import org.junit.Test;
+import org.sonar.test.TestUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CePropertyDefinitionsTest {
+
+  @Test
+  public void all() {
+    assertThat(CePropertyDefinitions.all()).isNotEmpty();
+  }
+
+  @Test
+  public void only_statics() {
+    assertThat(TestUtils.hasOnlyPrivateConstructors(CePropertyDefinitions.class)).isTrue();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java b/server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java
new file mode 100644 (file)
index 0000000..d18f19e
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import com.google.common.base.Optional;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.ce.monitoring.CEQueueStatus;
+import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryImpl;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.startsWith;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class CeQueueImplTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  System2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
+
+  @Rule
+  public DbTester dbTester = DbTester.create(system2);
+  DbSession session = dbTester.getSession();
+
+  UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
+  CEQueueStatus queueStatus = new CEQueueStatusImpl();
+  CeQueueListener listener = mock(CeQueueListener.class);
+  CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
+
+  @Before
+  public void setUp() throws Exception {
+    queueStatus.initPendingCount(0);
+  }
+
+  @Test
+  public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
+    CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
+    CeTask task = underTest.submit(taskSubmit);
+
+    verifyCeTask(taskSubmit, task, null);
+    verifyCeQueueDtoForTaskSubmit(taskSubmit);
+  }
+
+  @Test
+  public void submit_increments_receivedCount_of_QueueStatus() {
+    underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(1L);
+
+    underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_2", "rob"));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
+  }
+
+  @Test
+  public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
+    ComponentDto componentDto = insertComponent(newComponentDto("PROJECT_1"));
+    CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null);
+
+    CeTask task = underTest.submit(taskSubmit);
+
+    verifyCeTask(taskSubmit, task, componentDto);
+  }
+
+  @Test
+  public void submit_returns_task_without_component_info_when_submit_has_none() {
+    CeTaskSubmit taskSubmit = createTaskSubmit("not cpt related");
+
+    CeTask task = underTest.submit(taskSubmit);
+
+    verifyCeTask(taskSubmit, task, null);
+  }
+
+  @Test
+  public void submit_fails_with_ISE_if_paused() {
+    underTest.pauseSubmit();
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Compute Engine does not currently accept new tasks");
+
+    submit(CeTaskTypes.REPORT, "PROJECT_1");
+  }
+
+  @Test
+  public void massSubmit_returns_tasks_for_each_CeTaskSubmit_populated_from_CeTaskSubmit_and_creates_CeQueue_row_for_each() {
+    CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
+    CeTaskSubmit taskSubmit2 = createTaskSubmit("some type");
+
+    List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
+
+    assertThat(tasks).hasSize(2);
+    verifyCeTask(taskSubmit1, tasks.get(0), null);
+    verifyCeTask(taskSubmit2, tasks.get(1), null);
+    verifyCeQueueDtoForTaskSubmit(taskSubmit1);
+    verifyCeQueueDtoForTaskSubmit(taskSubmit2);
+  }
+
+  @Test
+  public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() {
+    ComponentDto componentDto1 = insertComponent(newComponentDto("PROJECT_1"));
+    CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null);
+    CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null);
+
+    List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
+
+    assertThat(tasks).hasSize(2);
+    verifyCeTask(taskSubmit1, tasks.get(0), componentDto1);
+    verifyCeTask(taskSubmit2, tasks.get(1), null);
+  }
+
+  @Test
+  public void massSubmit_increments_receivedCount_of_QueueStatus() {
+    underTest.massSubmit(asList(createTaskSubmit("type 1"), createTaskSubmit("type 2")));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
+
+    underTest.massSubmit(asList(createTaskSubmit("a"), createTaskSubmit("a"), createTaskSubmit("b")));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(5L);
+  }
+
+
+  @Test
+  public void cancel_pending() throws Exception {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+
+    // ignore
+    boolean canceled = underTest.cancel("UNKNOWN");
+    assertThat(canceled).isFalse();
+    verifyZeroInteractions(listener);
+
+    canceled = underTest.cancel(task.getUuid());
+    assertThat(canceled).isTrue();
+    Optional<CeActivityDto> activity = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(activity.isPresent()).isTrue();
+    assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    verify(listener).onRemoved(task, CeActivityDto.Status.CANCELED);
+  }
+
+  @Test
+  public void fail_to_cancel_if_in_progress() throws Exception {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(startsWith("Task is in progress and can't be canceled"));
+
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+
+    dbTester.getDbClient().ceQueueDao().peek(session);
+
+    underTest.cancel(task.getUuid());
+  }
+
+  @Test
+  public void cancelAll_pendings_but_not_in_progress() throws Exception {
+    CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2");
+    CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3");
+
+    dbTester.getDbClient().ceQueueDao().peek(session);
+
+    int canceledCount = underTest.cancelAll();
+    assertThat(canceledCount).isEqualTo(2);
+
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask1.getUuid());
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask2.getUuid());
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), inProgressTask.getUuid());
+    assertThat(history.isPresent()).isFalse();
+
+    verify(listener).onRemoved(pendingTask1, CeActivityDto.Status.CANCELED);
+    verify(listener).onRemoved(pendingTask2, CeActivityDto.Status.CANCELED);
+  }
+
+  @Test
+  public void pause_and_resume_submits() throws Exception {
+    assertThat(underTest.isSubmitPaused()).isFalse();
+    underTest.pauseSubmit();
+    assertThat(underTest.isSubmitPaused()).isTrue();
+    underTest.resumeSubmit();
+    assertThat(underTest.isSubmitPaused()).isFalse();
+  }
+
+  private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto) {
+    assertThat(task.getUuid()).isEqualTo(taskSubmit.getUuid());
+    assertThat(task.getComponentUuid()).isEqualTo(task.getComponentUuid());
+    assertThat(task.getType()).isEqualTo(taskSubmit.getType());
+    if (componentDto == null) {
+      assertThat(task.getComponentKey()).isNull();
+      assertThat(task.getComponentName()).isNull();
+    } else {
+      assertThat(task.getComponentKey()).isEqualTo(componentDto.key());
+      assertThat(task.getComponentName()).isEqualTo(componentDto.name());
+    }
+    assertThat(task.getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin());
+  }
+
+  private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) {
+    Optional<CeQueueDto> queueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), taskSubmit.getUuid());
+    assertThat(queueDto.isPresent()).isTrue();
+    assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType());
+    assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid());
+    assertThat(queueDto.get().getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin());
+    assertThat(queueDto.get().getCreatedAt()).isEqualTo(1_450_000_000_000L);
+  }
+
+  private static ComponentDto newComponentDto(String uuid) {
+    return new ComponentDto().setUuid(uuid).setName("name_" + uuid).setKey("key_" + uuid);
+  }
+
+  private CeTask submit(String reportType, String componentUuid) {
+    return underTest.submit(createTaskSubmit(reportType, componentUuid, null));
+  }
+
+  private CeTaskSubmit createTaskSubmit(String type) {
+    return createTaskSubmit(type, null, null);
+  }
+
+  private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUuid, @Nullable String submitterLogin) {
+    CeTaskSubmit.Builder submission = underTest.prepareSubmit();
+    submission.setType(type);
+    submission.setComponentUuid(componentUuid);
+    submission.setSubmitterLogin(submitterLogin);
+    return submission.build();
+  }
+
+  private CeTaskResult newTaskResult(Long snapshotId) {
+    CeTaskResult taskResult = mock(CeTaskResult.class);
+    when(taskResult.getSnapshotId()).thenReturn(snapshotId);
+    return taskResult;
+  }
+
+  private ComponentDto insertComponent(ComponentDto componentDto) {
+    dbTester.getDbClient().componentDao().insert(session, componentDto);
+    session.commit();
+    return componentDto;
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/queue/CeTaskTest.java b/server/sonar-server/src/test/java/org/sonar/ce/queue/CeTaskTest.java
new file mode 100644 (file)
index 0000000..f0759f5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CeTaskTest {
+
+  @Test
+  public void build() {
+    CeTask.Builder builder = new CeTask.Builder();
+    builder.setType("TYPE_1");
+    builder.setUuid("UUID_1");
+    builder.setSubmitterLogin("LOGIN_1");
+    builder.setComponentKey("COMPONENT_KEY_1");
+    builder.setComponentUuid("COMPONENT_UUID_1");
+    builder.setComponentName("The component");
+    CeTask task = builder.build();
+
+    assertThat(task.getType()).isEqualTo("TYPE_1");
+    assertThat(task.getUuid()).isEqualTo("UUID_1");
+    assertThat(task.getSubmitterLogin()).isEqualTo("LOGIN_1");
+    assertThat(task.getComponentKey()).isEqualTo("COMPONENT_KEY_1");
+    assertThat(task.getComponentUuid()).isEqualTo("COMPONENT_UUID_1");
+    assertThat(task.getComponentName()).isEqualTo("The component");
+  }
+
+  @Test
+  public void equals_and_hashCode_on_uuid() {
+    CeTask.Builder builder1 = new CeTask.Builder().setType("TYPE_1").setUuid("UUID_1");
+    CeTask task1 = builder1.build();
+    CeTask task1bis = builder1.build();
+    CeTask task2 = new CeTask.Builder().setType("TYPE_1").setUuid("UUID_2").build();
+
+    assertThat(task1.equals(task1)).isTrue();
+    assertThat(task1.equals(task1bis)).isTrue();
+    assertThat(task1.equals(task2)).isFalse();
+    assertThat(task1.hashCode()).isEqualTo(task1.hashCode());
+    assertThat(task1.hashCode()).isEqualTo(task1bis.hashCode());
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/queue/report/ReportSubmitterTest.java b/server/sonar-server/src/test/java/org/sonar/ce/queue/report/ReportSubmitterTest.java
new file mode 100644 (file)
index 0000000..80ddfdc
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.queue.report;
+
+import org.apache.commons.io.IOUtils;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.NewComponent;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeQueueImpl;
+import org.sonar.ce.queue.CeTaskSubmit;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.permission.PermissionService;
+import org.sonar.server.tester.UserSessionRule;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class ReportSubmitterTest {
+
+  static final String PROJECT_KEY = "MY_PROJECT";
+  static final String PROJECT_UUID = "P1";
+  static final String PROJECT_NAME = "My Project";
+  static final String TASK_UUID = "TASK_1";
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  CeQueue queue = mock(CeQueueImpl.class);
+  ReportFiles reportFiles = mock(ReportFiles.class);
+  ComponentService componentService = mock(ComponentService.class);
+  PermissionService permissionService = mock(PermissionService.class);
+  ReportSubmitter underTest = new ReportSubmitter(queue, userSession, reportFiles, componentService, permissionService);
+
+  @Test
+  public void submit_a_report_on_existing_project() {
+    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(new ComponentDto().setUuid(PROJECT_UUID));
+
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+
+    verifyZeroInteractions(permissionService);
+    verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
+      @Override
+      protected boolean matchesSafely(CeTaskSubmit submit) {
+        return submit.getType().equals(CeTaskTypes.REPORT) && submit.getComponentUuid().equals(PROJECT_UUID) &&
+          submit.getUuid().equals(TASK_UUID);
+      }
+
+      @Override
+      public void describeTo(Description description) {
+
+      }
+    }));
+  }
+
+  @Test
+  public void provision_project_if_does_not_exist() throws Exception {
+    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.PROVISIONING);
+
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
+    when(componentService.create(any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
+
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+
+    verify(permissionService).applyDefaultPermissionTemplate(PROJECT_KEY);
+    verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
+      @Override
+      protected boolean matchesSafely(CeTaskSubmit submit) {
+        return submit.getType().equals(CeTaskTypes.REPORT) && submit.getComponentUuid().equals(PROJECT_UUID) &&
+          submit.getUuid().equals(TASK_UUID);
+      }
+
+      @Override
+      public void describeTo(Description description) {
+
+      }
+    }));
+  }
+
+  @Test
+  public void submit_a_report_on_new_project_with_global_scan_permission() {
+    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
+    when(componentService.create(any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
+
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+
+    verify(queue).submit(any(CeTaskSubmit.class));
+  }
+
+  @Test
+  public void submit_a_report_on_existing_project_with_global_scan_permission() {
+    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(new ComponentDto().setUuid(PROJECT_UUID));
+
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+
+    verify(queue).submit(any(CeTaskSubmit.class));
+  }
+
+  @Test
+  public void submit_a_report_on_existing_project_with_project_scan_permission() {
+    userSession.addProjectPermissions(GlobalPermissions.SCAN_EXECUTION, PROJECT_KEY);
+
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(new ComponentDto().setUuid(PROJECT_UUID));
+
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+
+    verify(queue).submit(any(CeTaskSubmit.class));
+  }
+
+  @Test
+  public void fail_with_forbidden_exception_when_no_scan_permission() {
+    userSession.setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING);
+
+    thrown.expect(ForbiddenException.class);
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+  }
+
+  @Test
+  public void fail_with_forbidden_exception_on_new_project_when_only_project_scan_permission() {
+    userSession.addProjectPermissions(GlobalPermissions.SCAN_EXECUTION, PROJECT_KEY);
+
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
+    when(componentService.create(any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
+
+    thrown.expect(ForbiddenException.class);
+    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/taskprocessor/ReportTaskProcessorDeclarationTest.java b/server/sonar-server/src/test/java/org/sonar/ce/taskprocessor/ReportTaskProcessorDeclarationTest.java
new file mode 100644 (file)
index 0000000..14035aa
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.taskprocessor;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.ce.queue.CeTask;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ReportTaskProcessorDeclarationTest {
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private ReportTaskProcessorDeclaration underTest = new ReportTaskProcessorDeclaration();
+
+  @Test
+  public void getHandledCeTaskTypes_returns_REPORT() {
+    assertThat(underTest.getHandledCeTaskTypes()).containsOnly("REPORT");
+  }
+
+  @Test
+  public void process_throws_UOE() {
+    expectedException.expect(UnsupportedOperationException.class);
+    expectedException.expectMessage("process must not be called in WebServer");
+
+    underTest.process(mock(CeTask.class));
+  }
+}
index 7fce78e110ba03aefb3361f0ea60c594ddcab6e6..762a59bae01d3ae55b43caa188df3ea9bcf925aa 100644 (file)
@@ -32,6 +32,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.ce.log.CeFileAppenderFactory;
 import org.sonar.process.LogbackHelper;
 import org.sonar.process.ProcessProperties;
 import org.sonar.process.Props;
@@ -51,7 +52,7 @@ public class ServerProcessLoggingTest {
 
   /**
    * Path to data dir must be set for Compute Engine logging.
-   * @see org.sonar.server.computation.log.CeFileAppenderFactory
+   * @see CeFileAppenderFactory
    */
   @Before
   public void setUp() throws IOException {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
new file mode 100644 (file)
index 0000000..59b6d46
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.JsonAssert;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.WsCe;
+import org.sonarqube.ws.WsCe.ActivityResponse;
+import org.sonarqube.ws.client.ce.CeWsParameters;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.utils.DateUtils.formatDate;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_STATUS;
+
+public class ActivityActionTest {
+
+  private static final long EXECUTED_AT = System2.INSTANCE.now();
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  ComponentDbTester componentDb = new ComponentDbTester(dbTester);
+
+  CeLogging ceLogging = mock(CeLogging.class);
+  TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), ceLogging, System2.INSTANCE);
+  ActivityAction underTest = new ActivityAction(userSession, dbTester.getDbClient(), formatter, new CeTaskProcessor[] {mock(CeTaskProcessor.class)});
+  WsActionTester ws = new WsActionTester(underTest);
+
+  @Before
+  public void setUp() {
+    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.<File>absent());
+  }
+
+  @Test
+  public void get_all_past_activity() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+
+    ActivityResponse activityResponse = call(ws.newRequest()
+      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, formatDateTime(EXECUTED_AT + 2_000)));
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(2);
+    // chronological order, from newest to oldest
+    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T2");
+    assertThat(activityResponse.getTasks(0).getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
+    assertThat(activityResponse.getTasks(0).getComponentId()).isEqualTo("PROJECT_2");
+    assertThat(activityResponse.getTasks(0).getAnalysisId()).isEqualTo("123456");
+    assertThat(activityResponse.getTasks(0).getExecutionTimeMs()).isEqualTo(500L);
+    assertThat(activityResponse.getTasks(0).getLogs()).isFalse();
+    assertThat(activityResponse.getTasks(1).getId()).isEqualTo("T1");
+    assertThat(activityResponse.getTasks(1).getStatus()).isEqualTo(WsCe.TaskStatus.SUCCESS);
+    assertThat(activityResponse.getTasks(1).getComponentId()).isEqualTo("PROJECT_1");
+    assertThat(activityResponse.getTasks(1).getLogs()).isFalse();
+  }
+
+  @Test
+  public void filter_by_status() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+
+    ActivityResponse activityResponse = call(ws.newRequest()
+      .setParam("status", "FAILED,IN_PROGRESS"));
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(2);
+    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T3");
+    assertThat(activityResponse.getTasks(1).getId()).isEqualTo("T2");
+  }
+
+  @Test
+  public void filter_by_max_executed_at_exclude() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+
+    ActivityResponse activityResponse = call(ws.newRequest()
+      .setParam("status", "FAILED,IN_PROGRESS,SUCCESS")
+      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, "2016-02-15"));
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(0);
+  }
+
+  @Test
+  public void filter_by_max_executed_at_include_day_filled() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    String today = formatDate(new Date(EXECUTED_AT));
+    System.out.println(EXECUTED_AT + " - " + today);
+
+    ActivityResponse activityResponse = call(ws.newRequest()
+      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, today));
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(1);
+  }
+
+  @Test
+  public void filter_on_current_activities() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    // T2 is the current activity (the most recent one)
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_1", CeActivityDto.Status.FAILED);
+    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.PENDING);
+
+    ActivityResponse activityResponse = call(
+      ws.newRequest()
+        .setParam("onlyCurrents", "true"));
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(1);
+    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T2");
+  }
+
+  @Test
+  public void paginate_results() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+
+    assertPage(1, 1, 3, asList("T3"));
+    assertPage(2, 1, 3, asList("T2"));
+    assertPage(1, 10, 3, asList("T3", "T2", "T1"));
+    assertPage(2, 10, 3, Collections.<String>emptyList());
+  }
+
+  private void assertPage(int pageIndex, int pageSize, int expectedTotal, List<String> expectedOrderedTaskIds) {
+    ActivityResponse activityResponse = call(ws.newRequest()
+      .setParam(Param.PAGE, Integer.toString(pageIndex))
+      .setParam(Param.PAGE_SIZE, Integer.toString(pageSize))
+      .setParam(PARAM_STATUS, "SUCCESS,FAILED,CANCELED,IN_PROGRESS,PENDING"));
+
+    assertThat(activityResponse.getPaging().getPageIndex()).isEqualTo(pageIndex);
+    assertThat(activityResponse.getPaging().getPageSize()).isEqualTo(pageSize);
+    assertThat(activityResponse.getPaging().getTotal()).isEqualTo(expectedTotal);
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(expectedOrderedTaskIds.size());
+    for (int i = 0; i < expectedOrderedTaskIds.size(); i++) {
+      String expectedTaskId = expectedOrderedTaskIds.get(i);
+      assertThat(activityResponse.getTasks(i).getId()).isEqualTo(expectedTaskId);
+    }
+  }
+
+  @Test
+  public void project_administrator_can_access_his_project_activity() {
+    // no need to be a system admin
+    userSession.addComponentUuidPermission(UserRole.ADMIN, "PROJECT_1", "PROJECT_1");
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+
+    ActivityResponse activityResponse = call(ws.newRequest().setParam("componentId", "PROJECT_1"));
+
+    assertThat(activityResponse.getTasksCount()).isEqualTo(1);
+    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T1");
+    assertThat(activityResponse.getTasks(0).getStatus()).isEqualTo(WsCe.TaskStatus.SUCCESS);
+    assertThat(activityResponse.getTasks(0).getComponentId()).isEqualTo("PROJECT_1");
+  }
+
+  @Test
+  public void search_activity_by_component_name() throws IOException {
+    componentDb.insertProjectAndSnapshot(newProjectDto().setName("apache struts").setUuid("P1"));
+    componentDb.insertProjectAndSnapshot(newProjectDto().setName("apache zookeeper").setUuid("P2"));
+    componentDb.insertProjectAndSnapshot(newProjectDto().setName("eclipse").setUuid("P3"));
+    dbTester.commit();
+    componentDb.indexProjects();
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    insertActivity("T1", "P1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "P2", CeActivityDto.Status.SUCCESS);
+    insertActivity("T3", "P3", CeActivityDto.Status.SUCCESS);
+
+    ActivityResponse activityResponse = call(ws.newRequest().setParam(PARAM_COMPONENT_QUERY, "apac"));
+
+    assertThat(activityResponse.getTasksList()).extracting("id").containsOnly("T1", "T2");
+  }
+
+  @Test
+  public void search_task_id_in_queue_ignoring_other_parameters() throws IOException {
+    insertQueue("T1", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+
+    ActivityResponse result = call(
+      ws.newRequest()
+        .setParam(Param.TEXT_QUERY, "T1")
+        .setParam(PARAM_STATUS, CeQueueDto.Status.PENDING.name()));
+
+    assertThat(result.getTasksCount()).isEqualTo(1);
+    assertThat(result.getTasks(0).getId()).isEqualTo("T1");
+  }
+
+  @Test
+  public void search_task_id_in_activity() {
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+
+    ActivityResponse result = call(ws.newRequest().setParam(Param.TEXT_QUERY, "T1"));
+
+    assertThat(result.getTasksCount()).isEqualTo(1);
+    assertThat(result.getTasks(0).getId()).isEqualTo("T1");
+  }
+
+  @Test
+  public void fail_if_both_filters_on_component_id_and_name() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("componentId and componentQuery must not be set at the same time");
+
+    ws.newRequest()
+      .setParam("componentId", "ID1")
+      .setParam("componentQuery", "apache")
+      .setMediaType(MediaTypes.PROTOBUF)
+      .execute();
+  }
+
+  @Test
+  public void fail_if_page_size_greater_than_1000() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("The 'ps' parameter must be less than 1000");
+
+    ws.newRequest()
+      .setParam(Param.PAGE_SIZE, "1001")
+      .execute();
+  }
+
+  @Test
+  public void fail_if_date_is_not_well_formatted() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Date 'ill-formatted-date' cannot be parsed as either a date or date+time");
+
+    ws.newRequest()
+      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, "ill-formatted-date")
+      .execute();
+  }
+
+  @Test
+  public void support_json_response() {
+    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    TestResponse wsResponse = ws.newRequest()
+      .setMediaType(MediaTypes.JSON)
+      .execute();
+
+    JsonAssert.assertJson(wsResponse.getInput()).isSimilarTo("{\"tasks\":[]}");
+  }
+
+  private CeQueueDto insertQueue(String taskUuid, String componentUuid, CeQueueDto.Status status) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setUuid(taskUuid);
+    queueDto.setStatus(status);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.commit();
+    return queueDto;
+  }
+
+  private CeActivityDto insertActivity(String taskUuid, String componentUuid, CeActivityDto.Status status) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setUuid(taskUuid);
+    CeActivityDto activityDto = new CeActivityDto(queueDto);
+    activityDto.setStatus(status);
+    activityDto.setExecutionTimeMs(500L);
+    activityDto.setExecutedAt(EXECUTED_AT);
+    activityDto.setSnapshotId(123_456L);
+    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
+    dbTester.commit();
+    return activityDto;
+  }
+
+  private static ActivityResponse call(TestRequest request) {
+    try {
+      return ActivityResponse.parseFrom(
+        request
+          .setMediaType(MediaTypes.PROTOBUF)
+          .execute().getInputStream());
+    } catch (IOException e) {
+      throw Throwables.propagate(e);
+    }
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java
new file mode 100644 (file)
index 0000000..22d25b9
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbTester;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+public class CancelActionTest {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  CeQueue queue = mock(CeQueue.class);
+  CancelAction underTest = new CancelAction(userSession, queue);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void cancel_pending_task() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    tester.newRequest()
+      .setParam("id", "T1")
+      .execute();
+
+    verify(queue).cancel("T1");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void missing_id() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    tester.newRequest().execute();
+
+    verifyZeroInteractions(queue);
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void not_authorized() {
+    tester.newRequest()
+      .setParam("id", "T1")
+      .execute();
+
+    verifyZeroInteractions(queue);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CancelAllActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CancelAllActionTest.java
new file mode 100644 (file)
index 0000000..648bafc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbTester;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+public class CancelAllActionTest {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  CeQueue queue = mock(CeQueue.class);
+  CancelAllAction underTest = new CancelAllAction(userSession, queue);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void cancel_all_pending_tasks() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    tester.newRequest().execute();
+
+    verify(queue).cancelAll();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void not_authorized() {
+    tester.newRequest().execute();
+
+    verifyZeroInteractions(queue);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java
new file mode 100644 (file)
index 0000000..75eb84a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.ce.ws.CeWsModule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CeWsModuleTest {
+
+  @Test
+  public void verify_count_of_added_components() {
+    ComponentContainer container = new ComponentContainer();
+    new CeWsModule().configure(container);
+    assertThat(container.size()).isEqualTo(11 + 2 /* injected by ComponentContainer */);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsTest.java
new file mode 100644 (file)
index 0000000..1ec0618
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.ce.queue.report.ReportSubmitter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class CeWsTest {
+
+  @Test
+  public void define() throws Exception {
+    CeWsAction wsAction = new SubmitAction(mock(ReportSubmitter.class));
+
+    CeWs ws = new CeWs(wsAction);
+    WebService.Context context = mock(WebService.Context.class, Mockito.RETURNS_DEEP_STUBS);
+    ws.define(context);
+
+    assertThat(context.controller("api/ce")).isNotNull();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java
new file mode 100644 (file)
index 0000000..ff27f00
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import java.io.File;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Protobuf;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonarqube.ws.MediaTypes;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.WsCe;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ComponentActionTest {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  CeLogging ceLogging = mock(CeLogging.class);
+  TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), ceLogging, System2.INSTANCE);
+  ComponentAction underTest = new ComponentAction(userSession, dbTester.getDbClient(), formatter);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Before
+  public void setUp() {
+    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.<File>absent());
+  }
+
+  @Test
+  public void empty_queue_and_empty_activity() {
+    userSession.addComponentUuidPermission(UserRole.USER, "PROJECT_1", "PROJECT_1");
+
+    TestResponse wsResponse = tester.newRequest()
+      .setParam("componentId", "PROJECT_1")
+      .setMediaType(MediaTypes.PROTOBUF)
+      .execute();
+
+    WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
+    assertThat(response.getQueueCount()).isEqualTo(0);
+    assertThat(response.hasCurrent()).isFalse();
+  }
+
+  @Test
+  public void project_tasks() {
+    userSession.addComponentUuidPermission(UserRole.USER, "PROJECT_1", "PROJECT_1");
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+    insertActivity("T3", "PROJECT_1", CeActivityDto.Status.FAILED);
+    insertQueue("T4", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T5", "PROJECT_1", CeQueueDto.Status.PENDING);
+
+    TestResponse wsResponse = tester.newRequest()
+      .setParam("componentId", "PROJECT_1")
+      .setMediaType(MediaTypes.PROTOBUF)
+      .execute();
+
+    WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
+    assertThat(response.getQueueCount()).isEqualTo(2);
+    assertThat(response.getQueue(0).getId()).isEqualTo("T4");
+    assertThat(response.getQueue(1).getId()).isEqualTo("T5");
+    // T3 is the latest task executed on PROJECT_1
+    assertThat(response.hasCurrent()).isTrue();
+    assertThat(response.getCurrent().getId()).isEqualTo("T3");
+  }
+
+  @Test
+  public void canceled_tasks_must_not_be_picked_as_current_analysis() {
+    userSession.addComponentUuidPermission(UserRole.USER, "PROJECT_1", "PROJECT_1");
+    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
+    insertActivity("T3", "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insertActivity("T4", "PROJECT_1", CeActivityDto.Status.CANCELED);
+    insertActivity("T5", "PROJECT_1", CeActivityDto.Status.CANCELED);
+
+    TestResponse wsResponse = tester.newRequest()
+        .setParam("componentId", "PROJECT_1")
+        .setMediaType(MediaTypes.PROTOBUF)
+        .execute();
+
+    WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
+    assertThat(response.getQueueCount()).isEqualTo(0);
+    // T3 is the latest task executed on PROJECT_1 ignoring Canceled ones
+    assertThat(response.hasCurrent()).isTrue();
+    assertThat(response.getCurrent().getId()).isEqualTo("T3");
+  }
+
+  private CeQueueDto insertQueue(String taskUuid, String componentUuid, CeQueueDto.Status status) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setUuid(taskUuid);
+    queueDto.setStatus(status);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.getSession().commit();
+    return queueDto;
+  }
+
+  private CeActivityDto insertActivity(String taskUuid, String componentUuid, CeActivityDto.Status status) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setUuid(taskUuid);
+    CeActivityDto activityDto = new CeActivityDto(queueDto);
+    activityDto.setStatus(status);
+    activityDto.setExecutionTimeMs(500L);
+    activityDto.setSnapshotId(123_456L);
+    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
+    dbTester.getSession().commit();
+    return activityDto;
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/LogsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/LogsActionTest.java
new file mode 100644 (file)
index 0000000..ccdb4a9
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import java.io.File;
+import java.io.IOException;
+import javax.annotation.Nullable;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonarqube.ws.MediaTypes;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class LogsActionTest {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  CeLogging ceLogging = mock(CeLogging.class);
+  LogsAction underTest = new LogsAction(dbTester.getDbClient(), userSession, ceLogging);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void return_task_logs_if_available() throws IOException {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    // task must exist in database
+    insert("TASK_1", null);
+    File logFile = temp.newFile();
+    FileUtils.write(logFile, "{logs}");
+    when(ceLogging.getFile(new LogFileRef(CeTaskTypes.REPORT, "TASK_1", null))).thenReturn(Optional.of(logFile));
+
+    TestResponse response = tester.newRequest()
+      .setParam("taskId", "TASK_1")
+      .execute();
+
+    assertThat(response.getMediaType()).isEqualTo(MediaTypes.TXT);
+    assertThat(response.getInput()).isEqualTo("{logs}");
+  }
+
+  /**
+   * The parameter taskId is present but empty. It's considered as
+   * a valid task which does not exist
+   */
+  @Test(expected = NotFoundException.class)
+  public void return_404_if_task_id_is_empty() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+    tester.newRequest()
+      .setParam("taskId", "")
+      .execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void bad_request_if_task_id_is_missing() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+    tester.newRequest()
+      .execute();
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void return_404_if_task_logs_are_not_available() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+    insert("TASK_1", null);
+    when(ceLogging.getFile(new LogFileRef(CeTaskTypes.REPORT, "TASK_1", null))).thenReturn(Optional.<File>absent());
+
+    tester.newRequest()
+      .setParam("taskId", "TASK_1")
+      .execute();
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void return_404_if_task_does_not_exist() {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+    tester.newRequest()
+      .setParam("taskId", "TASK_1")
+      .execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void require_admin_permission() {
+    tester.newRequest()
+      .setParam("taskId", "TASK_1")
+      .execute();
+  }
+
+  private CeQueueDto insert(String taskUuid, @Nullable String componentUuid) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setUuid(taskUuid);
+    queueDto.setStatus(CeQueueDto.Status.IN_PROGRESS);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.getSession().commit();
+    return queueDto;
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/SubmitActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/SubmitActionTest.java
new file mode 100644 (file)
index 0000000..b34cb07
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import java.io.InputStream;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.sonar.core.util.Protobuf;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.report.ReportSubmitter;
+import org.sonarqube.ws.MediaTypes;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.JsonAssert;
+import org.sonarqube.ws.WsCe;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SubmitActionTest {
+
+  ReportSubmitter reportSubmitter = mock(ReportSubmitter.class);
+  SubmitAction underTest = new SubmitAction(reportSubmitter);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void submit_task_to_the_queue_and_ask_for_immediate_processing() {
+    CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin("robert").build();
+    when(reportSubmitter.submit(eq("my_project"), Matchers.isNull(String.class), eq("My Project"), any(InputStream.class))).thenReturn(task);
+
+    TestResponse wsResponse = tester.newRequest()
+      .setParam("projectKey", "my_project")
+      .setParam("projectName", "My Project")
+      .setParam("report", "{binary}")
+      .setMediaType(MediaTypes.PROTOBUF)
+      .setMethod("POST")
+      .execute();
+
+    verify(reportSubmitter).submit(eq("my_project"), Matchers.isNull(String.class), eq("My Project"), any(InputStream.class));
+
+    WsCe.SubmitResponse submitResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.SubmitResponse.PARSER);
+    assertThat(submitResponse.getTaskId()).isEqualTo("TASK_1");
+    assertThat(submitResponse.getProjectId()).isEqualTo("PROJECT_1");
+  }
+
+  @Test
+  public void test_example_json_response() {
+    CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin("robert").build();
+    when(reportSubmitter.submit(eq("my_project"), Matchers.isNull(String.class), eq("My Project"), any(InputStream.class))).thenReturn(task);
+
+    TestResponse wsResponse = tester.newRequest()
+      .setParam("projectKey", "my_project")
+      .setParam("projectName", "My Project")
+      .setParam("report", "{binary}")
+      .setMediaType(MediaTypes.JSON)
+      .setMethod("POST")
+      .execute();
+
+    JsonAssert.assertJson(tester.getDef().responseExampleAsString()).isSimilarTo(wsResponse.getInput());
+  }
+
+  /**
+   * If project name is not specified, then name is the project key
+   */
+  @Test
+  public void project_name_is_optional() {
+    CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin("robert").build();
+    when(reportSubmitter.submit(eq("my_project"), Matchers.isNull(String.class), eq("my_project"), any(InputStream.class))).thenReturn(task);
+
+    tester.newRequest()
+      .setParam("projectKey", "my_project")
+      .setParam("report", "{binary}")
+      .setMediaType(MediaTypes.PROTOBUF)
+      .setMethod("POST")
+      .execute();
+
+    verify(reportSubmitter).submit(eq("my_project"), Matchers.isNull(String.class), eq("my_project"), any(InputStream.class));
+
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java
new file mode 100644 (file)
index 0000000..f084205
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import java.io.File;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.Protobuf;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.WsCe;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+
+public class TaskActionTest {
+
+  static final ComponentDto PROJECT = ComponentTesting.newProjectDto()
+    .setUuid("PROJECT_1")
+    .setName("Project One")
+    .setKey("P1");
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  CeLogging ceLogging = mock(CeLogging.class);
+  TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), ceLogging, System2.INSTANCE);
+  TaskAction underTest = new TaskAction(dbTester.getDbClient(), formatter, userSession);
+  WsActionTester ws = new WsActionTester(underTest);
+
+  @Before
+  public void setUp() {
+    dbTester.getDbClient().componentDao().insert(dbTester.getSession(), PROJECT);
+    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.<File>absent());
+  }
+
+  @Test
+  public void task_is_in_queue() throws Exception {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setUuid("TASK_1");
+    queueDto.setComponentUuid(PROJECT.uuid());
+    queueDto.setStatus(CeQueueDto.Status.PENDING);
+    queueDto.setSubmitterLogin("john");
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.commit();
+
+    TestResponse wsResponse = ws.newRequest()
+      .setMediaType(MediaTypes.PROTOBUF)
+      .setParam("id", "TASK_1")
+      .execute();
+
+    WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
+    assertThat(taskResponse.getTask().getId()).isEqualTo("TASK_1");
+    assertThat(taskResponse.getTask().getStatus()).isEqualTo(WsCe.TaskStatus.PENDING);
+    assertThat(taskResponse.getTask().getSubmitterLogin()).isEqualTo("john");
+    assertThat(taskResponse.getTask().getComponentId()).isEqualTo(PROJECT.uuid());
+    assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(PROJECT.key());
+    assertThat(taskResponse.getTask().getComponentName()).isEqualTo(PROJECT.name());
+    assertThat(taskResponse.getTask().hasExecutionTimeMs()).isFalse();
+    assertThat(taskResponse.getTask().getLogs()).isFalse();
+  }
+
+  @Test
+  public void task_is_archived() throws Exception {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setUuid("TASK_1");
+    queueDto.setComponentUuid(PROJECT.uuid());
+    CeActivityDto activityDto = new CeActivityDto(queueDto);
+    activityDto.setStatus(CeActivityDto.Status.FAILED);
+    activityDto.setExecutionTimeMs(500L);
+    activityDto.setSnapshotId(123_456L);
+    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
+    dbTester.commit();
+
+    TestResponse wsResponse = ws.newRequest()
+      .setMediaType(MediaTypes.PROTOBUF)
+      .setParam("id", "TASK_1")
+      .execute();
+
+    WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
+    WsCe.Task task = taskResponse.getTask();
+    assertThat(task.getId()).isEqualTo("TASK_1");
+    assertThat(task.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
+    assertThat(task.getComponentId()).isEqualTo(PROJECT.uuid());
+    assertThat(task.getComponentKey()).isEqualTo(PROJECT.key());
+    assertThat(task.getComponentName()).isEqualTo(PROJECT.name());
+    assertThat(task.getAnalysisId()).isEqualTo("123456");
+    assertThat(task.getExecutionTimeMs()).isEqualTo(500L);
+    assertThat(task.getLogs()).isFalse();
+  }
+
+  @Test
+  public void task_not_found() throws Exception {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
+
+    expectedException.expect(NotFoundException.class);
+    ws.newRequest()
+      .setParam("id", "DOES_NOT_EXIST")
+      .execute();
+  }
+
+  @Test
+  public void not_fail_on_queue_task_not_linked_on_project_with_system_admin_permissions() {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType("fake");
+    queueDto.setUuid("TASK_1");
+    queueDto.setStatus(CeQueueDto.Status.PENDING);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.commit();
+
+    ws.newRequest()
+      .setMediaType(MediaTypes.JSON)
+      .setParam("id", "TASK_1")
+      .execute();
+  }
+
+  @Test
+  public void not_fail_on_queue_task_not_linked_on_project_with_global_scan_permissions() {
+    userSession.login("john").setGlobalPermissions(SCAN_EXECUTION);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType("fake");
+    queueDto.setUuid("TASK_1");
+    queueDto.setStatus(CeQueueDto.Status.PENDING);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.commit();
+
+    ws.newRequest()
+      .setMediaType(MediaTypes.JSON)
+      .setParam("id", "TASK_1")
+      .execute();
+  }
+
+  @Test
+  public void fail_on_queue_task_not_linked_on_project_if_not_admin_nor_scan_permission() {
+    userSession.login("john").setGlobalPermissions(PROVISIONING);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType("fake");
+    queueDto.setUuid("TASK_1");
+    queueDto.setStatus(CeQueueDto.Status.PENDING);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.commit();
+
+    expectedException.expect(ForbiddenException.class);
+    ws.newRequest()
+      .setMediaType(MediaTypes.PROTOBUF)
+      .setParam("id", "TASK_1")
+      .execute();
+  }
+
+  @Test
+  public void not_fail_on_queue_task_linked_on_project_with_project_scan_permission() {
+    userSession.login("john").addProjectUuidPermissions(SCAN_EXECUTION, PROJECT.uuid());
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType("fake");
+    queueDto.setUuid("TASK_1");
+    queueDto.setStatus(CeQueueDto.Status.PENDING);
+    queueDto.setComponentUuid(PROJECT.uuid());
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.commit();
+
+    ws.newRequest()
+      .setMediaType(MediaTypes.JSON)
+      .setParam("id", "TASK_1")
+      .execute();
+  }
+
+  @Test
+  public void not_fail_on_archived_task_linked_on_project_with_project_scan_permission() throws Exception {
+    userSession.login("john").addProjectUuidPermissions(SCAN_EXECUTION, PROJECT.uuid());
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setUuid("TASK_1");
+    queueDto.setComponentUuid(PROJECT.uuid());
+    CeActivityDto activityDto = new CeActivityDto(queueDto);
+    activityDto.setStatus(CeActivityDto.Status.FAILED);
+    activityDto.setExecutionTimeMs(500L);
+    activityDto.setSnapshotId(123_456L);
+    activityDto.setComponentUuid(PROJECT.uuid());
+    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
+    dbTester.commit();
+
+    ws.newRequest()
+      .setMediaType(MediaTypes.PROTOBUF)
+      .setParam("id", "TASK_1")
+      .execute();
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java
new file mode 100644 (file)
index 0000000..620b0e7
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.base.Optional;
+import java.io.IOException;
+import java.util.Date;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonarqube.ws.WsCe;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class TaskFormatterTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  System2 system2 = mock(System2.class);
+  CeLogging ceLogging = mock(CeLogging.class, Mockito.RETURNS_DEEP_STUBS);
+  TaskFormatter underTest = new TaskFormatter(db.getDbClient(), ceLogging, system2);
+
+  @Test
+  public void formatQueue_without_component() {
+    CeQueueDto dto = new CeQueueDto();
+    dto.setUuid("UUID");
+    dto.setTaskType("TYPE");
+    dto.setStatus(CeQueueDto.Status.PENDING);
+    dto.setCreatedAt(1_450_000_000_000L);
+
+    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
+
+    assertThat(wsTask.getType()).isEqualTo("TYPE");
+    assertThat(wsTask.getId()).isEqualTo("UUID");
+    assertThat(wsTask.getStatus()).isEqualTo(WsCe.TaskStatus.PENDING);
+    assertThat(wsTask.getLogs()).isFalse();
+    assertThat(wsTask.getSubmittedAt()).isEqualTo(DateUtils.formatDateTime(new Date(1_450_000_000_000L)));
+
+    assertThat(wsTask.hasExecutionTimeMs()).isFalse();
+    assertThat(wsTask.hasSubmitterLogin()).isFalse();
+    assertThat(wsTask.hasComponentId()).isFalse();
+    assertThat(wsTask.hasComponentKey()).isFalse();
+    assertThat(wsTask.hasComponentName()).isFalse();
+    assertThat(wsTask.hasExecutedAt()).isFalse();
+    assertThat(wsTask.hasStartedAt()).isFalse();
+    assertThat(wsTask.hasExecutionTimeMs()).isFalse();
+  }
+
+  @Test
+  public void formatQueue_with_component_and_other_fields() throws IOException {
+    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.of(temp.newFile()));
+    db.getDbClient().componentDao().insert(db.getSession(), new ComponentDto()
+      .setUuid("COMPONENT_UUID").setKey("COMPONENT_KEY").setName("Component Name").setQualifier(Qualifiers.PROJECT));
+
+    CeQueueDto dto = new CeQueueDto();
+    dto.setUuid("UUID");
+    dto.setTaskType("TYPE");
+    dto.setStatus(CeQueueDto.Status.IN_PROGRESS);
+    dto.setCreatedAt(1_450_000_000_000L);
+    dto.setStartedAt(1_451_000_000_000L);
+    dto.setComponentUuid("COMPONENT_UUID");
+    dto.setSubmitterLogin("rob");
+
+    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
+
+    assertThat(wsTask.getType()).isEqualTo("TYPE");
+    assertThat(wsTask.getId()).isEqualTo("UUID");
+    assertThat(wsTask.getComponentId()).isEqualTo("COMPONENT_UUID");
+    assertThat(wsTask.getComponentKey()).isEqualTo("COMPONENT_KEY");
+    assertThat(wsTask.getComponentName()).isEqualTo("Component Name");
+    assertThat(wsTask.getComponentQualifier()).isEqualTo("TRK");
+    assertThat(wsTask.getStatus()).isEqualTo(WsCe.TaskStatus.IN_PROGRESS);
+    assertThat(wsTask.getLogs()).isTrue();
+    assertThat(wsTask.getSubmitterLogin()).isEqualTo("rob");
+    assertThat(wsTask.hasExecutionTimeMs()).isTrue();
+    assertThat(wsTask.hasExecutedAt()).isFalse();
+  }
+
+  @Test
+  public void formatQueue_do_not_fail_if_component_not_found() throws Exception {
+    CeQueueDto dto = new CeQueueDto();
+    dto.setUuid("UUID");
+    dto.setTaskType("TYPE");
+    dto.setStatus(CeQueueDto.Status.IN_PROGRESS);
+    dto.setCreatedAt(1_450_000_000_000L);
+    dto.setComponentUuid("DOES_NOT_EXIST");
+
+    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
+
+    assertThat(wsTask.getComponentId()).isEqualTo("DOES_NOT_EXIST");
+    assertThat(wsTask.hasComponentKey()).isFalse();
+    assertThat(wsTask.hasComponentName()).isFalse();
+  }
+
+  @Test
+  public void formatQueue_compute_execute_time_if_in_progress() {
+    long startedAt = 1_450_000_001_000L;
+    long now = 1_450_000_003_000L;
+    CeQueueDto dto = new CeQueueDto();
+    dto.setUuid("UUID");
+    dto.setTaskType("TYPE");
+    dto.setStatus(CeQueueDto.Status.IN_PROGRESS);
+    dto.setCreatedAt(1_450_000_000_000L);
+    dto.setStartedAt(startedAt);
+    when(system2.now()).thenReturn(now);
+
+    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
+
+    assertThat(wsTask.getExecutionTimeMs()).isEqualTo(now-startedAt);
+  }
+
+  @Test
+  public void formatQueues() throws Exception {
+    CeQueueDto dto1 = new CeQueueDto();
+    dto1.setUuid("UUID1");
+    dto1.setTaskType("TYPE1");
+    dto1.setStatus(CeQueueDto.Status.IN_PROGRESS);
+    dto1.setCreatedAt(1_450_000_000_000L);
+
+    CeQueueDto dto2 = new CeQueueDto();
+    dto2.setUuid("UUID2");
+    dto2.setTaskType("TYPE2");
+    dto2.setStatus(CeQueueDto.Status.PENDING);
+    dto2.setCreatedAt(1_451_000_000_000L);
+
+    Iterable<WsCe.Task> wsTasks = underTest.formatQueue(db.getSession(), asList(dto1, dto2));
+    assertThat(wsTasks).extracting("id").containsExactly("UUID1", "UUID2");
+  }
+
+  @Test
+  public void formatActivity() {
+    CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
+
+    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto);
+
+    assertThat(wsTask.getType()).isEqualTo(CeTaskTypes.REPORT);
+    assertThat(wsTask.getId()).isEqualTo("UUID");
+    assertThat(wsTask.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
+    assertThat(wsTask.getLogs()).isFalse();
+    assertThat(wsTask.getSubmittedAt()).isEqualTo(DateUtils.formatDateTime(new Date(1_450_000_000_000L)));
+    assertThat(wsTask.getExecutionTimeMs()).isEqualTo(500L);
+    assertThat(wsTask.getAnalysisId()).isEqualTo("123456");
+    assertThat(wsTask.getLogs()).isFalse();
+  }
+
+  @Test
+  public void formatActivity_has_logs() throws IOException {
+    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.of(temp.newFile()));
+    CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
+
+    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto);
+
+    assertThat(wsTask.getLogs()).isTrue();
+  }
+
+  @Test
+  public void formatActivities() {
+    CeActivityDto dto1 = newActivity("UUID1", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
+    CeActivityDto dto2 = newActivity("UUID2", "COMPONENT_UUID", CeActivityDto.Status.SUCCESS);
+
+    Iterable<WsCe.Task> wsTasks = underTest.formatActivity(db.getSession(), asList(dto1, dto2));
+
+    assertThat(wsTasks).extracting("id").containsExactly("UUID1", "UUID2");
+  }
+
+  private CeActivityDto newActivity(String taskUuid, String componentUuid, CeActivityDto.Status status) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setCreatedAt(1_450_000_000_000L);
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setUuid(taskUuid);
+    CeActivityDto activityDto = new CeActivityDto(queueDto);
+    activityDto.setStatus(status);
+    activityDto.setExecutionTimeMs(500L);
+    activityDto.setSnapshotId(123_456L);
+    return activityDto;
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskTypesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskTypesActionTest.java
new file mode 100644 (file)
index 0000000..3757f10
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.ce.ws;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.junit.Test;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.sonar.test.JsonAssert.assertJson;
+
+public class TaskTypesActionTest {
+
+  WsActionTester ws = new WsActionTester(new TaskTypesAction(new CeTaskProcessor[] {
+    new FakeCeTaskProcessor("REPORT"),
+    new FakeCeTaskProcessor("DEV_REFRESH", "DEV_PURGE"),
+    new FakeCeTaskProcessor("VIEW_REFRESH")
+  }));
+
+  @Test
+  public void json_example() {
+    String response = ws.newRequest().execute().getInput();
+
+    assertJson(response).isSimilarTo(getClass().getResource("task_types-example.json"));
+  }
+
+  private static class FakeCeTaskProcessor implements CeTaskProcessor {
+    private final Set<String> taskTypes;
+
+    private FakeCeTaskProcessor(String... taskTypes) {
+      this.taskTypes = ImmutableSet.copyOf(taskTypes);
+    }
+
+    @Override
+    public Set<String> getHandledCeTaskTypes() {
+      return taskTypes;
+    }
+
+    @Override
+    public CeTaskResult process(CeTask task) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/CePropertyDefinitionsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/CePropertyDefinitionsTest.java
deleted file mode 100644 (file)
index 87a8005..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation;
-
-import org.junit.Test;
-import org.sonar.server.computation.property.CePropertyDefinitions;
-import org.sonar.test.TestUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CePropertyDefinitionsTest {
-
-  @Test
-  public void all() {
-    assertThat(CePropertyDefinitions.all()).isNotEmpty();
-  }
-
-  @Test
-  public void only_statics() {
-    assertThat(TestUtils.hasOnlyPrivateConstructors(CePropertyDefinitions.class)).isTrue();
-  }
-}
index bc59c911ead923d53e4d7e73dc3716ee6e6ffe54..7974b5c5534d97412a231a77b842e0e967f7ebbf 100644 (file)
@@ -27,8 +27,8 @@ import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
 import org.sonar.server.computation.queue.PurgeCeActivities;
 
 import static org.assertj.core.api.Assertions.assertThat;
index e63575f92eac3e5cc24b2e0c9bb707b9f40a224c..f4aee71458764e835fa05b234fc9d85df4a86ee0 100644 (file)
@@ -29,7 +29,7 @@ import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.config.Settings;
 import org.sonar.process.ProcessProperties;
-import org.sonar.server.computation.queue.report.ReportFiles;
+import org.sonar.ce.queue.report.ReportFiles;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
index caaa3890edc2d0ecff53dc8d826b90afa2a23204..0674fd77fee3a5875b32c53fce743607b7ec1274 100644 (file)
@@ -28,7 +28,7 @@ import java.util.Set;
 import javax.annotation.Nullable;
 import org.junit.Test;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 import org.sonar.server.computation.step.ComputationStep;
 import org.sonar.server.computation.step.PersistComponentsStep;
 import org.sonar.server.computation.step.PersistDevelopersStep;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeFileAppenderFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeFileAppenderFactoryTest.java
deleted file mode 100644 (file)
index b455040..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.core.FileAppender;
-import java.io.File;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CeFileAppenderFactoryTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Test
-  public void buildAppender() throws Exception {
-    File logsDir = temp.newFolder();
-    CeFileAppenderFactory factory = new CeFileAppenderFactory(logsDir);
-
-    FileAppender underTest = factory.buildAppender(new LoggerContext(), "uuid_1.log");
-
-    assertThat(new File(underTest.getFile())).isEqualTo(new File(logsDir, "uuid_1.log"));
-
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLogAcceptFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLogAcceptFilterTest.java
deleted file mode 100644 (file)
index 308fdca..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.core.filter.Filter;
-import ch.qos.logback.core.spi.FilterReply;
-import org.apache.log4j.MDC;
-import org.junit.After;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CeLogAcceptFilterTest {
-
-  private static final Object UNUSED = "";
-
-  Filter underTest = new CeLogAcceptFilter();
-
-  @After
-  public void tearDown() {
-    MDC.clear();
-  }
-
-  @Test
-  public void reject_non_ce_logs() {
-    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.DENY);
-  }
-
-  @Test
-  public void accept_ce_logs() {
-    MDC.put(CeLogging.MDC_LOG_PATH, "abc.log");
-    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.ACCEPT);
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLogDenyFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLogDenyFilterTest.java
deleted file mode 100644 (file)
index c3db80f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.core.filter.Filter;
-import ch.qos.logback.core.spi.FilterReply;
-import org.apache.log4j.MDC;
-import org.junit.After;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CeLogDenyFilterTest {
-
-  private static final Object UNUSED = "";
-
-  Filter underTest = new CeLogDenyFilter();
-
-  @After
-  public void tearDown() {
-    MDC.clear();
-  }
-
-  @Test
-  public void accept_non_ce_logs() {
-    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.ACCEPT);
-  }
-
-  @Test
-  public void deny_ce_logs() {
-    MDC.put(CeLogging.MDC_LOG_PATH, "abc.log");
-    assertThat(underTest.decide(UNUSED)).isEqualTo(FilterReply.DENY);
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLoggingTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/log/CeLoggingTest.java
deleted file mode 100644 (file)
index 7df4d13..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.sift.SiftingAppender;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.Appender;
-import ch.qos.logback.core.filter.Filter;
-import ch.qos.logback.core.joran.spi.JoranException;
-import com.google.common.base.Optional;
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.slf4j.LoggerFactory;
-import org.slf4j.MDC;
-import org.sonar.api.config.Settings;
-import org.sonar.process.LogbackHelper;
-import org.sonar.process.ProcessProperties;
-import org.sonar.server.computation.queue.CeTask;
-
-import static java.lang.String.format;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.server.computation.log.CeLogging.MDC_LOG_PATH;
-
-public class CeLoggingTest {
-
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  private LogbackHelper helper = new LogbackHelper();
-  private File dataDir;
-
-  @Before
-  public void setUp() throws Exception {
-    this.dataDir = temp.newFolder();
-  }
-
-  @After
-  public void resetLogback() throws JoranException {
-    helper.resetFromXml("/logback-test.xml");
-  }
-
-  @After
-  public void cleanMDC() throws Exception {
-    MDC.clear();
-  }
-
-  @Test
-  public void getFile() throws IOException {
-    Settings settings = newSettings(dataDir, 10);
-
-    CeLogging underTest = new CeLogging(settings);
-    LogFileRef ref = new LogFileRef("TYPE1", "TASK1", "COMPONENT1");
-
-    // file does not exist
-    Optional<File> file = underTest.getFile(ref);
-    assertThat(file.isPresent()).isFalse();
-
-    File logFile = new File(dataDir, "ce/logs/" + ref.getRelativePath());
-    FileUtils.touch(logFile);
-    file = underTest.getFile(ref);
-    assertThat(file.isPresent()).isTrue();
-    assertThat(file.get()).isEqualTo(logFile);
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void fail_if_data_dir_is_not_set() {
-    new CeLogging(new Settings());
-  }
-
-  @Test
-  public void initForTask_adds_path_of_ce_log_file_in_MDC() throws IOException {
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
-
-    CeTask task = createCeTask("TYPE1", "U1");
-    underTest.initForTask(task);
-    assertThat(MDC.get(MDC_LOG_PATH)).isNotEmpty().isEqualTo(LogFileRef.from(task).getRelativePath());
-  }
-
-  @Test
-  public void clearForTask_throws_ISE_if_CE_appender_is_not_configured() throws IOException {
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
-
-    CeTask task = createCeTask("TYPE1", "U1");
-    underTest.initForTask(task);
-
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Appender with name ce is null or not a SiftingAppender");
-
-    underTest.clearForTask();
-  }
-
-  @Test
-  public void clearForTask_throws_ISE_if_CE_appender_is_not_a_SiftingAppender() throws IOException {
-    Appender<ILoggingEvent> mockCeAppender = mock(Appender.class);
-    when(mockCeAppender.getName()).thenReturn("ce");
-    helper.getRootContext().getLogger(Logger.ROOT_LOGGER_NAME).addAppender(mockCeAppender);
-
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
-
-    CeTask task = createCeTask("TYPE1", "U1");
-    underTest.initForTask(task);
-
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Appender with name ce is null or not a SiftingAppender");
-
-    underTest.clearForTask();
-  }
-
-  @Test
-  public void clearForTask_clears_MDC() throws IOException {
-    setupCeAppender();
-
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
-
-    CeTask task = createCeTask("TYPE1", "U1");
-    underTest.initForTask(task);
-    assertThat(MDC.get(MDC_LOG_PATH)).isNotEmpty().isEqualTo(LogFileRef.from(task).getRelativePath());
-
-    underTest.clearForTask();
-    assertThat(MDC.get(MDC_LOG_PATH)).isNull();
-  }
-
-  @Test
-  public void cleanForTask_stops_only_appender_for_MDC_value() throws IOException {
-    Logger rootLogger = setupCeAppender();
-
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
-
-    // init MDC
-    underTest.initForTask(createCeTask("TYPE1", "U1"));
-    verifyNoAppender(rootLogger);
-
-    // logging will create and start the appender
-    LoggerFactory.getLogger(getClass()).info("some log!");
-    verifyAllAppenderStarted(rootLogger, 1);
-
-    // init MDC and create appender for another task
-    // (in the same thread, which should not happen, but it's good enough for our test)
-    CeTask ceTask = createCeTask("TYPE1", "U2");
-    underTest.initForTask(ceTask);
-    LoggerFactory.getLogger(getClass()).info("some other log!");
-    verifyAllAppenderStarted(rootLogger, 2);
-
-    // stop appender which is currently referenced in MDC
-    underTest.clearForTask();
-
-    Appender appender = verifySingleAppenderIsStopped(rootLogger, 2);
-    assertThat(appender.getName()).isEqualTo("ce-" + LogFileRef.from(ceTask).getRelativePath());
-  }
-
-  @Test
-  public void delete_oldest_files_of_same_directory_to_keep_only_max_allowed_files() throws IOException {
-    for (int i = 1; i <= 5; i++) {
-      File file = new File(dataDir, format("U%d.log", i));
-      FileUtils.touch(file);
-      // see javadoc: "all platforms support file-modification times to the nearest second,
-      // but some provide more precision" --> increment by second, not by millisecond
-      file.setLastModified(1_450_000_000_000L + i * 1000);
-    }
-    assertThat(dataDir.listFiles()).hasSize(5);
-
-    // keep 3 files in each dir
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 3));
-    underTest.purgeDir(dataDir);
-
-    assertThat(dataDir.listFiles()).hasSize(3);
-    assertThat(dataDir.listFiles()).extracting("name")
-      .containsOnly("U3.log", "U4.log", "U5.log");
-  }
-
-  @Test
-  public void do_not_delete_files_if_dir_has_less_files_than_max_allowed() throws IOException {
-    FileUtils.touch(new File(dataDir, "U1.log"));
-
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 5));
-    underTest.purgeDir(dataDir);
-
-    assertThat(dataDir.listFiles()).extracting("name").containsOnly("U1.log");
-  }
-
-  @Test
-  public void do_not_keep_any_logs() throws IOException {
-    FileUtils.touch(new File(dataDir, "U1.log"));
-
-    CeLogging underTest = new CeLogging(newSettings(dataDir, 0));
-    underTest.purgeDir(dataDir);
-
-    assertThat(dataDir.listFiles()).isEmpty();
-  }
-
-  @Test
-  public void fail_if_max_logs_settings_is_negative() throws IOException {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Property sonar.ce.maxLogsPerTask must be positive. Got: -1");
-
-    Settings settings = newSettings(dataDir, -1);
-    CeLogging logging = new CeLogging(settings);
-    logging.purgeDir(dataDir);
-  }
-
-  @Test
-  public void createConfiguration() throws Exception {
-    SiftingAppender siftingAppender = CeLogging.createAppenderConfiguration(new LoggerContext(), dataDir);
-
-    // filter on CE logs
-    List<Filter<ILoggingEvent>> filters = siftingAppender.getCopyOfAttachedFiltersList();
-    assertThat(filters).hasSize(1);
-    assertThat(filters.get(0)).isInstanceOf(CeLogAcceptFilter.class);
-
-    assertThat(siftingAppender.getDiscriminator().getKey()).isEqualTo(MDC_LOG_PATH);
-    assertThat(siftingAppender.getTimeout().getMilliseconds()).isEqualTo(1000 * 60 * 2);
-  }
-
-  private Logger setupCeAppender() {
-    Logger rootLogger = helper.getRootContext().getLogger(Logger.ROOT_LOGGER_NAME);
-    rootLogger.addAppender(CeLogging.createAppenderConfiguration(helper.getRootContext(), dataDir));
-    return rootLogger;
-  }
-
-  private void verifyNoAppender(Logger rootLogger) {
-    Collection<Appender<ILoggingEvent>> allAppenders = getAllAppenders(rootLogger);
-    assertThat(allAppenders).isEmpty();
-  }
-
-  private void verifyAllAppenderStarted(Logger rootLogger, int expectedSize) {
-    Collection<Appender<ILoggingEvent>> allAppenders = getAllAppenders(rootLogger);
-    assertThat(allAppenders).hasSize(expectedSize);
-    for (Appender<ILoggingEvent> appender : allAppenders) {
-      assertThat(appender.isStarted()).isTrue();
-    }
-  }
-
-  private Appender verifySingleAppenderIsStopped(Logger rootLogger, int expectedSize) {
-    Collection<Appender<ILoggingEvent>> allAppenders = getAllAppenders(rootLogger);
-    assertThat(allAppenders).hasSize(expectedSize);
-    Appender res = null;
-    for (Appender<ILoggingEvent> appender : allAppenders) {
-      if (!appender.isStarted()) {
-        assertThat(res).describedAs("More than one appender found stopped").isNull();
-        res = appender;
-      }
-    }
-    assertThat(res).describedAs("There should be one stopped appender").isNotNull();
-    return res;
-  }
-
-  private Collection<Appender<ILoggingEvent>> getAllAppenders(Logger rootLogger) {
-    Appender<ILoggingEvent> ceAppender = rootLogger.getAppender("ce");
-    assertThat(ceAppender).isInstanceOf(SiftingAppender.class);
-    return ((SiftingAppender) ceAppender).getAppenderTracker().allComponents();
-  }
-
-  private static Settings newSettings(File dataDir, int maxLogs) {
-    Settings settings = new Settings();
-    settings.setProperty(ProcessProperties.PATH_DATA, dataDir.getAbsolutePath());
-    settings.setProperty(CeLogging.MAX_LOGS_PROPERTY, maxLogs);
-    return settings;
-  }
-
-  private static CeTask createCeTask(String type, String uuid) {
-    return new CeTask.Builder().setType(type).setUuid(uuid).build();
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/log/LogFileRefTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/log/LogFileRefTest.java
deleted file mode 100644 (file)
index 9f23dce..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.log;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.db.ce.CeTaskTypes;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class LogFileRefTest {
-
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
-  @Test
-  public void equals_hashCode() {
-    LogFileRef ref1 = new LogFileRef(CeTaskTypes.REPORT, "UUID_1", "COMPONENT_1");
-    LogFileRef ref1bis = new LogFileRef(CeTaskTypes.REPORT, "UUID_1", "COMPONENT_1");
-    LogFileRef ref2 = new LogFileRef(CeTaskTypes.REPORT, "UUID_2", "COMPONENT_1");
-
-    assertThat(ref1.equals(ref1)).isTrue();
-    assertThat(ref1.equals(ref1bis)).isTrue();
-    assertThat(ref1.equals(ref2)).isFalse();
-    assertThat(ref1.equals(null)).isFalse();
-    assertThat(ref1.equals("UUID_1")).isFalse();
-
-    assertThat(ref1.hashCode()).isEqualTo(ref1bis.hashCode());
-  }
-
-  @Test
-  public void getRelativePath() {
-    assertThat(new LogFileRef("TYPE_1", "UUID_1", "COMPONENT_1").getRelativePath()).isEqualTo("TYPE_1/COMPONENT_1/UUID_1.log");
-    assertThat(new LogFileRef("TYPE_1", "UUID_1", null).getRelativePath()).isEqualTo("TYPE_1/UUID_1.log");
-  }
-
-  @Test
-  public void do_not_accept_invalid_task_type() {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("'foo/bar' is not a valid filename for Compute Engine logs");
-
-    new LogFileRef("foo/bar", "UUID", null);
-  }
-
-  @Test
-  public void do_not_accept_invalid_uuid() {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("'foo/bar' is not a valid filename for Compute Engine logs");
-
-    new LogFileRef("REPORT", "foo/bar", null);
-  }
-
-  @Test
-  public void do_not_accept_invalid_component_uuid() {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("'foo/bar' is not a valid filename for Compute Engine logs");
-
-    new LogFileRef("REPORT", "UUID", "foo/bar");
-  }
-
-  @Test
-  public void filename_must_support_uuid() {
-    String uuid = "AU-Tpxb-_iU5OvuD2FLy";
-    assertThat(LogFileRef.requireValidFilename(uuid)).isEqualTo(uuid);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplConcurrentTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplConcurrentTest.java
deleted file mode 100644 (file)
index 5d919d3..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.monitoring;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import org.junit.After;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CEQueueStatusImplConcurrentTest {
-  private ExecutorService executorService = Executors.newFixedThreadPool(10, new ThreadFactory() {
-    private int cnt = 0;
-
-    @Override
-    public Thread newThread(Runnable r) {
-      return new Thread(r, CEQueueStatusImplConcurrentTest.class.getSimpleName() + cnt++);
-    }
-  });
-  private CEQueueStatusImpl underTest = new CEQueueStatusImpl();
-
-  @After
-  public void tearDown() throws Exception {
-    executorService.shutdownNow();
-  }
-
-  @Test
-  public void test_concurrent_modifications_in_any_order() throws InterruptedException {
-    long initialPendingCount = 9963L;
-    underTest.initPendingCount(initialPendingCount);
-
-    for (Runnable runnable : buildShuffleCallsToUnderTest()) {
-      executorService.submit(runnable);
-    }
-
-    executorService.awaitTermination(1, TimeUnit.SECONDS);
-
-    assertThat(underTest.getReceivedCount()).isEqualTo(100);
-    assertThat(underTest.getPendingCount()).isEqualTo(initialPendingCount + 2);
-    assertThat(underTest.getInProgressCount()).isEqualTo(1);
-    assertThat(underTest.getErrorCount()).isEqualTo(17);
-    assertThat(underTest.getSuccessCount()).isEqualTo(80);
-    assertThat(underTest.getProcessingTime()).isEqualTo(177);
-  }
-
-  private List<Runnable> buildShuffleCallsToUnderTest() {
-    List<Runnable> res = new ArrayList<>();
-    for (int i = 0; i < 100; i++) {
-      res.add(new AddReceivedRunnable());
-    }
-    for (int i = 0; i < 98; i++) {
-      res.add(new AddInProgressRunnable());
-    }
-    for (int i = 0; i < 80; i++) {
-      res.add(new AddSuccessRunnable());
-    }
-    for (int i = 0; i < 17; i++) {
-      res.add(new AddErrorRunnable());
-    }
-    Collections.shuffle(res);
-    return res;
-  }
-
-  private class AddReceivedRunnable implements Runnable {
-    @Override
-    public void run() {
-      underTest.addReceived();
-    }
-  }
-
-  private class AddInProgressRunnable implements Runnable {
-    @Override
-    public void run() {
-      underTest.addInProgress();
-    }
-  }
-
-  private class AddErrorRunnable implements Runnable {
-    @Override
-    public void run() {
-      underTest.addError(1);
-    }
-  }
-
-  private class AddSuccessRunnable implements Runnable {
-    @Override
-    public void run() {
-      underTest.addSuccess(2);
-    }
-  }
-}
index 8ba7e634d3eb250388a81589d0fedcec8a210c1b..bca30441eccfa35abbf2e8757c5224c8544fa45c 100644 (file)
@@ -20,8 +20,9 @@
 package org.sonar.server.computation.monitoring;
 
 import org.junit.Test;
+import org.sonar.ce.monitoring.CEQueueStatus;
 import org.sonar.server.computation.configuration.CeConfiguration;
-import org.sonar.server.computation.queue.CeQueueImpl;
+import org.sonar.ce.queue.CeQueueImpl;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
index 50a82a6e7c807d9722ce682242b7d2648d976f94..7ea418c57488ce0d7f1f4ce315106ce34bca7e57 100644 (file)
@@ -27,11 +27,11 @@ import org.junit.rules.TemporaryFolder;
 import org.mockito.Mockito;
 import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.api.utils.System2;
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.queue.report.ReportFiles;
 
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -51,7 +51,7 @@ public class CeQueueCleanerTest {
 
   ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class);
   ReportFiles reportFiles = mock(ReportFiles.class, Mockito.RETURNS_DEEP_STUBS);
-  CeQueueImpl queue = mock(CeQueueImpl.class);
+  InternalCeQueue queue = mock(InternalCeQueue.class);
   CeQueueCleaner underTest = new CeQueueCleaner(dbTester.getDbClient(), serverUpgradeStatus, reportFiles, queue);
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueImplTest.java
deleted file mode 100644 (file)
index 69acc25..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import com.google.common.base.Optional;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.core.util.UuidFactoryImpl;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.hamcrest.Matchers.startsWith;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class CeQueueImplTest {
-
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
-  System2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
-
-  @Rule
-  public DbTester dbTester = DbTester.create(system2);
-  DbSession session = dbTester.getSession();
-
-  UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
-  CEQueueStatus queueStatus = new CEQueueStatusImpl();
-  CeQueueListener listener = mock(CeQueueListener.class);
-  CeQueue underTest = new CeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
-
-  @Before
-  public void setUp() throws Exception {
-    queueStatus.initPendingCount(0);
-  }
-
-  @Test
-  public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
-    CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
-    CeTask task = underTest.submit(taskSubmit);
-
-    verifyCeTask(taskSubmit, task, null);
-    verifyCeQueueDtoForTaskSubmit(taskSubmit);
-  }
-
-  @Test
-  public void submit_increments_receivedCount_of_QueueStatus() {
-    underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"));
-
-    assertThat(queueStatus.getReceivedCount()).isEqualTo(1L);
-
-    underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_2", "rob"));
-
-    assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
-  }
-
-  @Test
-  public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
-    ComponentDto componentDto = insertComponent(newComponentDto("PROJECT_1"));
-    CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null);
-
-    CeTask task = underTest.submit(taskSubmit);
-
-    verifyCeTask(taskSubmit, task, componentDto);
-  }
-
-  @Test
-  public void submit_returns_task_without_component_info_when_submit_has_none() {
-    CeTaskSubmit taskSubmit = createTaskSubmit("not cpt related");
-
-    CeTask task = underTest.submit(taskSubmit);
-
-    verifyCeTask(taskSubmit, task, null);
-  }
-
-  @Test
-  public void submit_fails_with_ISE_if_paused() {
-    underTest.pauseSubmit();
-
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Compute Engine does not currently accept new tasks");
-
-    submit(CeTaskTypes.REPORT, "PROJECT_1");
-  }
-
-  @Test
-  public void massSubmit_returns_tasks_for_each_CeTaskSubmit_populated_from_CeTaskSubmit_and_creates_CeQueue_row_for_each() {
-    CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
-    CeTaskSubmit taskSubmit2 = createTaskSubmit("some type");
-
-    List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
-
-    assertThat(tasks).hasSize(2);
-    verifyCeTask(taskSubmit1, tasks.get(0), null);
-    verifyCeTask(taskSubmit2, tasks.get(1), null);
-    verifyCeQueueDtoForTaskSubmit(taskSubmit1);
-    verifyCeQueueDtoForTaskSubmit(taskSubmit2);
-  }
-
-  @Test
-  public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() {
-    ComponentDto componentDto1 = insertComponent(newComponentDto("PROJECT_1"));
-    CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null);
-    CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null);
-
-    List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
-
-    assertThat(tasks).hasSize(2);
-    verifyCeTask(taskSubmit1, tasks.get(0), componentDto1);
-    verifyCeTask(taskSubmit2, tasks.get(1), null);
-  }
-
-  @Test
-  public void massSubmit_increments_receivedCount_of_QueueStatus() {
-    underTest.massSubmit(asList(createTaskSubmit("type 1"), createTaskSubmit("type 2")));
-
-    assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
-
-    underTest.massSubmit(asList(createTaskSubmit("a"), createTaskSubmit("a"), createTaskSubmit("b")));
-
-    assertThat(queueStatus.getReceivedCount()).isEqualTo(5L);
-  }
-
-  @Test
-  public void test_remove() {
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-    Optional<CeTask> peek = underTest.peek();
-    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, null);
-
-    // queue is empty
-    assertThat(dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), task.getUuid()).isPresent()).isFalse();
-    assertThat(underTest.peek().isPresent()).isFalse();
-
-    // available in history
-    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
-    assertThat(history.isPresent()).isTrue();
-    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
-    assertThat(history.get().getIsLast()).isTrue();
-    assertThat(history.get().getSnapshotId()).isNull();
-
-    verify(listener).onRemoved(task, CeActivityDto.Status.SUCCESS);
-  }
-
-  @Test
-  public void remove_does_not_set_snapshotId_in_CeActivity_when_CeTaskResult_has_no_snapshot_id() {
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-    Optional<CeTask> peek = underTest.peek();
-    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(null));
-
-    // available in history
-    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
-    assertThat(history.isPresent()).isTrue();
-    assertThat(history.get().getSnapshotId()).isNull();
-  }
-
-  @Test
-  public void remove_sets_snapshotId_in_CeActivity_when_CeTaskResult_has_no_snapshot_id() {
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-    long snapshotId = 663L;
-
-    Optional<CeTask> peek = underTest.peek();
-    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(snapshotId));
-
-    // available in history
-    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
-    assertThat(history.isPresent()).isTrue();
-    assertThat(history.get().getSnapshotId()).isEqualTo(snapshotId);
-  }
-
-  @Test
-  public void fail_to_remove_if_not_in_queue() throws Exception {
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-    underTest.remove(task, CeActivityDto.Status.SUCCESS, null);
-
-    expectedException.expect(IllegalStateException.class);
-
-    underTest.remove(task, CeActivityDto.Status.SUCCESS, null);
-  }
-
-  @Test
-  public void test_peek() throws Exception {
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-
-    Optional<CeTask> peek = underTest.peek();
-    assertThat(peek.isPresent()).isTrue();
-    assertThat(peek.get().getUuid()).isEqualTo(task.getUuid());
-    assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT);
-    assertThat(peek.get().getComponentUuid()).isEqualTo("PROJECT_1");
-
-    // no more pending tasks
-    peek = underTest.peek();
-    assertThat(peek.isPresent()).isFalse();
-
-    verify(listener, never()).onRemoved(eq(task), any(CeActivityDto.Status.class));
-  }
-
-  @Test
-  public void peek_nothing_if_paused() throws Exception {
-    submit(CeTaskTypes.REPORT, "PROJECT_1");
-    underTest.pausePeek();
-
-    Optional<CeTask> peek = underTest.peek();
-    assertThat(peek.isPresent()).isFalse();
-  }
-
-  @Test
-  public void cancel_pending() throws Exception {
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-
-    // ignore
-    boolean canceled = underTest.cancel("UNKNOWN");
-    assertThat(canceled).isFalse();
-    verifyZeroInteractions(listener);
-
-    canceled = underTest.cancel(task.getUuid());
-    assertThat(canceled).isTrue();
-    Optional<CeActivityDto> activity = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
-    assertThat(activity.isPresent()).isTrue();
-    assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
-    verify(listener).onRemoved(task, CeActivityDto.Status.CANCELED);
-  }
-
-  @Test
-  public void fail_to_cancel_if_in_progress() throws Exception {
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage(startsWith("Task is in progress and can't be canceled"));
-
-    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
-    underTest.peek();
-
-    underTest.cancel(task.getUuid());
-  }
-
-  @Test
-  public void cancelAll_pendings_but_not_in_progress() throws Exception {
-    CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1");
-    CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2");
-    CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3");
-    underTest.peek();
-
-    int canceledCount = underTest.cancelAll();
-    assertThat(canceledCount).isEqualTo(2);
-
-    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask1.getUuid());
-    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
-    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask2.getUuid());
-    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
-    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), inProgressTask.getUuid());
-    assertThat(history.isPresent()).isFalse();
-
-    verify(listener).onRemoved(pendingTask1, CeActivityDto.Status.CANCELED);
-    verify(listener).onRemoved(pendingTask2, CeActivityDto.Status.CANCELED);
-  }
-
-  @Test
-  public void pause_and_resume_submits() throws Exception {
-    assertThat(underTest.isSubmitPaused()).isFalse();
-    underTest.pauseSubmit();
-    assertThat(underTest.isSubmitPaused()).isTrue();
-    underTest.resumeSubmit();
-    assertThat(underTest.isSubmitPaused()).isFalse();
-  }
-
-  @Test
-  public void pause_and_resume_peeks() throws Exception {
-    assertThat(underTest.isPeekPaused()).isFalse();
-    underTest.pausePeek();
-    assertThat(underTest.isPeekPaused()).isTrue();
-    underTest.resumePeek();
-    assertThat(underTest.isPeekPaused()).isFalse();
-  }
-
-  private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto) {
-    assertThat(task.getUuid()).isEqualTo(taskSubmit.getUuid());
-    assertThat(task.getComponentUuid()).isEqualTo(task.getComponentUuid());
-    assertThat(task.getType()).isEqualTo(taskSubmit.getType());
-    if (componentDto == null) {
-      assertThat(task.getComponentKey()).isNull();
-      assertThat(task.getComponentName()).isNull();
-    } else {
-      assertThat(task.getComponentKey()).isEqualTo(componentDto.key());
-      assertThat(task.getComponentName()).isEqualTo(componentDto.name());
-    }
-    assertThat(task.getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin());
-  }
-
-  private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) {
-    Optional<CeQueueDto> queueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), taskSubmit.getUuid());
-    assertThat(queueDto.isPresent()).isTrue();
-    assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType());
-    assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid());
-    assertThat(queueDto.get().getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin());
-    assertThat(queueDto.get().getCreatedAt()).isEqualTo(1_450_000_000_000L);
-  }
-
-  private static ComponentDto newComponentDto(String uuid) {
-    return new ComponentDto().setUuid(uuid).setName("name_" + uuid).setKey("key_" + uuid);
-  }
-
-  private CeTask submit(String reportType, String componentUuid) {
-    return underTest.submit(createTaskSubmit(reportType, componentUuid, null));
-  }
-
-  private CeTaskSubmit createTaskSubmit(String type) {
-    return createTaskSubmit(type, null, null);
-  }
-
-  private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUuid, @Nullable String submitterLogin) {
-    CeTaskSubmit.Builder submission = underTest.prepareSubmit();
-    submission.setType(type);
-    submission.setComponentUuid(componentUuid);
-    submission.setSubmitterLogin(submitterLogin);
-    return submission.build();
-  }
-
-  private CeTaskResult newTaskResult(Long snapshotId) {
-    CeTaskResult taskResult = mock(CeTaskResult.class);
-    when(taskResult.getSnapshotId()).thenReturn(snapshotId);
-    return taskResult;
-  }
-
-  private ComponentDto insertComponent(ComponentDto componentDto) {
-    dbTester.getDbClient().componentDao().insert(session, componentDto);
-    session.commit();
-    return componentDto;
-  }
-}
index 98a93e18becebfebf7ed5189bc82c3f6bcfaf558..41f42da6364dcf9c9bed012b0fef4181e66dfb11 100644 (file)
@@ -32,9 +32,9 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
+import org.sonar.ce.monitoring.CEQueueStatus;
 import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
-import org.sonar.server.computation.queue.report.ReportFiles;
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.server.computation.taskprocessor.CeProcessingScheduler;
 
 import static org.assertj.core.api.Assertions.assertThat;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeTaskTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeTaskTest.java
deleted file mode 100644 (file)
index 9886a00..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CeTaskTest {
-
-  @Test
-  public void build() {
-    CeTask.Builder builder = new CeTask.Builder();
-    builder.setType("TYPE_1");
-    builder.setUuid("UUID_1");
-    builder.setSubmitterLogin("LOGIN_1");
-    builder.setComponentKey("COMPONENT_KEY_1");
-    builder.setComponentUuid("COMPONENT_UUID_1");
-    builder.setComponentName("The component");
-    CeTask task = builder.build();
-
-    assertThat(task.getType()).isEqualTo("TYPE_1");
-    assertThat(task.getUuid()).isEqualTo("UUID_1");
-    assertThat(task.getSubmitterLogin()).isEqualTo("LOGIN_1");
-    assertThat(task.getComponentKey()).isEqualTo("COMPONENT_KEY_1");
-    assertThat(task.getComponentUuid()).isEqualTo("COMPONENT_UUID_1");
-    assertThat(task.getComponentName()).isEqualTo("The component");
-  }
-
-  @Test
-  public void equals_and_hashCode_on_uuid() {
-    CeTask.Builder builder1 = new CeTask.Builder().setType("TYPE_1").setUuid("UUID_1");
-    CeTask task1 = builder1.build();
-    CeTask task1bis = builder1.build();
-    CeTask task2 = new CeTask.Builder().setType("TYPE_1").setUuid("UUID_2").build();
-
-    assertThat(task1.equals(task1)).isTrue();
-    assertThat(task1.equals(task1bis)).isTrue();
-    assertThat(task1.equals(task2)).isFalse();
-    assertThat(task1.hashCode()).isEqualTo(task1.hashCode());
-    assertThat(task1.hashCode()).isEqualTo(task1bis.hashCode());
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java
new file mode 100644 (file)
index 0000000..8220ef2
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.computation.queue;
+
+import com.google.common.base.Optional;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.ce.monitoring.CEQueueStatus;
+import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
+import org.sonar.ce.queue.CeQueueListener;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskSubmit;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryImpl;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.startsWith;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class InternalCeQueueImplTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  System2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
+
+  @Rule
+  public DbTester dbTester = DbTester.create(system2);
+  DbSession session = dbTester.getSession();
+
+  UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
+  CEQueueStatus queueStatus = new CEQueueStatusImpl();
+  CeQueueListener listener = mock(CeQueueListener.class);
+  InternalCeQueue underTest = new InternalCeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
+
+  @Before
+  public void setUp() throws Exception {
+    queueStatus.initPendingCount(0);
+  }
+
+  @Test
+  public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
+    CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
+    CeTask task = underTest.submit(taskSubmit);
+
+    verifyCeTask(taskSubmit, task, null);
+    verifyCeQueueDtoForTaskSubmit(taskSubmit);
+  }
+
+  @Test
+  public void submit_increments_receivedCount_of_QueueStatus() {
+    underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(1L);
+
+    underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_2", "rob"));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
+  }
+
+  @Test
+  public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
+    ComponentDto componentDto = insertComponent(newComponentDto("PROJECT_1"));
+    CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null);
+
+    CeTask task = underTest.submit(taskSubmit);
+
+    verifyCeTask(taskSubmit, task, componentDto);
+  }
+
+  @Test
+  public void submit_returns_task_without_component_info_when_submit_has_none() {
+    CeTaskSubmit taskSubmit = createTaskSubmit("not cpt related");
+
+    CeTask task = underTest.submit(taskSubmit);
+
+    verifyCeTask(taskSubmit, task, null);
+  }
+
+  @Test
+  public void submit_fails_with_ISE_if_paused() {
+    underTest.pauseSubmit();
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Compute Engine does not currently accept new tasks");
+
+    submit(CeTaskTypes.REPORT, "PROJECT_1");
+  }
+
+  @Test
+  public void massSubmit_returns_tasks_for_each_CeTaskSubmit_populated_from_CeTaskSubmit_and_creates_CeQueue_row_for_each() {
+    CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
+    CeTaskSubmit taskSubmit2 = createTaskSubmit("some type");
+
+    List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
+
+    assertThat(tasks).hasSize(2);
+    verifyCeTask(taskSubmit1, tasks.get(0), null);
+    verifyCeTask(taskSubmit2, tasks.get(1), null);
+    verifyCeQueueDtoForTaskSubmit(taskSubmit1);
+    verifyCeQueueDtoForTaskSubmit(taskSubmit2);
+  }
+
+  @Test
+  public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() {
+    ComponentDto componentDto1 = insertComponent(newComponentDto("PROJECT_1"));
+    CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null);
+    CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null);
+
+    List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
+
+    assertThat(tasks).hasSize(2);
+    verifyCeTask(taskSubmit1, tasks.get(0), componentDto1);
+    verifyCeTask(taskSubmit2, tasks.get(1), null);
+  }
+
+  @Test
+  public void massSubmit_increments_receivedCount_of_QueueStatus() {
+    underTest.massSubmit(asList(createTaskSubmit("type 1"), createTaskSubmit("type 2")));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
+
+    underTest.massSubmit(asList(createTaskSubmit("a"), createTaskSubmit("a"), createTaskSubmit("b")));
+
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(5L);
+  }
+
+  @Test
+  public void test_remove() {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    Optional<CeTask> peek = underTest.peek();
+    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, null);
+
+    // queue is empty
+    assertThat(dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), task.getUuid()).isPresent()).isFalse();
+    assertThat(underTest.peek().isPresent()).isFalse();
+
+    // available in history
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(history.isPresent()).isTrue();
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
+    assertThat(history.get().getIsLast()).isTrue();
+    assertThat(history.get().getSnapshotId()).isNull();
+
+    verify(listener).onRemoved(task, CeActivityDto.Status.SUCCESS);
+  }
+
+  @Test
+  public void remove_does_not_set_snapshotId_in_CeActivity_when_CeTaskResult_has_no_snapshot_id() {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    Optional<CeTask> peek = underTest.peek();
+    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(null));
+
+    // available in history
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(history.isPresent()).isTrue();
+    assertThat(history.get().getSnapshotId()).isNull();
+  }
+
+  @Test
+  public void remove_sets_snapshotId_in_CeActivity_when_CeTaskResult_has_no_snapshot_id() {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    long snapshotId = 663L;
+
+    Optional<CeTask> peek = underTest.peek();
+    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(snapshotId));
+
+    // available in history
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(history.isPresent()).isTrue();
+    assertThat(history.get().getSnapshotId()).isEqualTo(snapshotId);
+  }
+
+  @Test
+  public void fail_to_remove_if_not_in_queue() throws Exception {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    underTest.remove(task, CeActivityDto.Status.SUCCESS, null);
+
+    expectedException.expect(IllegalStateException.class);
+
+    underTest.remove(task, CeActivityDto.Status.SUCCESS, null);
+  }
+
+  @Test
+  public void test_peek() throws Exception {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+
+    Optional<CeTask> peek = underTest.peek();
+    assertThat(peek.isPresent()).isTrue();
+    assertThat(peek.get().getUuid()).isEqualTo(task.getUuid());
+    assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT);
+    assertThat(peek.get().getComponentUuid()).isEqualTo("PROJECT_1");
+
+    // no more pending tasks
+    peek = underTest.peek();
+    assertThat(peek.isPresent()).isFalse();
+
+    verify(listener, never()).onRemoved(eq(task), any(CeActivityDto.Status.class));
+  }
+
+  @Test
+  public void peek_nothing_if_paused() throws Exception {
+    submit(CeTaskTypes.REPORT, "PROJECT_1");
+    underTest.pausePeek();
+
+    Optional<CeTask> peek = underTest.peek();
+    assertThat(peek.isPresent()).isFalse();
+  }
+
+  @Test
+  public void cancel_pending() throws Exception {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+
+    // ignore
+    boolean canceled = underTest.cancel("UNKNOWN");
+    assertThat(canceled).isFalse();
+    verifyZeroInteractions(listener);
+
+    canceled = underTest.cancel(task.getUuid());
+    assertThat(canceled).isTrue();
+    Optional<CeActivityDto> activity = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(activity.isPresent()).isTrue();
+    assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    verify(listener).onRemoved(task, CeActivityDto.Status.CANCELED);
+  }
+
+  @Test
+  public void fail_to_cancel_if_in_progress() throws Exception {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(startsWith("Task is in progress and can't be canceled"));
+
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    underTest.peek();
+
+    underTest.cancel(task.getUuid());
+  }
+
+  @Test
+  public void cancelAll_pendings_but_not_in_progress() throws Exception {
+    CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2");
+    CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3");
+    underTest.peek();
+
+    int canceledCount = underTest.cancelAll();
+    assertThat(canceledCount).isEqualTo(2);
+
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask1.getUuid());
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask2.getUuid());
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), inProgressTask.getUuid());
+    assertThat(history.isPresent()).isFalse();
+
+    verify(listener).onRemoved(pendingTask1, CeActivityDto.Status.CANCELED);
+    verify(listener).onRemoved(pendingTask2, CeActivityDto.Status.CANCELED);
+  }
+
+  @Test
+  public void pause_and_resume_submits() throws Exception {
+    assertThat(underTest.isSubmitPaused()).isFalse();
+    underTest.pauseSubmit();
+    assertThat(underTest.isSubmitPaused()).isTrue();
+    underTest.resumeSubmit();
+    assertThat(underTest.isSubmitPaused()).isFalse();
+  }
+
+  @Test
+  public void pause_and_resume_peeks() throws Exception {
+    assertThat(underTest.isPeekPaused()).isFalse();
+    underTest.pausePeek();
+    assertThat(underTest.isPeekPaused()).isTrue();
+    underTest.resumePeek();
+    assertThat(underTest.isPeekPaused()).isFalse();
+  }
+
+  private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto) {
+    assertThat(task.getUuid()).isEqualTo(taskSubmit.getUuid());
+    assertThat(task.getComponentUuid()).isEqualTo(task.getComponentUuid());
+    assertThat(task.getType()).isEqualTo(taskSubmit.getType());
+    if (componentDto == null) {
+      assertThat(task.getComponentKey()).isNull();
+      assertThat(task.getComponentName()).isNull();
+    } else {
+      assertThat(task.getComponentKey()).isEqualTo(componentDto.key());
+      assertThat(task.getComponentName()).isEqualTo(componentDto.name());
+    }
+    assertThat(task.getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin());
+  }
+
+  private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) {
+    Optional<CeQueueDto> queueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), taskSubmit.getUuid());
+    assertThat(queueDto.isPresent()).isTrue();
+    assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType());
+    assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid());
+    assertThat(queueDto.get().getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin());
+    assertThat(queueDto.get().getCreatedAt()).isEqualTo(1_450_000_000_000L);
+  }
+
+  private static ComponentDto newComponentDto(String uuid) {
+    return new ComponentDto().setUuid(uuid).setName("name_" + uuid).setKey("key_" + uuid);
+  }
+
+  private CeTask submit(String reportType, String componentUuid) {
+    return underTest.submit(createTaskSubmit(reportType, componentUuid, null));
+  }
+
+  private CeTaskSubmit createTaskSubmit(String type) {
+    return createTaskSubmit(type, null, null);
+  }
+
+  private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUuid, @Nullable String submitterLogin) {
+    CeTaskSubmit.Builder submission = underTest.prepareSubmit();
+    submission.setType(type);
+    submission.setComponentUuid(componentUuid);
+    submission.setSubmitterLogin(submitterLogin);
+    return submission.build();
+  }
+
+  private CeTaskResult newTaskResult(Long snapshotId) {
+    CeTaskResult taskResult = mock(CeTaskResult.class);
+    when(taskResult.getSnapshotId()).thenReturn(snapshotId);
+    return taskResult;
+  }
+
+  private ComponentDto insertComponent(ComponentDto componentDto) {
+    dbTester.getDbClient().componentDao().insert(session, componentDto);
+    session.commit();
+    return componentDto;
+  }
+}
index eb03752cb16b36f65fe238028873c5395cce3548..0c2991d48e5c9ecbc758d8b6b7a20d1d3bfb1291 100644 (file)
 package org.sonar.server.computation.queue.report;
 
 import org.junit.Test;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.report.ReportFiles;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.queue.CeTask;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/report/ReportSubmitterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/report/ReportSubmitterTest.java
deleted file mode 100644 (file)
index c45201b..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.queue.report;
-
-import org.apache.commons.io.IOUtils;
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.server.component.ComponentService;
-import org.sonar.server.component.NewComponent;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.computation.queue.CeQueueImpl;
-import org.sonar.server.computation.queue.CeTaskSubmit;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.permission.PermissionService;
-import org.sonar.server.tester.UserSessionRule;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class ReportSubmitterTest {
-
-  static final String PROJECT_KEY = "MY_PROJECT";
-  static final String PROJECT_UUID = "P1";
-  static final String PROJECT_NAME = "My Project";
-  static final String TASK_UUID = "TASK_1";
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-
-  CeQueue queue = mock(CeQueueImpl.class);
-  ReportFiles reportFiles = mock(ReportFiles.class);
-  ComponentService componentService = mock(ComponentService.class);
-  PermissionService permissionService = mock(PermissionService.class);
-  ReportSubmitter underTest = new ReportSubmitter(queue, userSession, reportFiles, componentService, permissionService);
-
-  @Test
-  public void submit_a_report_on_existing_project() {
-    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(new ComponentDto().setUuid(PROJECT_UUID));
-
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-
-    verifyZeroInteractions(permissionService);
-    verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
-      @Override
-      protected boolean matchesSafely(CeTaskSubmit submit) {
-        return submit.getType().equals(CeTaskTypes.REPORT) && submit.getComponentUuid().equals(PROJECT_UUID) &&
-          submit.getUuid().equals(TASK_UUID);
-      }
-
-      @Override
-      public void describeTo(Description description) {
-
-      }
-    }));
-  }
-
-  @Test
-  public void provision_project_if_does_not_exist() throws Exception {
-    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.PROVISIONING);
-
-    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
-    when(componentService.create(any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
-
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-
-    verify(permissionService).applyDefaultPermissionTemplate(PROJECT_KEY);
-    verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
-      @Override
-      protected boolean matchesSafely(CeTaskSubmit submit) {
-        return submit.getType().equals(CeTaskTypes.REPORT) && submit.getComponentUuid().equals(PROJECT_UUID) &&
-          submit.getUuid().equals(TASK_UUID);
-      }
-
-      @Override
-      public void describeTo(Description description) {
-
-      }
-    }));
-  }
-
-  @Test
-  public void submit_a_report_on_new_project_with_global_scan_permission() {
-    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
-    when(componentService.create(any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
-
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-
-    verify(queue).submit(any(CeTaskSubmit.class));
-  }
-
-  @Test
-  public void submit_a_report_on_existing_project_with_global_scan_permission() {
-    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(new ComponentDto().setUuid(PROJECT_UUID));
-
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-
-    verify(queue).submit(any(CeTaskSubmit.class));
-  }
-
-  @Test
-  public void submit_a_report_on_existing_project_with_project_scan_permission() {
-    userSession.addProjectPermissions(GlobalPermissions.SCAN_EXECUTION, PROJECT_KEY);
-
-    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(new ComponentDto().setUuid(PROJECT_UUID));
-
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-
-    verify(queue).submit(any(CeTaskSubmit.class));
-  }
-
-  @Test
-  public void fail_with_forbidden_exception_when_no_scan_permission() {
-    userSession.setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING);
-
-    thrown.expect(ForbiddenException.class);
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-  }
-
-  @Test
-  public void fail_with_forbidden_exception_on_new_project_when_only_project_scan_permission() {
-    userSession.addProjectPermissions(GlobalPermissions.SCAN_EXECUTION, PROJECT_KEY);
-
-    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
-    when(componentService.create(any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
-
-    thrown.expect(ForbiddenException.class);
-    underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-  }
-
-}
index c767d044bd86a1d82c6efdde386f4a8d0aae4fc6..ae71f067071fec0055343b15ec247a8b75dcc83f 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.core.platform.ComponentContainer;
 import org.sonar.server.computation.container.ComputeEngineContainerImpl;
 import org.sonar.server.computation.container.ReportComputeEngineContainerPopulator;
 import org.sonar.server.computation.container.StepsExplorer;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 
 import static com.google.common.collect.FluentIterable.from;
 import static com.google.common.collect.Sets.difference;
index d8d9716622866bdcb4e8044ed28ae0e19c31d0e9..29246afb7c8aa61d7d4efcbe42b78732e9d39d4d 100644 (file)
@@ -33,8 +33,8 @@ import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.server.computation.batch.MutableBatchReportDirectoryHolder;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.report.ReportFiles;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.report.ReportFiles;
 
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Mockito.mock;
index c1bab1e087507b54006ead82919905bda191aeda..dfcc110d6ff66d79dde0121d67d4097c72a76ab9 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.api.utils.MessageException;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.server.computation.analysis.MutableAnalysisMetadataHolderRule;
 import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.ce.queue.CeTask;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
index d3412b0882b3ee06acdac33048ee1328c7f33a5a..911a84e44116a94540df14a666eca2cfee0b6f30 100644 (file)
@@ -24,8 +24,9 @@ import java.util.Set;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.guava.api.Assertions.assertThat;
index 375968064804ede0a38651bd7094d6f645bc2d37..2f745d280934da3b6f367c44e275e935fab1c225 100644 (file)
@@ -24,8 +24,9 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 import org.junit.rules.ExternalResource;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskResult;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
index f9d708ee8384382059e994ea95995c323cb82de5..a4648392c1378ddda45fe6113ffbb1d5583a70c2 100644 (file)
@@ -24,12 +24,11 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.InOrder;
 import org.mockito.Mockito;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.queue.CeTask;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.computation.queue.CeQueueImpl;
-import org.sonar.server.computation.queue.CeTask;
+import org.sonar.server.computation.queue.InternalCeQueue;
 import org.sonar.server.computation.taskprocessor.report.ReportTaskProcessor;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -43,7 +42,7 @@ public class CeWorkerCallableImplTest {
   @Rule
   public CeTaskProcessorRepositoryRule taskProcessorRepository = new CeTaskProcessorRepositoryRule();
 
-  CeQueue queue = mock(CeQueueImpl.class);
+  InternalCeQueue queue = mock(InternalCeQueue.class);
   ReportTaskProcessor taskProcessor = mock(ReportTaskProcessor.class);
   CeLogging ceLogging = mock(CeLogging.class);
   CeWorkerCallable underTest = new CeWorkerCallableImpl(queue, ceLogging, taskProcessorRepository);
index 5b9df2bde0f794ac9e41d5fed2c4629eb5b3bceb..221e2ed330592a593a4df0c17ca97bcf0ed64bbb 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.computation.taskprocessor;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java
deleted file mode 100644 (file)
index 049725d..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Throwables;
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDbTester;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonar.server.computation.taskprocessor.CeTaskProcessor;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.TestRequest;
-import org.sonar.server.ws.TestResponse;
-import org.sonar.server.ws.WsActionTester;
-import org.sonar.test.JsonAssert;
-import org.sonarqube.ws.MediaTypes;
-import org.sonarqube.ws.WsCe;
-import org.sonarqube.ws.WsCe.ActivityResponse;
-import org.sonarqube.ws.client.ce.CeWsParameters;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.api.utils.DateUtils.formatDate;
-import static org.sonar.api.utils.DateUtils.formatDateTime;
-import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY;
-import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_STATUS;
-
-public class ActivityActionTest {
-
-  private static final long EXECUTED_AT = System2.INSTANCE.now();
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  ComponentDbTester componentDb = new ComponentDbTester(dbTester);
-
-  CeLogging ceLogging = mock(CeLogging.class);
-  TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), ceLogging, System2.INSTANCE);
-  ActivityAction underTest = new ActivityAction(userSession, dbTester.getDbClient(), formatter, new CeTaskProcessor[] {mock(CeTaskProcessor.class)});
-  WsActionTester ws = new WsActionTester(underTest);
-
-  @Before
-  public void setUp() {
-    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.<File>absent());
-  }
-
-  @Test
-  public void get_all_past_activity() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-
-    ActivityResponse activityResponse = call(ws.newRequest()
-      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, formatDateTime(EXECUTED_AT + 2_000)));
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(2);
-    // chronological order, from newest to oldest
-    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T2");
-    assertThat(activityResponse.getTasks(0).getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
-    assertThat(activityResponse.getTasks(0).getComponentId()).isEqualTo("PROJECT_2");
-    assertThat(activityResponse.getTasks(0).getAnalysisId()).isEqualTo("123456");
-    assertThat(activityResponse.getTasks(0).getExecutionTimeMs()).isEqualTo(500L);
-    assertThat(activityResponse.getTasks(0).getLogs()).isFalse();
-    assertThat(activityResponse.getTasks(1).getId()).isEqualTo("T1");
-    assertThat(activityResponse.getTasks(1).getStatus()).isEqualTo(WsCe.TaskStatus.SUCCESS);
-    assertThat(activityResponse.getTasks(1).getComponentId()).isEqualTo("PROJECT_1");
-    assertThat(activityResponse.getTasks(1).getLogs()).isFalse();
-  }
-
-  @Test
-  public void filter_by_status() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
-
-    ActivityResponse activityResponse = call(ws.newRequest()
-      .setParam("status", "FAILED,IN_PROGRESS"));
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(2);
-    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T3");
-    assertThat(activityResponse.getTasks(1).getId()).isEqualTo("T2");
-  }
-
-  @Test
-  public void filter_by_max_executed_at_exclude() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
-
-    ActivityResponse activityResponse = call(ws.newRequest()
-      .setParam("status", "FAILED,IN_PROGRESS,SUCCESS")
-      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, "2016-02-15"));
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(0);
-  }
-
-  @Test
-  public void filter_by_max_executed_at_include_day_filled() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    String today = formatDate(new Date(EXECUTED_AT));
-    System.out.println(EXECUTED_AT + " - " + today);
-
-    ActivityResponse activityResponse = call(ws.newRequest()
-      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, today));
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(1);
-  }
-
-  @Test
-  public void filter_on_current_activities() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    // T2 is the current activity (the most recent one)
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_1", CeActivityDto.Status.FAILED);
-    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.PENDING);
-
-    ActivityResponse activityResponse = call(
-      ws.newRequest()
-        .setParam("onlyCurrents", "true"));
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(1);
-    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T2");
-  }
-
-  @Test
-  public void paginate_results() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-    insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
-
-    assertPage(1, 1, 3, asList("T3"));
-    assertPage(2, 1, 3, asList("T2"));
-    assertPage(1, 10, 3, asList("T3", "T2", "T1"));
-    assertPage(2, 10, 3, Collections.<String>emptyList());
-  }
-
-  private void assertPage(int pageIndex, int pageSize, int expectedTotal, List<String> expectedOrderedTaskIds) {
-    ActivityResponse activityResponse = call(ws.newRequest()
-      .setParam(Param.PAGE, Integer.toString(pageIndex))
-      .setParam(Param.PAGE_SIZE, Integer.toString(pageSize))
-      .setParam(PARAM_STATUS, "SUCCESS,FAILED,CANCELED,IN_PROGRESS,PENDING"));
-
-    assertThat(activityResponse.getPaging().getPageIndex()).isEqualTo(pageIndex);
-    assertThat(activityResponse.getPaging().getPageSize()).isEqualTo(pageSize);
-    assertThat(activityResponse.getPaging().getTotal()).isEqualTo(expectedTotal);
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(expectedOrderedTaskIds.size());
-    for (int i = 0; i < expectedOrderedTaskIds.size(); i++) {
-      String expectedTaskId = expectedOrderedTaskIds.get(i);
-      assertThat(activityResponse.getTasks(i).getId()).isEqualTo(expectedTaskId);
-    }
-  }
-
-  @Test
-  public void project_administrator_can_access_his_project_activity() {
-    // no need to be a system admin
-    userSession.addComponentUuidPermission(UserRole.ADMIN, "PROJECT_1", "PROJECT_1");
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-
-    ActivityResponse activityResponse = call(ws.newRequest().setParam("componentId", "PROJECT_1"));
-
-    assertThat(activityResponse.getTasksCount()).isEqualTo(1);
-    assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T1");
-    assertThat(activityResponse.getTasks(0).getStatus()).isEqualTo(WsCe.TaskStatus.SUCCESS);
-    assertThat(activityResponse.getTasks(0).getComponentId()).isEqualTo("PROJECT_1");
-  }
-
-  @Test
-  public void search_activity_by_component_name() throws IOException {
-    componentDb.insertProjectAndSnapshot(newProjectDto().setName("apache struts").setUuid("P1"));
-    componentDb.insertProjectAndSnapshot(newProjectDto().setName("apache zookeeper").setUuid("P2"));
-    componentDb.insertProjectAndSnapshot(newProjectDto().setName("eclipse").setUuid("P3"));
-    dbTester.commit();
-    componentDb.indexProjects();
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    insertActivity("T1", "P1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "P2", CeActivityDto.Status.SUCCESS);
-    insertActivity("T3", "P3", CeActivityDto.Status.SUCCESS);
-
-    ActivityResponse activityResponse = call(ws.newRequest().setParam(PARAM_COMPONENT_QUERY, "apac"));
-
-    assertThat(activityResponse.getTasksList()).extracting("id").containsOnly("T1", "T2");
-  }
-
-  @Test
-  public void search_task_id_in_queue_ignoring_other_parameters() throws IOException {
-    insertQueue("T1", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
-
-    ActivityResponse result = call(
-      ws.newRequest()
-        .setParam(Param.TEXT_QUERY, "T1")
-        .setParam(PARAM_STATUS, CeQueueDto.Status.PENDING.name()));
-
-    assertThat(result.getTasksCount()).isEqualTo(1);
-    assertThat(result.getTasks(0).getId()).isEqualTo("T1");
-  }
-
-  @Test
-  public void search_task_id_in_activity() {
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-
-    ActivityResponse result = call(ws.newRequest().setParam(Param.TEXT_QUERY, "T1"));
-
-    assertThat(result.getTasksCount()).isEqualTo(1);
-    assertThat(result.getTasks(0).getId()).isEqualTo("T1");
-  }
-
-  @Test
-  public void fail_if_both_filters_on_component_id_and_name() {
-    expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("componentId and componentQuery must not be set at the same time");
-
-    ws.newRequest()
-      .setParam("componentId", "ID1")
-      .setParam("componentQuery", "apache")
-      .setMediaType(MediaTypes.PROTOBUF)
-      .execute();
-  }
-
-  @Test
-  public void fail_if_page_size_greater_than_1000() {
-    expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("The 'ps' parameter must be less than 1000");
-
-    ws.newRequest()
-      .setParam(Param.PAGE_SIZE, "1001")
-      .execute();
-  }
-
-  @Test
-  public void fail_if_date_is_not_well_formatted() {
-    expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Date 'ill-formatted-date' cannot be parsed as either a date or date+time");
-
-    ws.newRequest()
-      .setParam(CeWsParameters.PARAM_MAX_EXECUTED_AT, "ill-formatted-date")
-      .execute();
-  }
-
-  @Test
-  public void support_json_response() {
-    userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    TestResponse wsResponse = ws.newRequest()
-      .setMediaType(MediaTypes.JSON)
-      .execute();
-
-    JsonAssert.assertJson(wsResponse.getInput()).isSimilarTo("{\"tasks\":[]}");
-  }
-
-  private CeQueueDto insertQueue(String taskUuid, String componentUuid, CeQueueDto.Status status) {
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setComponentUuid(componentUuid);
-    queueDto.setUuid(taskUuid);
-    queueDto.setStatus(status);
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
-    return queueDto;
-  }
-
-  private CeActivityDto insertActivity(String taskUuid, String componentUuid, CeActivityDto.Status status) {
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setComponentUuid(componentUuid);
-    queueDto.setUuid(taskUuid);
-    CeActivityDto activityDto = new CeActivityDto(queueDto);
-    activityDto.setStatus(status);
-    activityDto.setExecutionTimeMs(500L);
-    activityDto.setExecutedAt(EXECUTED_AT);
-    activityDto.setSnapshotId(123_456L);
-    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
-    dbTester.commit();
-    return activityDto;
-  }
-
-  private static ActivityResponse call(TestRequest request) {
-    try {
-      return ActivityResponse.parseFrom(
-        request
-          .setMediaType(MediaTypes.PROTOBUF)
-          .execute().getInputStream());
-    } catch (IOException e) {
-      throw Throwables.propagate(e);
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CancelActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CancelActionTest.java
deleted file mode 100644 (file)
index 1e18687..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.db.DbTester;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsActionTester;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-public class CancelActionTest {
-
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  CeQueue queue = mock(CeQueue.class);
-  CancelAction underTest = new CancelAction(userSession, queue);
-  WsActionTester tester = new WsActionTester(underTest);
-
-  @Test
-  public void cancel_pending_task() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-
-    tester.newRequest()
-      .setParam("id", "T1")
-      .execute();
-
-    verify(queue).cancel("T1");
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void missing_id() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-
-    tester.newRequest().execute();
-
-    verifyZeroInteractions(queue);
-  }
-
-  @Test(expected = ForbiddenException.class)
-  public void not_authorized() {
-    tester.newRequest()
-      .setParam("id", "T1")
-      .execute();
-
-    verifyZeroInteractions(queue);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CancelAllActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CancelAllActionTest.java
deleted file mode 100644 (file)
index 37d826c..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.db.DbTester;
-import org.sonar.server.computation.queue.CeQueue;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsActionTester;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-public class CancelAllActionTest {
-
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  CeQueue queue = mock(CeQueue.class);
-  CancelAllAction underTest = new CancelAllAction(userSession, queue);
-  WsActionTester tester = new WsActionTester(underTest);
-
-  @Test
-  public void cancel_all_pending_tasks() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-
-    tester.newRequest().execute();
-
-    verify(queue).cancelAll();
-  }
-
-  @Test(expected = ForbiddenException.class)
-  public void not_authorized() {
-    tester.newRequest().execute();
-
-    verifyZeroInteractions(queue);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsModuleTest.java
deleted file mode 100644 (file)
index 5186c1a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CeWsModuleTest {
-
-  @Test
-  public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
-    new CeWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(11 + 2 /* injected by ComponentContainer */);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsTest.java
deleted file mode 100644 (file)
index c8ccbda..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.computation.queue.report.ReportSubmitter;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class CeWsTest {
-
-  @Test
-  public void define() throws Exception {
-    CeWsAction wsAction = new SubmitAction(mock(ReportSubmitter.class));
-
-    CeWs ws = new CeWs(wsAction);
-    WebService.Context context = mock(WebService.Context.class, Mockito.RETURNS_DEEP_STUBS);
-    ws.define(context);
-
-    assertThat(context.controller("api/ce")).isNotNull();
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java
deleted file mode 100644 (file)
index 1c97a73..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import java.io.File;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.util.Protobuf;
-import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonarqube.ws.MediaTypes;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.TestResponse;
-import org.sonar.server.ws.WsActionTester;
-import org.sonarqube.ws.WsCe;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ComponentActionTest {
-
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  CeLogging ceLogging = mock(CeLogging.class);
-  TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), ceLogging, System2.INSTANCE);
-  ComponentAction underTest = new ComponentAction(userSession, dbTester.getDbClient(), formatter);
-  WsActionTester tester = new WsActionTester(underTest);
-
-  @Before
-  public void setUp() {
-    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.<File>absent());
-  }
-
-  @Test
-  public void empty_queue_and_empty_activity() {
-    userSession.addComponentUuidPermission(UserRole.USER, "PROJECT_1", "PROJECT_1");
-
-    TestResponse wsResponse = tester.newRequest()
-      .setParam("componentId", "PROJECT_1")
-      .setMediaType(MediaTypes.PROTOBUF)
-      .execute();
-
-    WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
-    assertThat(response.getQueueCount()).isEqualTo(0);
-    assertThat(response.hasCurrent()).isFalse();
-  }
-
-  @Test
-  public void project_tasks() {
-    userSession.addComponentUuidPermission(UserRole.USER, "PROJECT_1", "PROJECT_1");
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-    insertActivity("T3", "PROJECT_1", CeActivityDto.Status.FAILED);
-    insertQueue("T4", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
-    insertQueue("T5", "PROJECT_1", CeQueueDto.Status.PENDING);
-
-    TestResponse wsResponse = tester.newRequest()
-      .setParam("componentId", "PROJECT_1")
-      .setMediaType(MediaTypes.PROTOBUF)
-      .execute();
-
-    WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
-    assertThat(response.getQueueCount()).isEqualTo(2);
-    assertThat(response.getQueue(0).getId()).isEqualTo("T4");
-    assertThat(response.getQueue(1).getId()).isEqualTo("T5");
-    // T3 is the latest task executed on PROJECT_1
-    assertThat(response.hasCurrent()).isTrue();
-    assertThat(response.getCurrent().getId()).isEqualTo("T3");
-  }
-
-  @Test
-  public void canceled_tasks_must_not_be_picked_as_current_analysis() {
-    userSession.addComponentUuidPermission(UserRole.USER, "PROJECT_1", "PROJECT_1");
-    insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
-    insertActivity("T3", "PROJECT_1", CeActivityDto.Status.SUCCESS);
-    insertActivity("T4", "PROJECT_1", CeActivityDto.Status.CANCELED);
-    insertActivity("T5", "PROJECT_1", CeActivityDto.Status.CANCELED);
-
-    TestResponse wsResponse = tester.newRequest()
-        .setParam("componentId", "PROJECT_1")
-        .setMediaType(MediaTypes.PROTOBUF)
-        .execute();
-
-    WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
-    assertThat(response.getQueueCount()).isEqualTo(0);
-    // T3 is the latest task executed on PROJECT_1 ignoring Canceled ones
-    assertThat(response.hasCurrent()).isTrue();
-    assertThat(response.getCurrent().getId()).isEqualTo("T3");
-  }
-
-  private CeQueueDto insertQueue(String taskUuid, String componentUuid, CeQueueDto.Status status) {
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setComponentUuid(componentUuid);
-    queueDto.setUuid(taskUuid);
-    queueDto.setStatus(status);
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.getSession().commit();
-    return queueDto;
-  }
-
-  private CeActivityDto insertActivity(String taskUuid, String componentUuid, CeActivityDto.Status status) {
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setComponentUuid(componentUuid);
-    queueDto.setUuid(taskUuid);
-    CeActivityDto activityDto = new CeActivityDto(queueDto);
-    activityDto.setStatus(status);
-    activityDto.setExecutionTimeMs(500L);
-    activityDto.setSnapshotId(123_456L);
-    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
-    dbTester.getSession().commit();
-    return activityDto;
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/LogsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/LogsActionTest.java
deleted file mode 100644 (file)
index 9fb0875..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import java.io.File;
-import java.io.IOException;
-import javax.annotation.Nullable;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonarqube.ws.MediaTypes;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.TestResponse;
-import org.sonar.server.ws.WsActionTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class LogsActionTest {
-
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  CeLogging ceLogging = mock(CeLogging.class);
-  LogsAction underTest = new LogsAction(dbTester.getDbClient(), userSession, ceLogging);
-  WsActionTester tester = new WsActionTester(underTest);
-
-  @Test
-  public void return_task_logs_if_available() throws IOException {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-
-    // task must exist in database
-    insert("TASK_1", null);
-    File logFile = temp.newFile();
-    FileUtils.write(logFile, "{logs}");
-    when(ceLogging.getFile(new LogFileRef(CeTaskTypes.REPORT, "TASK_1", null))).thenReturn(Optional.of(logFile));
-
-    TestResponse response = tester.newRequest()
-      .setParam("taskId", "TASK_1")
-      .execute();
-
-    assertThat(response.getMediaType()).isEqualTo(MediaTypes.TXT);
-    assertThat(response.getInput()).isEqualTo("{logs}");
-  }
-
-  /**
-   * The parameter taskId is present but empty. It's considered as
-   * a valid task which does not exist
-   */
-  @Test(expected = NotFoundException.class)
-  public void return_404_if_task_id_is_empty() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-    tester.newRequest()
-      .setParam("taskId", "")
-      .execute();
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void bad_request_if_task_id_is_missing() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-    tester.newRequest()
-      .execute();
-  }
-
-  @Test(expected = NotFoundException.class)
-  public void return_404_if_task_logs_are_not_available() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-    insert("TASK_1", null);
-    when(ceLogging.getFile(new LogFileRef(CeTaskTypes.REPORT, "TASK_1", null))).thenReturn(Optional.<File>absent());
-
-    tester.newRequest()
-      .setParam("taskId", "TASK_1")
-      .execute();
-  }
-
-  @Test(expected = NotFoundException.class)
-  public void return_404_if_task_does_not_exist() {
-    userSession.setGlobalPermissions(UserRole.ADMIN);
-    tester.newRequest()
-      .setParam("taskId", "TASK_1")
-      .execute();
-  }
-
-  @Test(expected = ForbiddenException.class)
-  public void require_admin_permission() {
-    tester.newRequest()
-      .setParam("taskId", "TASK_1")
-      .execute();
-  }
-
-  private CeQueueDto insert(String taskUuid, @Nullable String componentUuid) {
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setComponentUuid(componentUuid);
-    queueDto.setUuid(taskUuid);
-    queueDto.setStatus(CeQueueDto.Status.IN_PROGRESS);
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.getSession().commit();
-    return queueDto;
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitActionTest.java
deleted file mode 100644 (file)
index 0d82f81..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import java.io.InputStream;
-import org.junit.Test;
-import org.mockito.Matchers;
-import org.sonar.core.util.Protobuf;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.report.ReportSubmitter;
-import org.sonarqube.ws.MediaTypes;
-import org.sonar.server.ws.TestResponse;
-import org.sonar.server.ws.WsActionTester;
-import org.sonar.test.JsonAssert;
-import org.sonarqube.ws.WsCe;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class SubmitActionTest {
-
-  ReportSubmitter reportSubmitter = mock(ReportSubmitter.class);
-  SubmitAction underTest = new SubmitAction(reportSubmitter);
-  WsActionTester tester = new WsActionTester(underTest);
-
-  @Test
-  public void submit_task_to_the_queue_and_ask_for_immediate_processing() {
-    CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin("robert").build();
-    when(reportSubmitter.submit(eq("my_project"), Matchers.isNull(String.class), eq("My Project"), any(InputStream.class))).thenReturn(task);
-
-    TestResponse wsResponse = tester.newRequest()
-      .setParam("projectKey", "my_project")
-      .setParam("projectName", "My Project")
-      .setParam("report", "{binary}")
-      .setMediaType(MediaTypes.PROTOBUF)
-      .setMethod("POST")
-      .execute();
-
-    verify(reportSubmitter).submit(eq("my_project"), Matchers.isNull(String.class), eq("My Project"), any(InputStream.class));
-
-    WsCe.SubmitResponse submitResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.SubmitResponse.PARSER);
-    assertThat(submitResponse.getTaskId()).isEqualTo("TASK_1");
-    assertThat(submitResponse.getProjectId()).isEqualTo("PROJECT_1");
-  }
-
-  @Test
-  public void test_example_json_response() {
-    CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin("robert").build();
-    when(reportSubmitter.submit(eq("my_project"), Matchers.isNull(String.class), eq("My Project"), any(InputStream.class))).thenReturn(task);
-
-    TestResponse wsResponse = tester.newRequest()
-      .setParam("projectKey", "my_project")
-      .setParam("projectName", "My Project")
-      .setParam("report", "{binary}")
-      .setMediaType(MediaTypes.JSON)
-      .setMethod("POST")
-      .execute();
-
-    JsonAssert.assertJson(tester.getDef().responseExampleAsString()).isSimilarTo(wsResponse.getInput());
-  }
-
-  /**
-   * If project name is not specified, then name is the project key
-   */
-  @Test
-  public void project_name_is_optional() {
-    CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin("robert").build();
-    when(reportSubmitter.submit(eq("my_project"), Matchers.isNull(String.class), eq("my_project"), any(InputStream.class))).thenReturn(task);
-
-    tester.newRequest()
-      .setParam("projectKey", "my_project")
-      .setParam("report", "{binary}")
-      .setMediaType(MediaTypes.PROTOBUF)
-      .setMethod("POST")
-      .execute();
-
-    verify(reportSubmitter).submit(eq("my_project"), Matchers.isNull(String.class), eq("my_project"), any(InputStream.class));
-
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java
deleted file mode 100644 (file)
index 18c3685..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import java.io.File;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.Protobuf;
-import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.TestResponse;
-import org.sonar.server.ws.WsActionTester;
-import org.sonarqube.ws.MediaTypes;
-import org.sonarqube.ws.WsCe;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
-import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
-import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
-
-public class TaskActionTest {
-
-  static final ComponentDto PROJECT = ComponentTesting.newProjectDto()
-    .setUuid("PROJECT_1")
-    .setName("Project One")
-    .setKey("P1");
-
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  CeLogging ceLogging = mock(CeLogging.class);
-  TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), ceLogging, System2.INSTANCE);
-  TaskAction underTest = new TaskAction(dbTester.getDbClient(), formatter, userSession);
-  WsActionTester ws = new WsActionTester(underTest);
-
-  @Before
-  public void setUp() {
-    dbTester.getDbClient().componentDao().insert(dbTester.getSession(), PROJECT);
-    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.<File>absent());
-  }
-
-  @Test
-  public void task_is_in_queue() throws Exception {
-    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setUuid("TASK_1");
-    queueDto.setComponentUuid(PROJECT.uuid());
-    queueDto.setStatus(CeQueueDto.Status.PENDING);
-    queueDto.setSubmitterLogin("john");
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
-
-    TestResponse wsResponse = ws.newRequest()
-      .setMediaType(MediaTypes.PROTOBUF)
-      .setParam("id", "TASK_1")
-      .execute();
-
-    WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
-    assertThat(taskResponse.getTask().getId()).isEqualTo("TASK_1");
-    assertThat(taskResponse.getTask().getStatus()).isEqualTo(WsCe.TaskStatus.PENDING);
-    assertThat(taskResponse.getTask().getSubmitterLogin()).isEqualTo("john");
-    assertThat(taskResponse.getTask().getComponentId()).isEqualTo(PROJECT.uuid());
-    assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(PROJECT.key());
-    assertThat(taskResponse.getTask().getComponentName()).isEqualTo(PROJECT.name());
-    assertThat(taskResponse.getTask().hasExecutionTimeMs()).isFalse();
-    assertThat(taskResponse.getTask().getLogs()).isFalse();
-  }
-
-  @Test
-  public void task_is_archived() throws Exception {
-    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setUuid("TASK_1");
-    queueDto.setComponentUuid(PROJECT.uuid());
-    CeActivityDto activityDto = new CeActivityDto(queueDto);
-    activityDto.setStatus(CeActivityDto.Status.FAILED);
-    activityDto.setExecutionTimeMs(500L);
-    activityDto.setSnapshotId(123_456L);
-    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
-    dbTester.commit();
-
-    TestResponse wsResponse = ws.newRequest()
-      .setMediaType(MediaTypes.PROTOBUF)
-      .setParam("id", "TASK_1")
-      .execute();
-
-    WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
-    WsCe.Task task = taskResponse.getTask();
-    assertThat(task.getId()).isEqualTo("TASK_1");
-    assertThat(task.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
-    assertThat(task.getComponentId()).isEqualTo(PROJECT.uuid());
-    assertThat(task.getComponentKey()).isEqualTo(PROJECT.key());
-    assertThat(task.getComponentName()).isEqualTo(PROJECT.name());
-    assertThat(task.getAnalysisId()).isEqualTo("123456");
-    assertThat(task.getExecutionTimeMs()).isEqualTo(500L);
-    assertThat(task.getLogs()).isFalse();
-  }
-
-  @Test
-  public void task_not_found() throws Exception {
-    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
-
-    expectedException.expect(NotFoundException.class);
-    ws.newRequest()
-      .setParam("id", "DOES_NOT_EXIST")
-      .execute();
-  }
-
-  @Test
-  public void not_fail_on_queue_task_not_linked_on_project_with_system_admin_permissions() {
-    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType("fake");
-    queueDto.setUuid("TASK_1");
-    queueDto.setStatus(CeQueueDto.Status.PENDING);
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
-
-    ws.newRequest()
-      .setMediaType(MediaTypes.JSON)
-      .setParam("id", "TASK_1")
-      .execute();
-  }
-
-  @Test
-  public void not_fail_on_queue_task_not_linked_on_project_with_global_scan_permissions() {
-    userSession.login("john").setGlobalPermissions(SCAN_EXECUTION);
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType("fake");
-    queueDto.setUuid("TASK_1");
-    queueDto.setStatus(CeQueueDto.Status.PENDING);
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
-
-    ws.newRequest()
-      .setMediaType(MediaTypes.JSON)
-      .setParam("id", "TASK_1")
-      .execute();
-  }
-
-  @Test
-  public void fail_on_queue_task_not_linked_on_project_if_not_admin_nor_scan_permission() {
-    userSession.login("john").setGlobalPermissions(PROVISIONING);
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType("fake");
-    queueDto.setUuid("TASK_1");
-    queueDto.setStatus(CeQueueDto.Status.PENDING);
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
-
-    expectedException.expect(ForbiddenException.class);
-    ws.newRequest()
-      .setMediaType(MediaTypes.PROTOBUF)
-      .setParam("id", "TASK_1")
-      .execute();
-  }
-
-  @Test
-  public void not_fail_on_queue_task_linked_on_project_with_project_scan_permission() {
-    userSession.login("john").addProjectUuidPermissions(SCAN_EXECUTION, PROJECT.uuid());
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType("fake");
-    queueDto.setUuid("TASK_1");
-    queueDto.setStatus(CeQueueDto.Status.PENDING);
-    queueDto.setComponentUuid(PROJECT.uuid());
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
-
-    ws.newRequest()
-      .setMediaType(MediaTypes.JSON)
-      .setParam("id", "TASK_1")
-      .execute();
-  }
-
-  @Test
-  public void not_fail_on_archived_task_linked_on_project_with_project_scan_permission() throws Exception {
-    userSession.login("john").addProjectUuidPermissions(SCAN_EXECUTION, PROJECT.uuid());
-
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setUuid("TASK_1");
-    queueDto.setComponentUuid(PROJECT.uuid());
-    CeActivityDto activityDto = new CeActivityDto(queueDto);
-    activityDto.setStatus(CeActivityDto.Status.FAILED);
-    activityDto.setExecutionTimeMs(500L);
-    activityDto.setSnapshotId(123_456L);
-    activityDto.setComponentUuid(PROJECT.uuid());
-    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
-    dbTester.commit();
-
-    ws.newRequest()
-      .setMediaType(MediaTypes.PROTOBUF)
-      .setParam("id", "TASK_1")
-      .execute();
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java
deleted file mode 100644 (file)
index 15883c8..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.base.Optional;
-import java.io.IOException;
-import java.util.Date;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.Mockito;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.server.computation.log.CeLogging;
-import org.sonar.server.computation.log.LogFileRef;
-import org.sonarqube.ws.WsCe;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class TaskFormatterTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Rule
-  public DbTester db = DbTester.create(System2.INSTANCE);
-
-  System2 system2 = mock(System2.class);
-  CeLogging ceLogging = mock(CeLogging.class, Mockito.RETURNS_DEEP_STUBS);
-  TaskFormatter underTest = new TaskFormatter(db.getDbClient(), ceLogging, system2);
-
-  @Test
-  public void formatQueue_without_component() {
-    CeQueueDto dto = new CeQueueDto();
-    dto.setUuid("UUID");
-    dto.setTaskType("TYPE");
-    dto.setStatus(CeQueueDto.Status.PENDING);
-    dto.setCreatedAt(1_450_000_000_000L);
-
-    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
-
-    assertThat(wsTask.getType()).isEqualTo("TYPE");
-    assertThat(wsTask.getId()).isEqualTo("UUID");
-    assertThat(wsTask.getStatus()).isEqualTo(WsCe.TaskStatus.PENDING);
-    assertThat(wsTask.getLogs()).isFalse();
-    assertThat(wsTask.getSubmittedAt()).isEqualTo(DateUtils.formatDateTime(new Date(1_450_000_000_000L)));
-
-    assertThat(wsTask.hasExecutionTimeMs()).isFalse();
-    assertThat(wsTask.hasSubmitterLogin()).isFalse();
-    assertThat(wsTask.hasComponentId()).isFalse();
-    assertThat(wsTask.hasComponentKey()).isFalse();
-    assertThat(wsTask.hasComponentName()).isFalse();
-    assertThat(wsTask.hasExecutedAt()).isFalse();
-    assertThat(wsTask.hasStartedAt()).isFalse();
-    assertThat(wsTask.hasExecutionTimeMs()).isFalse();
-  }
-
-  @Test
-  public void formatQueue_with_component_and_other_fields() throws IOException {
-    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.of(temp.newFile()));
-    db.getDbClient().componentDao().insert(db.getSession(), new ComponentDto()
-      .setUuid("COMPONENT_UUID").setKey("COMPONENT_KEY").setName("Component Name").setQualifier(Qualifiers.PROJECT));
-
-    CeQueueDto dto = new CeQueueDto();
-    dto.setUuid("UUID");
-    dto.setTaskType("TYPE");
-    dto.setStatus(CeQueueDto.Status.IN_PROGRESS);
-    dto.setCreatedAt(1_450_000_000_000L);
-    dto.setStartedAt(1_451_000_000_000L);
-    dto.setComponentUuid("COMPONENT_UUID");
-    dto.setSubmitterLogin("rob");
-
-    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
-
-    assertThat(wsTask.getType()).isEqualTo("TYPE");
-    assertThat(wsTask.getId()).isEqualTo("UUID");
-    assertThat(wsTask.getComponentId()).isEqualTo("COMPONENT_UUID");
-    assertThat(wsTask.getComponentKey()).isEqualTo("COMPONENT_KEY");
-    assertThat(wsTask.getComponentName()).isEqualTo("Component Name");
-    assertThat(wsTask.getComponentQualifier()).isEqualTo("TRK");
-    assertThat(wsTask.getStatus()).isEqualTo(WsCe.TaskStatus.IN_PROGRESS);
-    assertThat(wsTask.getLogs()).isTrue();
-    assertThat(wsTask.getSubmitterLogin()).isEqualTo("rob");
-    assertThat(wsTask.hasExecutionTimeMs()).isTrue();
-    assertThat(wsTask.hasExecutedAt()).isFalse();
-  }
-
-  @Test
-  public void formatQueue_do_not_fail_if_component_not_found() throws Exception {
-    CeQueueDto dto = new CeQueueDto();
-    dto.setUuid("UUID");
-    dto.setTaskType("TYPE");
-    dto.setStatus(CeQueueDto.Status.IN_PROGRESS);
-    dto.setCreatedAt(1_450_000_000_000L);
-    dto.setComponentUuid("DOES_NOT_EXIST");
-
-    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
-
-    assertThat(wsTask.getComponentId()).isEqualTo("DOES_NOT_EXIST");
-    assertThat(wsTask.hasComponentKey()).isFalse();
-    assertThat(wsTask.hasComponentName()).isFalse();
-  }
-
-  @Test
-  public void formatQueue_compute_execute_time_if_in_progress() {
-    long startedAt = 1_450_000_001_000L;
-    long now = 1_450_000_003_000L;
-    CeQueueDto dto = new CeQueueDto();
-    dto.setUuid("UUID");
-    dto.setTaskType("TYPE");
-    dto.setStatus(CeQueueDto.Status.IN_PROGRESS);
-    dto.setCreatedAt(1_450_000_000_000L);
-    dto.setStartedAt(startedAt);
-    when(system2.now()).thenReturn(now);
-
-    WsCe.Task wsTask = underTest.formatQueue(db.getSession(), dto);
-
-    assertThat(wsTask.getExecutionTimeMs()).isEqualTo(now-startedAt);
-  }
-
-  @Test
-  public void formatQueues() throws Exception {
-    CeQueueDto dto1 = new CeQueueDto();
-    dto1.setUuid("UUID1");
-    dto1.setTaskType("TYPE1");
-    dto1.setStatus(CeQueueDto.Status.IN_PROGRESS);
-    dto1.setCreatedAt(1_450_000_000_000L);
-
-    CeQueueDto dto2 = new CeQueueDto();
-    dto2.setUuid("UUID2");
-    dto2.setTaskType("TYPE2");
-    dto2.setStatus(CeQueueDto.Status.PENDING);
-    dto2.setCreatedAt(1_451_000_000_000L);
-
-    Iterable<WsCe.Task> wsTasks = underTest.formatQueue(db.getSession(), asList(dto1, dto2));
-    assertThat(wsTasks).extracting("id").containsExactly("UUID1", "UUID2");
-  }
-
-  @Test
-  public void formatActivity() {
-    CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
-
-    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto);
-
-    assertThat(wsTask.getType()).isEqualTo(CeTaskTypes.REPORT);
-    assertThat(wsTask.getId()).isEqualTo("UUID");
-    assertThat(wsTask.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
-    assertThat(wsTask.getLogs()).isFalse();
-    assertThat(wsTask.getSubmittedAt()).isEqualTo(DateUtils.formatDateTime(new Date(1_450_000_000_000L)));
-    assertThat(wsTask.getExecutionTimeMs()).isEqualTo(500L);
-    assertThat(wsTask.getAnalysisId()).isEqualTo("123456");
-    assertThat(wsTask.getLogs()).isFalse();
-  }
-
-  @Test
-  public void formatActivity_has_logs() throws IOException {
-    when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.of(temp.newFile()));
-    CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
-
-    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto);
-
-    assertThat(wsTask.getLogs()).isTrue();
-  }
-
-  @Test
-  public void formatActivities() {
-    CeActivityDto dto1 = newActivity("UUID1", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
-    CeActivityDto dto2 = newActivity("UUID2", "COMPONENT_UUID", CeActivityDto.Status.SUCCESS);
-
-    Iterable<WsCe.Task> wsTasks = underTest.formatActivity(db.getSession(), asList(dto1, dto2));
-
-    assertThat(wsTasks).extracting("id").containsExactly("UUID1", "UUID2");
-  }
-
-  private CeActivityDto newActivity(String taskUuid, String componentUuid, CeActivityDto.Status status) {
-    CeQueueDto queueDto = new CeQueueDto();
-    queueDto.setCreatedAt(1_450_000_000_000L);
-    queueDto.setTaskType(CeTaskTypes.REPORT);
-    queueDto.setComponentUuid(componentUuid);
-    queueDto.setUuid(taskUuid);
-    CeActivityDto activityDto = new CeActivityDto(queueDto);
-    activityDto.setStatus(status);
-    activityDto.setExecutionTimeMs(500L);
-    activityDto.setSnapshotId(123_456L);
-    return activityDto;
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskTypesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskTypesActionTest.java
deleted file mode 100644 (file)
index 1706293..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.computation.ws;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Set;
-import org.junit.Test;
-import org.sonar.server.computation.queue.CeTask;
-import org.sonar.server.computation.queue.CeTaskResult;
-import org.sonar.server.computation.taskprocessor.CeTaskProcessor;
-import org.sonar.server.ws.WsActionTester;
-
-import static org.sonar.test.JsonAssert.assertJson;
-
-public class TaskTypesActionTest {
-
-  WsActionTester ws = new WsActionTester(new TaskTypesAction(new CeTaskProcessor[] {
-    new FakeCeTaskProcessor("REPORT"),
-    new FakeCeTaskProcessor("DEV_REFRESH", "DEV_PURGE"),
-    new FakeCeTaskProcessor("VIEW_REFRESH")
-  }));
-
-  @Test
-  public void json_example() {
-    String response = ws.newRequest().execute().getInput();
-
-    assertJson(response).isSimilarTo(getClass().getResource("task_types-example.json"));
-  }
-
-  private static class FakeCeTaskProcessor implements CeTaskProcessor {
-    private final Set<String> taskTypes;
-
-    private FakeCeTaskProcessor(String... taskTypes) {
-      this.taskTypes = ImmutableSet.copyOf(taskTypes);
-    }
-
-    @Override
-    public Set<String> getHandledCeTaskTypes() {
-      return taskTypes;
-    }
-
-    @Override
-    public CeTaskResult process(CeTask task) {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-}