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;
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;
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;
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
+ 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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!");
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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();
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * 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;
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;
/**
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+
*/
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
DefaultPeriodCleaner.class,
ProjectCleaner.class,
- ProjectSettingsFactory.class,
IndexPurgeListener.class);
}
}
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 {
/**
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}.
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 {
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 {
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;
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;
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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;
+++ /dev/null
-/*
- * 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();
-}
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;
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 {
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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;
+++ /dev/null
-/*
- * 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();
-}
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.
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;
+++ /dev/null
-/*
- * 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();
- }
- }
-}
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;
/**
+++ /dev/null
-/*
- * 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);
-
-}
*/
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,
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
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 {
*/
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 {
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-}
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;
/**
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;
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 {
+++ /dev/null
-/*
- * 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);
-}
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 {
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;
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}.
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;
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;
*/
package org.sonar.server.computation.taskprocessor;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
public interface MutableTaskResultHolder extends TaskResultHolder {
/**
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;
*/
package org.sonar.server.computation.taskprocessor;
-import org.sonar.server.computation.queue.CeTaskResult;
+import org.sonar.ce.queue.CeTaskResult;
public interface TaskResultHolder {
/**
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;
+++ /dev/null
-/*
- * 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;
- }
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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();
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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;
-
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;
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;
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;
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;
// Compute engine (must be after Views and Developer Cockpit)
CeModule.class,
- CeQueueModule.class,
- CeTaskProcessorModule.class,
CeWsModule.class,
- ReportProcessingModule.class,
+
+ ProjectSettingsFactory.class,
// UI
GlobalNavigationAction.class,
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;
RegisterIssueFilters.class,
RenameIssueWidgets.class,
ServerLifecycleNotifier.class,
- PurgeCeActivities.class,
DisplayLogOnDeprecatedProjects.class,
ClearRulesOverloadedDebt.class,
FeedUsersLocalStartupTask.class
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;
--- /dev/null
+{
+ "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
+ }
+ ]
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+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
--- /dev/null
+{
+ "taskId": "TASK_1",
+ "projectId": "PROJECT_1"
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "taskTypes": [
+ "REPORT",
+ "DEV_REFRESH",
+ "DEV_PURGE",
+ "VIEW_REFRESH"
+ ]
+}
+++ /dev/null
-{
- "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
- }
- ]
-}
+++ /dev/null
-{
- "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
- }
-}
+++ /dev/null
-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
+++ /dev/null
-{
- "taskId": "TASK_1",
- "projectId": "PROJECT_1"
-}
+++ /dev/null
-{
- "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
- }
-}
+++ /dev/null
-{
- "taskTypes": [
- "REPORT",
- "DEV_REFRESH",
- "DEV_PURGE",
- "VIEW_REFRESH"
- ]
-}
--- /dev/null
+/*
+ * 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"));
+
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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}"));
+ }
+
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
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;
/**
* 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 {
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 */);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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));
+
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+
+}
+++ /dev/null
-/*
- * 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();
- }
-}
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;
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;
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;
+++ /dev/null
-/*
- * 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"));
-
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
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;
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;
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
+++ /dev/null
-/*
- * 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;
- }
-}
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;
+++ /dev/null
-/*
- * 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());
- }
-}
--- /dev/null
+/*
+ * 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;
+ }
+}
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;
+++ /dev/null
-/*
- * 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}"));
- }
-
-}
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;
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;
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;
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;
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;
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;
@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);
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;
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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 */);
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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));
-
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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();
- }
- }
-
-}