.hasSize(
CONTAINER_ITSELF
+ 75 // level 4
- + 7 // content of CeModule
+ + 6 // content of CeModule
+ 7 // content of CeQueueModule
- + 4 // content of ProjectAnalysisTaskModule
+ + 3 // content of ProjectAnalysisTaskModule
+ 4 // content of CeTaskProcessorModule
);
assertThat(picoContainer.getParent().getComponentAdapters()).hasSize(
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 26 // level 1
- + 46 // content of DaoModule
+ + 47 // content of DaoModule
+ 2 // content of EsSearchModule
+ 55 // content of CorePropertyDefinitions
+ 1 // content of CePropertyDefinitions
import org.sonar.ce.log.CeLogging;
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;
+import org.sonar.server.computation.queue.ReportSubmitter;
public class CeModule extends Module {
@Override
// Queue
CeQueueImpl.class,
ReportSubmitter.class,
- ReportFiles.class,
-
+
// Core tasks processors
ReportTaskProcessorDeclaration.class);
}
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.util.Collections.singletonList;
import static org.sonar.db.component.ComponentDtoFunctions.toUuid;
@ComputeEngineSide
private final DbClient dbClient;
private final UuidFactory uuidFactory;
- private final CeQueueListener[] listeners;
// state
private AtomicBoolean submitPaused = new AtomicBoolean(false);
- /**
- * Constructor in case there is no CeQueueListener
- */
public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory) {
- this(dbClient, uuidFactory, new CeQueueListener[] {});
- }
-
- public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory, CeQueueListener[] listeners) {
this.dbClient = dbClient;
this.uuidFactory = uuidFactory;
- this.listeners = listeners;
}
@Override
.toSet();
Map<String, ComponentDto> componentDtoByUuid = from(dbClient.componentDao()
.selectByUuids(dbSession, componentUuids))
- .uniqueIndex(toUuid());
+ .uniqueIndex(toUuid());
return from(dtos)
.transform(new CeQueueDtoToCeTask(componentDtoByUuid))
}
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);
+ remove(dbSession, q, activityDto);
}
@Override
}
}
- protected void remove(DbSession dbSession, CeTask task, CeQueueDto queueDto, CeActivityDto activityDto) {
+ protected void remove(DbSession dbSession, CeQueueDto queueDto, CeActivityDto activityDto) {
dbClient.ceActivityDao().insert(dbSession, activityDto);
dbClient.ceQueueDao().deleteByUuid(dbSession, queueDto.getUuid());
+ dbClient.ceTaskDataDao().deleteByUuids(dbSession, singletonList(queueDto.getUuid()));
dbSession.commit();
- for (CeQueueListener listener : listeners) {
- listener.onRemoved(task, activityDto.getStatus());
- }
}
@Override
+++ /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.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.ce.ComputeEngineSide;
-import org.sonar.process.ProcessProperties;
-
-import static java.lang.String.format;
-
-@ComputeEngineSide
-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.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.ce.queue.CeQueue;
-import org.sonar.ce.queue.CeTask;
-import org.sonar.ce.queue.CeTaskSubmit;
-import org.sonar.core.component.ComponentKeys;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-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.permission.PermissionService;
-import org.sonar.server.user.UserSession;
-
-import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
-import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
-
-@ComputeEngineSide
-public class ReportSubmitter {
-
- private final CeQueue queue;
- private final UserSession userSession;
- private final ReportFiles reportFiles;
- private final ComponentService componentService;
- private final PermissionService permissionService;
- private final DbClient dbClient;
-
- public ReportSubmitter(CeQueue queue, UserSession userSession, ReportFiles reportFiles,
- ComponentService componentService, PermissionService permissionService, DbClient dbClient) {
- this.queue = queue;
- this.userSession = userSession;
- this.reportFiles = reportFiles;
- this.componentService = componentService;
- this.permissionService = permissionService;
- this.dbClient = dbClient;
- }
-
- 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) {
- project = createProject(projectKey, projectBranch, projectName);
- }
-
- userSession.checkComponentPermission(SCAN_EXECUTION, projectKey);
-
- return submitReport(reportInput, project);
- }
-
- @CheckForNull
- private ComponentDto createProject(String projectKey, @Nullable String projectBranch, @Nullable String projectName) {
- DbSession dbSession = dbClient.openSession(false);
- try {
- boolean wouldCurrentUserHaveScanPermission = permissionService.wouldCurrentUserHavePermissionWithDefaultTemplate(dbSession, SCAN_EXECUTION, projectBranch, projectKey,
- Qualifiers.PROJECT);
- if (!wouldCurrentUserHaveScanPermission) {
- throw insufficientPrivilegesException();
- }
-
- NewComponent newProject = new NewComponent(projectKey, StringUtils.defaultIfBlank(projectName, projectKey));
- newProject.setBranch(projectBranch);
- newProject.setQualifier(Qualifiers.PROJECT);
- // "provisioning" permission is check in ComponentService
- ComponentDto project = componentService.create(dbSession, newProject);
- permissionService.applyDefaultPermissionTemplate(dbSession, project.getKey());
- return project;
- } finally {
- dbClient.closeSession(dbSession);
- }
- }
-
- private CeTask submitReport(InputStream reportInput, ComponentDto project) {
- // 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;
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.computation.queue.ReportSubmitter;
import org.sonar.server.ws.WsUtils;
import org.sonarqube.ws.WsCe;
*/
package org.sonar.server.computation;
-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.CeTasksMBeanImpl;
// queue cleaning
CeQueueCleaner.class,
- ReportFiles.class,
-
+
// init queue state and queue processing
CeQueueInitializer.class);
}
*/
package org.sonar.server.computation.queue;
-import java.util.HashSet;
-import java.util.Set;
-import org.sonar.api.platform.ServerUpgradeStatus;
+import java.util.List;
import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.platform.ServerUpgradeStatus;
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;
/**
* 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 InternalCeQueue queue;
- public CeQueueCleaner(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, ReportFiles reportFiles, InternalCeQueue queue) {
+ public CeQueueCleaner(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, InternalCeQueue queue) {
this.dbClient = dbClient;
this.serverUpgradeStatus = serverUpgradeStatus;
- this.reportFiles = reportFiles;
this.queue = queue;
}
dbClient.ceQueueDao().resetAllToPendingStatus(dbSession);
dbSession.commit();
- // verify that the report files are available for the tasks in queue
- Set<String> uuidsInQueue = new HashSet<>();
- for (CeQueueDto queueDto : dbClient.ceQueueDao().selectAllInAscOrder(dbSession)) {
- uuidsInQueue.add(queueDto.getUuid());
- if (CeTaskTypes.REPORT.equals(queueDto.getTaskType()) && !reportFiles.fileForUuid(queueDto.getUuid()).exists()) {
- // the report is not available on file system
- queue.cancel(dbSession, queueDto);
- }
- }
-
- // clean-up filesystem
- for (String uuid : reportFiles.listUuids()) {
- if (!uuidsInQueue.contains(uuid)) {
- reportFiles.deleteIfExists(uuid);
- }
- }
+ // Reports that have been processed are not kept in database yet.
+ // They are supposed to be systematically dropped.
+ // Let's clean-up orphans if any.
+ List<String> uuids = dbClient.ceTaskDataDao().selectUuidsNotInQueue(dbSession);
+ dbClient.ceTaskDataDao().deleteByUuids(dbSession, uuids);
+ dbSession.commit();
}
}
import org.sonar.api.utils.System2;
import org.sonar.ce.monitoring.CEQueueStatus;
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;
private AtomicBoolean peekPaused = new AtomicBoolean(false);
public InternalCeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory,
- CEQueueStatus queueStatus, CeQueueListener[] listeners) {
- super(dbClient, uuidFactory, listeners);
+ CEQueueStatus queueStatus) {
+ super(dbClient, uuidFactory);
this.system2 = system2;
this.dbClient = dbClient;
this.queueStatus = queueStatus;
activityDto.setStatus(status);
updateQueueStatus(status, activityDto);
updateTaskResult(activityDto, taskResult);
- remove(dbSession, task, queueDto.get(), activityDto);
+ remove(dbSession, queueDto.get(), activityDto);
} 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.queue;
+
+import java.io.InputStream;
+import javax.annotation.CheckForNull;
+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.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.ce.queue.CeTaskSubmit;
+import org.sonar.core.component.ComponentKeys;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+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.permission.PermissionService;
+import org.sonar.server.user.UserSession;
+
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
+
+@ServerSide
+public class ReportSubmitter {
+
+ private final CeQueue queue;
+ private final UserSession userSession;
+ private final ComponentService componentService;
+ private final PermissionService permissionService;
+ private final DbClient dbClient;
+
+ public ReportSubmitter(CeQueue queue, UserSession userSession,
+ ComponentService componentService, PermissionService permissionService, DbClient dbClient) {
+ this.queue = queue;
+ this.userSession = userSession;
+ this.componentService = componentService;
+ this.permissionService = permissionService;
+ this.dbClient = dbClient;
+ }
+
+ 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) {
+ project = createProject(projectKey, projectBranch, projectName);
+ }
+
+ userSession.checkComponentPermission(SCAN_EXECUTION, projectKey);
+
+ return submitReport(reportInput, project);
+ }
+
+ @CheckForNull
+ private ComponentDto createProject(String projectKey, @Nullable String projectBranch, @Nullable String projectName) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ boolean wouldCurrentUserHaveScanPermission = permissionService.wouldCurrentUserHavePermissionWithDefaultTemplate(dbSession, SCAN_EXECUTION, projectBranch, projectKey,
+ Qualifiers.PROJECT);
+ if (!wouldCurrentUserHaveScanPermission) {
+ throw insufficientPrivilegesException();
+ }
+
+ NewComponent newProject = new NewComponent(projectKey, StringUtils.defaultIfBlank(projectName, projectKey));
+ newProject.setBranch(projectBranch);
+ newProject.setQualifier(Qualifiers.PROJECT);
+ // "provisioning" permission is check in ComponentService
+ ComponentDto project = componentService.create(dbSession, newProject);
+ permissionService.applyDefaultPermissionTemplate(dbSession, project.getKey());
+ return project;
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+ private CeTask submitReport(InputStream reportInput, ComponentDto project) {
+ // the report file must be saved before submitting the task
+ CeTaskSubmit.Builder submit = queue.prepareSubmit();
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ dbClient.ceTaskDataDao().insert(dbSession, submit.getUuid(), reportInput);
+ dbSession.commit();
+ }
+
+ submit.setType(CeTaskTypes.REPORT);
+ submit.setComponentUuid(project.uuid());
+ submit.setSubmitterLogin(userSession.getLogin());
+ return queue.submit(submit.build());
+ }
+}
*/
package org.sonar.server.computation.task.projectanalysis;
-import org.sonar.ce.queue.report.ReportSubmitter;
+import org.sonar.server.computation.queue.ReportSubmitter;
import org.sonar.core.platform.Module;
import org.sonar.server.computation.task.projectanalysis.container.ContainerFactoryImpl;
-import org.sonar.server.computation.task.projectanalysis.queue.CleanReportQueueListener;
import org.sonar.server.computation.task.projectanalysis.taskprocessor.ReportTaskProcessor;
import org.sonar.server.computation.task.step.ComputationStepExecutor;
@Override
protected void configureModule() {
add(
- // queue
- CleanReportQueueListener.class,
-
// task
ContainerFactoryImpl.class,
ComputationStepExecutor.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.task.projectanalysis.queue;
-
-import org.sonar.ce.queue.report.ReportFiles;
-import org.sonar.db.ce.CeActivityDto;
-import org.sonar.ce.queue.CeQueueListener;
-import org.sonar.ce.queue.CeTask;
-
-public class CleanReportQueueListener implements CeQueueListener {
-
- private final ReportFiles reportFiles;
-
- public CleanReportQueueListener(ReportFiles reportFiles) {
- this.reportFiles = reportFiles;
- }
-
- @Override
- public void onRemoved(CeTask task, CeActivityDto.Status status) {
- reportFiles.deleteIfExists(task.getUuid());
- }
-}
+++ /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.task.projectanalysis.queue;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import java.io.File;
import java.io.IOException;
-import org.apache.commons.io.FileUtils;
+import java.util.Optional;
+import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.ZipUtils;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.queue.CeTask;
-import org.sonar.ce.queue.report.ReportFiles;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeTaskDataDao;
import org.sonar.server.computation.task.projectanalysis.batch.MutableBatchReportDirectoryHolder;
import org.sonar.server.computation.task.step.ComputationStep;
public class ExtractReportStep implements ComputationStep {
private static final Logger LOG = Loggers.get(ExtractReportStep.class);
- private final ReportFiles reportFiles;
+ private final DbClient dbClient;
private final CeTask task;
private final TempFolder tempFolder;
private final MutableBatchReportDirectoryHolder reportDirectoryHolder;
- public ExtractReportStep(ReportFiles reportFiles, CeTask task, TempFolder tempFolder,
+ public ExtractReportStep(DbClient dbClient, CeTask task, TempFolder tempFolder,
MutableBatchReportDirectoryHolder reportDirectoryHolder) {
- this.reportFiles = reportFiles;
+ this.dbClient = dbClient;
this.task = task;
this.tempFolder = tempFolder;
this.reportDirectoryHolder = reportDirectoryHolder;
@Override
public void execute() {
- File dir = tempFolder.newDir();
- File zip = reportFiles.fileForUuid(task.getUuid());
- try {
- ZipUtils.unzip(zip, dir);
- reportDirectoryHolder.setDirectory(dir);
- LOG.info("Analysis report extracted | compressedSize={}", FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(zip)));
- } catch (IOException e) {
- throw new IllegalStateException(String.format("Fail to unzip %s into %s", zip, dir), e);
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ Optional<CeTaskDataDao.DataStream> opt = dbClient.ceTaskDataDao().selectData(dbSession, task.getUuid());
+ if (opt.isPresent()) {
+ File unzippedDir = tempFolder.newDir();
+ try (CeTaskDataDao.DataStream reportStream = opt.get()) {
+ ZipUtils.unzip(reportStream.getInputStream(), unzippedDir);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to extract report " + task.getUuid() + " from database", e);
+ }
+ reportDirectoryHolder.setDirectory(unzippedDir);
+ LOG.info("Analysis report extracted");
+ } else {
+ throw MessageException.of("Analysis report " + task.getUuid() + " is missing in database");
+ }
}
}
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;
public class CeQueueImplTest {
DbSession session = dbTester.getSession();
UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
- CeQueueListener listener = mock(CeQueueListener.class);
- CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory, new CeQueueListener[] {listener});
+ CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory);
@Test
public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
// 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
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
+++ /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.api.resources.Qualifiers;
-import org.sonar.ce.queue.CeQueue;
-import org.sonar.ce.queue.CeQueueImpl;
-import org.sonar.ce.queue.CeTaskSubmit;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-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.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.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
-import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
-
-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);
- DbClient dbClient = mock(DbClient.class);
- ReportSubmitter underTest = new ReportSubmitter(queue, userSession, reportFiles, componentService, permissionService, dbClient);
-
- @Test
- public void submit_a_report_on_existing_project() {
- userSession.setGlobalPermissions(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(SCAN_EXECUTION, PROVISIONING);
-
- when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
- when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
- when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
- when(permissionService.wouldCurrentUserHavePermissionWithDefaultTemplate(any(DbSession.class), eq(SCAN_EXECUTION), anyString(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT)))
- .thenReturn(true);
-
- underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
-
- verify(permissionService).applyDefaultPermissionTemplate(any(DbSession.class), eq(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(SCAN_EXECUTION, PROVISIONING);
-
- when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
- when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
- when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
- when(permissionService.wouldCurrentUserHavePermissionWithDefaultTemplate(any(DbSession.class), eq(SCAN_EXECUTION), anyString(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT)))
- .thenReturn(true);
-
- 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(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(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(SCAN_EXECUTION, PROJECT_KEY);
-
- when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
- when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
- when(componentService.create(any(DbSession.class), 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.junit.Test;
import org.mockito.Mockito;
import org.sonar.api.server.ws.WebService;
-import org.sonar.ce.queue.report.ReportSubmitter;
+import org.sonar.server.computation.queue.ReportSubmitter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
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.sonar.server.computation.queue.ReportSubmitter;
import org.sonarqube.ws.MediaTypes;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
+++ /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 java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-import org.h2.util.IOUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.Settings;
-import org.sonar.process.ProcessProperties;
-import org.sonar.ce.queue.report.ReportFiles;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ReportFilesTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- File reportDir;
- Settings settings = new Settings();
- ReportFiles underTest = new ReportFiles(settings);
-
- @Before
- public void setUp() throws IOException {
- File dataDir = temp.newFolder();
- reportDir = new File(dataDir, "ce/reports");
- settings.setProperty(ProcessProperties.PATH_DATA, dataDir.getCanonicalPath());
- }
-
- @Test
- public void save_report() throws IOException {
- underTest.save("TASK_1", IOUtils.getInputStreamFromString("{binary}"));
-
- assertThat(FileUtils.readFileToString(new File(reportDir, "TASK_1.zip"))).isEqualTo("{binary}");
-
- }
-
- @Test
- public void deleteIfExists_uuid_does_not_exist() {
- // do not fail, does nothing
- underTest.deleteIfExists("TASK_1");
- }
-
- @Test
- public void deleteIfExists() throws IOException {
- File report = new File(reportDir, "TASK_1.zip");
- FileUtils.touch(report);
- assertThat(report).exists();
-
- underTest.deleteIfExists("TASK_1");
- assertThat(report).doesNotExist();
- }
-
- /**
- * List the zip files contained in the report directory
- */
- @Test
- public void listUuids() throws IOException {
- FileUtils.touch(new File(reportDir, "TASK_1.zip"));
- FileUtils.touch(new File(reportDir, "TASK_2.zip"));
- FileUtils.touch(new File(reportDir, "something.else"));
-
- assertThat(underTest.listUuids()).containsOnly("TASK_1", "TASK_2");
- }
-
- @Test
- public void listUuids_dir_does_not_exist_yet() throws IOException {
- FileUtils.deleteQuietly(reportDir);
-
- assertThat(underTest.listUuids()).isEmpty();
- }
-
- @Test
- public void deleteAll() throws IOException {
- FileUtils.touch(new File(reportDir, "TASK_1.zip"));
- FileUtils.touch(new File(reportDir, "TASK_2.zip"));
- FileUtils.touch(new File(reportDir, "something.else"));
-
- underTest.deleteAll();
-
- // directory still exists but is empty
- assertThat(reportDir).exists().isDirectory();
- assertThat(reportDir.listFiles()).isEmpty();
- }
-
- @Test
- public void deleteAll_dir_does_not_exist_yet() throws IOException {
- FileUtils.deleteQuietly(reportDir);
-
- underTest.deleteAll();
-
- assertThat(reportDir).doesNotExist();
- }
-}
*/
package org.sonar.server.computation.queue;
-import java.io.File;
import java.io.IOException;
+import java.util.Optional;
+import org.apache.commons.io.IOUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.mockito.Mockito;
import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.utils.System2;
-import org.sonar.ce.queue.report.ReportFiles;
-import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskDataDao;
import org.sonar.db.ce.CeTaskTypes;
-import static java.util.Arrays.asList;
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;
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
- ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class);
- ReportFiles reportFiles = mock(ReportFiles.class, Mockito.RETURNS_DEEP_STUBS);
- InternalCeQueue queue = mock(InternalCeQueue.class);
- CeQueueCleaner underTest = new CeQueueCleaner(dbTester.getDbClient(), serverUpgradeStatus, reportFiles, queue);
+ private ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class);
+ private InternalCeQueue queue = mock(InternalCeQueue.class);
+ private CeQueueCleaner underTest = new CeQueueCleaner(dbTester.getDbClient(), serverUpgradeStatus, queue);
@Test
public void reset_in_progress_tasks_to_pending() throws IOException {
verify(queue).clear();
}
- @Test
- public void cancel_task_if_report_file_is_missing() throws IOException {
- CeQueueDto task = insertInQueue("TASK_1", CeQueueDto.Status.PENDING, false);
-
- underTest.clean(dbTester.getSession());
-
- verify(queue).cancel(any(DbSession.class), eq(task));
- }
-
@Test
public void delete_orphan_report_files() throws Exception {
- // two files on disk but on task in queue
- insertInQueue("TASK_1", CeQueueDto.Status.PENDING, true);
- when(reportFiles.listUuids()).thenReturn(asList("TASK_1", "TASK_2"));
+ // analysis reports are persisted but the associated
+ // task is not in the queue
+ insertInQueue("TASK_1", CeQueueDto.Status.PENDING);
+ insertTaskData("TASK_1");
+ insertTaskData("TASK_2");
underTest.clean(dbTester.getSession());
- verify(reportFiles).deleteIfExists("TASK_2");
- }
+ CeTaskDataDao dataDao = dbTester.getDbClient().ceTaskDataDao();
+ Optional<CeTaskDataDao.DataStream> task1Data = dataDao.selectData(dbTester.getSession(), "TASK_1");
+ assertThat(task1Data).isPresent();
+ task1Data.get().close();
- private void insertInQueue(String taskUuid, CeQueueDto.Status status) throws IOException {
- insertInQueue(taskUuid, status, true);
+ assertThat(dataDao.selectData(dbTester.getSession(), "TASK_2")).isNotPresent();
}
- private CeQueueDto insertInQueue(String taskUuid, CeQueueDto.Status status, boolean createFile) throws IOException {
- CeQueueDto queueDto = new CeQueueDto();
- queueDto.setTaskType(CeTaskTypes.REPORT);
- queueDto.setComponentUuid("PROJECT_1");
- queueDto.setUuid(taskUuid);
- queueDto.setStatus(status);
- dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+ private CeQueueDto insertInQueue(String taskUuid, CeQueueDto.Status status) throws IOException {
+ CeQueueDto dto = new CeQueueDto();
+ dto.setTaskType(CeTaskTypes.REPORT);
+ dto.setComponentUuid("PROJECT_1");
+ dto.setUuid(taskUuid);
+ dto.setStatus(status);
+ dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), dto);
dbTester.getSession().commit();
+ return dto;
+ }
- File file = tempFolder.newFile();
- when(reportFiles.fileForUuid(taskUuid)).thenReturn(file);
- if (!createFile) {
- file.delete();
- }
- return queueDto;
+ private void insertTaskData(String taskUuid) throws IOException {
+ dbTester.getDbClient().ceTaskDataDao().insert(dbTester.getSession(), taskUuid, IOUtils.toInputStream("{binary}"));
+ dbTester.getSession().commit();
}
}
import org.sonar.api.utils.System2;
import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.ce.monitoring.CEQueueStatus;
-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 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 {
UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
CEQueueStatus queueStatus = new CEQueueStatusImpl(dbTester.getDbClient());
- CeQueueListener listener = mock(CeQueueListener.class);
- InternalCeQueue underTest = new InternalCeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
+ InternalCeQueue underTest = new InternalCeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus);
@Test
public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
assertThat(history.get().getIsLast()).isTrue();
assertThat(history.get().getAnalysisUuid()).isNull();
-
- verify(listener).onRemoved(task, CeActivityDto.Status.SUCCESS);
}
@Test
// no more pending tasks
peek = underTest.peek();
assertThat(peek.isPresent()).isFalse();
-
- verify(listener, never()).onRemoved(eq(task), any(CeActivityDto.Status.class));
}
@Test
// 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
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
--- /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.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.api.resources.Qualifiers;
+import org.sonar.api.utils.System2;
+import org.sonar.ce.queue.CeQueue;
+import org.sonar.ce.queue.CeQueueImpl;
+import org.sonar.ce.queue.CeTaskSubmit;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+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.exceptions.ForbiddenException;
+import org.sonar.server.permission.PermissionService;
+import org.sonar.server.tester.UserSessionRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+
+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();
+
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+ private CeQueue queue = mock(CeQueueImpl.class);
+ private ComponentService componentService = mock(ComponentService.class);
+ private PermissionService permissionService = mock(PermissionService.class);
+ private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentService, permissionService, dbTester.getDbClient());
+
+ @Test
+ public void submit_a_report_on_existing_project() {
+ userSession.setGlobalPermissions(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}"));
+
+ verifyReportIsPersisted(TASK_UUID);
+ 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(SCAN_EXECUTION, PROVISIONING);
+
+ when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+ when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
+ when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
+ when(permissionService.wouldCurrentUserHavePermissionWithDefaultTemplate(any(DbSession.class), eq(SCAN_EXECUTION), anyString(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT)))
+ .thenReturn(true);
+
+ underTest.submit(PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}"));
+
+ verifyReportIsPersisted(TASK_UUID);
+ verify(permissionService).applyDefaultPermissionTemplate(any(DbSession.class), eq(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(SCAN_EXECUTION, PROVISIONING);
+
+ when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+ when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
+ when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
+ when(permissionService.wouldCurrentUserHavePermissionWithDefaultTemplate(any(DbSession.class), eq(SCAN_EXECUTION), anyString(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT)))
+ .thenReturn(true);
+
+ 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(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(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(SCAN_EXECUTION, PROJECT_KEY);
+
+ when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
+ when(componentService.getNullableByKey(PROJECT_KEY)).thenReturn(null);
+ when(componentService.create(any(DbSession.class), 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}"));
+ }
+
+ private void verifyReportIsPersisted(String taskUuid) {
+ assertThat(dbTester.selectFirst("select task_uuid from ce_task_data where task_uuid='" + taskUuid + "'")).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.task.projectanalysis.queue;
-
-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 static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class CleanReportQueueListenerTest {
-
- ReportFiles reportFiles = mock(ReportFiles.class);
- CleanReportQueueListener underTest = new CleanReportQueueListener(reportFiles);
-
- @Test
- public void remove_report_file_if_success() {
- CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin(null).build();
-
- underTest.onRemoved(task, CeActivityDto.Status.SUCCESS);
- verify(reportFiles).deleteIfExists("TASK_1");
- }
-
- @Test
- public void remove_report_file_if_failure() {
- CeTask task = new CeTask.Builder().setUuid("TASK_1").setType(CeTaskTypes.REPORT).setComponentUuid("PROJECT_1").setSubmitterLogin(null).build();
-
- underTest.onRemoved(task, CeActivityDto.Status.FAILED);
- verify(reportFiles).deleteIfExists("TASK_1");
- }
-}
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import org.apache.commons.io.FileUtils;
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.System2;
import org.sonar.api.utils.ZipUtils;
import org.sonar.api.utils.internal.JUnitTempFolder;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.ce.queue.CeTask;
+import org.sonar.db.DbTester;
import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.server.computation.task.projectanalysis.batch.BatchReportDirectoryHolderImpl;
import org.sonar.server.computation.task.projectanalysis.batch.MutableBatchReportDirectoryHolder;
-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 static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.assertj.core.api.Assertions.assertThat;
public class ExtractReportStepTest {
- public static final String TASK_UUID = "1";
+ private static final String TASK_UUID = "1";
+
@Rule
public JUnitTempFolder tempFolder = new JUnitTempFolder();
@Rule
public ExpectedException expectedException = ExpectedException.none();
- MutableBatchReportDirectoryHolder reportDirectoryHolder = mock(MutableBatchReportDirectoryHolder.class);
- ReportFiles reportFiles = mock(ReportFiles.class);
- CeTask ceTask = new CeTask.Builder().setType(CeTaskTypes.REPORT).setUuid(TASK_UUID).build();
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+ private MutableBatchReportDirectoryHolder reportDirectoryHolder = new BatchReportDirectoryHolderImpl();
+ private CeTask ceTask = new CeTask.Builder().setType(CeTaskTypes.REPORT).setUuid(TASK_UUID).build();
- ExtractReportStep underTest = new ExtractReportStep(reportFiles, ceTask, tempFolder, reportDirectoryHolder);
+ private ExtractReportStep underTest = new ExtractReportStep(dbTester.getDbClient(), ceTask, tempFolder, reportDirectoryHolder);
@Test
public void fail_if_report_zip_does_not_exist() throws Exception {
- File zip = tempFolder.newFile();
- FileUtils.forceDelete(zip);
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Fail to unzip " + zip.getPath());
-
- when(reportFiles.fileForUuid(TASK_UUID)).thenReturn(zip);
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("Analysis report 1 is missing in database");
underTest.execute();
}
@Test
public void unzip_report() throws Exception {
- File zipDir = tempFolder.newDir();
- final File metadataFile = new File(zipDir, "metadata.pb");
- FileUtils.write(metadataFile, "{report}");
- File zip = tempFolder.newFile();
- ZipUtils.zipDir(zipDir, zip);
- when(reportFiles.fileForUuid(TASK_UUID)).thenReturn(zip);
+ File reportFile = generateReport();
+ try (InputStream input = FileUtils.openInputStream(reportFile)) {
+ dbTester.getDbClient().ceTaskDataDao().insert(dbTester.getSession(), TASK_UUID, input);
+ }
+ dbTester.getSession().commit();
+ dbTester.getSession().close();
underTest.execute();
- verify(reportDirectoryHolder).setDirectory(argThat(new TypeSafeMatcher<File>() {
- @Override
- protected boolean matchesSafely(File dir) {
- try {
- return dir.isDirectory() && dir.exists() &&
- // directory contains the uncompressed report (which contains only metadata.pb in this test)
- dir.listFiles().length == 1 &&
- FileUtils.contentEquals(dir.listFiles()[0], metadataFile);
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void describeTo(Description description) {
-
- }
- }));
+ // directory contains the uncompressed report (which contains only metadata.pb in this test)
+ File unzippedDir = reportDirectoryHolder.getDirectory();
+ assertThat(unzippedDir).isDirectory().exists();
+ assertThat(unzippedDir.listFiles()).hasSize(1);
+ assertThat(new File(unzippedDir, "metadata.pb")).hasContent("{metadata}");
+ }
+
+ private File generateReport() throws IOException {
+ File zipDir = tempFolder.newDir();
+ File metadataFile = new File(zipDir, "metadata.pb");
+ FileUtils.write(metadataFile, "{metadata}");
+ File zip = tempFolder.newFile();
+ ZipUtils.zipDir(zipDir, zip);
+ return zip;
}
}
--- /dev/null
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+#
+# SonarQube 6.1
+#
+class CreateTableCeTaskData < ActiveRecord::Migration
+
+ def self.up
+ # FIXME define primary key
+ create_table 'ce_task_data', :id => false do |t|
+ t.column 'task_uuid', :string, :limit => 40, :null => false
+ t.column 'data', :binary, :null => true
+ t.column 'created_at', :big_integer, :null => false
+ t.column 'updated_at', :big_integer, :null => false
+ end
+ add_index 'ce_task_data', 'task_uuid', :name => 'ce_task_data_uuid', :unique => true
+ end
+end
import org.sonar.db.activity.ActivityDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
+import org.sonar.db.ce.CeTaskDataDao;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentLinkDao;
import org.sonar.db.component.ResourceDao;
AuthorizationDao.class,
CeActivityDao.class,
CeQueueDao.class,
+ CeTaskDataDao.class,
ComponentDao.class,
ComponentLinkDao.class,
CustomMeasureDao.class,
import org.sonar.db.activity.ActivityDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
+import org.sonar.db.ce.CeTaskDataDao;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentLinkDao;
import org.sonar.db.component.ResourceDao;
private final IssueFilterDao issueFilterDao;
private final IssueFilterFavouriteDao issueFilterFavouriteDao;
private final IssueChangeDao issueChangeDao;
- private final CeQueueDao ceQueueDao;
private final CeActivityDao ceActivityDao;
+ private final CeQueueDao ceQueueDao;
+ private final CeTaskDataDao ceTaskDataDao;
private final DashboardDao dashboardDao;
private final ActiveDashboardDao activeDashboardDao;
private final WidgetDao widgetDao;
issueFilterDao = getDao(map, IssueFilterDao.class);
issueFilterFavouriteDao = getDao(map, IssueFilterFavouriteDao.class);
issueChangeDao = getDao(map, IssueChangeDao.class);
- ceQueueDao = getDao(map, CeQueueDao.class);
ceActivityDao = getDao(map, CeActivityDao.class);
+ ceQueueDao = getDao(map, CeQueueDao.class);
+ ceTaskDataDao = getDao(map, CeTaskDataDao.class);
dashboardDao = getDao(map, DashboardDao.class);
activeDashboardDao = getDao(map, ActiveDashboardDao.class);
widgetDao = getDao(map, WidgetDao.class);
return permissionTemplateCharacteristicDao;
}
+ public CeActivityDao ceActivityDao() {
+ return ceActivityDao;
+ }
+
public CeQueueDao ceQueueDao() {
return ceQueueDao;
}
- public CeActivityDao ceActivityDao() {
- return ceActivityDao;
+ public CeTaskDataDao ceTaskDataDao() {
+ return ceTaskDataDao;
}
public DashboardDao dashboardDao() {
import org.sonar.db.activity.ActivityMapper;
import org.sonar.db.ce.CeActivityMapper;
import org.sonar.db.ce.CeQueueMapper;
+import org.sonar.db.ce.CeTaskDataMapper;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentDtoWithSnapshotId;
import org.sonar.db.component.ComponentLinkDto;
GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
MeasureMapper.class, MetricMapper.class, CustomMeasureMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class,
ProjectQgateAssociationMapper.class, EventMapper.class,
- CeQueueMapper.class, CeActivityMapper.class, ComponentLinkMapper.class,
+ CeQueueMapper.class, CeActivityMapper.class, CeTaskDataMapper.class, ComponentLinkMapper.class,
Migration45Mapper.class, Migration50Mapper.class, Migration53Mapper.class
};
confBuilder.loadMappers(mappers);
--- /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.db.ce;
+
+import java.io.InputStream;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Optional;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Dao;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.db.DbSession;
+
+public class CeTaskDataDao implements Dao {
+
+ private final System2 system;
+
+ public CeTaskDataDao(System2 system) {
+ this.system = system;
+ }
+
+ public void insert(DbSession dbSession, String taskUuid, InputStream data) {
+ long now = system.now();
+ try (PreparedStatement stmt = dbSession.getConnection().prepareStatement(
+ "INSERT INTO ce_task_data (task_uuid, created_at, updated_at, data) VALUES (?, ?, ?, ?)")) {
+ stmt.setString(1, taskUuid);
+ stmt.setLong(2, now);
+ stmt.setLong(3, now);
+ stmt.setBinaryStream(4, data);
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ throw new IllegalStateException("Fail to insert data of CE task " + taskUuid, e);
+ }
+ }
+
+ public Optional<DataStream> selectData(DbSession dbSession, String taskUuid) {
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ DataStream result = null;
+ try {
+ stmt = dbSession.getConnection().prepareStatement("SELECT data FROM ce_task_data WHERE task_uuid=? AND data IS NOT NULL");
+ stmt.setString(1, taskUuid);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ result = new DataStream(stmt, rs, rs.getBinaryStream(1));
+ return Optional.of(result);
+ }
+ return Optional.empty();
+ } catch (SQLException e) {
+ throw new IllegalStateException("Fail to select data of CE task " + taskUuid, e);
+ } finally {
+ if (result == null) {
+ DatabaseUtils.closeQuietly(rs);
+ DatabaseUtils.closeQuietly(stmt);
+ }
+ }
+ }
+
+ public List<String> selectUuidsNotInQueue(DbSession dbSession) {
+ return dbSession.getMapper(CeTaskDataMapper.class).selectUuidsNotInQueue();
+ }
+
+ public void deleteByUuids(DbSession dbSession, List<String> uuids) {
+ CeTaskDataMapper mapper = dbSession.getMapper(CeTaskDataMapper.class);
+ DatabaseUtils.executeLargeUpdates(uuids, mapper::deleteByUuids);
+ }
+
+ public static class DataStream implements AutoCloseable {
+ private final PreparedStatement stmt;
+ private final ResultSet rs;
+ private final InputStream stream;
+
+ private DataStream(PreparedStatement stmt, ResultSet rs, InputStream stream) {
+ this.stmt = stmt;
+ this.rs = rs;
+ this.stream = stream;
+ }
+
+ public InputStream getInputStream() {
+ return stream;
+ }
+
+ @Override
+ public void close() {
+ IOUtils.closeQuietly(stream);
+ DatabaseUtils.closeQuietly(rs);
+ DatabaseUtils.closeQuietly(stmt);
+ }
+ }
+}
--- /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.db.ce;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+
+public interface CeTaskDataMapper {
+
+ void deleteByUuids(@Param("uuids") List<String> uuids);
+
+ List<String> selectUuidsNotInQueue();
+
+}
public class DatabaseVersion {
- public static final int LAST_VERSION = 1_301;
+ public static final int LAST_VERSION = 1_302;
/**
* The minimum supported version which can be upgraded. Lower
"authors",
"ce_activity",
"ce_queue",
+ "ce_task_data",
"dashboards",
"duplications_index",
"events",
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.db.ce.CeTaskDataMapper">
+
+ <select id="selectUuidsNotInQueue" resultType="String">
+ select d.task_uuid
+ from ce_task_data d
+ left join ce_queue q on d.task_uuid = q.uuid
+ where q.uuid is null
+ </select>
+
+ <delete id="deleteByUuids" parameterType="String">
+ delete from ce_task_data
+ where task_uuid in <foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid}</foreach>
+ </delete>
+
+</mapper>
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1300');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1301');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1302');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482');
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
"EXECUTION_TIME_MS" BIGINT NULL
);
+CREATE TABLE "CE_TASK_DATA" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "TASK_UUID" VARCHAR(40) NOT NULL,
+ "DATA" BLOB(167772150),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL
+);
+
CREATE TABLE "USER_TOKENS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"LOGIN" VARCHAR(255) NOT NULL,
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(2 + 46);
+ assertThat(container.size()).isEqualTo(2 + 47);
}
}
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Clob;
return client;
}
- public void executeUpdateSql(String sql, String... params) {
+ public void executeUpdateSql(String sql, Object... params) {
try (Connection connection = db.getDatabase().getDataSource().getConnection()) {
new QueryRunner().update(connection, sql, params);
} catch (Exception e) {
*
* @param valuesByColumn column name and value pairs, if any value is null, the associated column won't be inserted
*/
- public void executeInsert(String table, String... valuesByColumn) {
- executeInsert(table, mapOf(valuesByColumn));
+ public void executeInsert(String table, String firstColumn, Object... others) {
+ executeInsert(table, mapOf(firstColumn, others));
}
- private static Map<String, String> mapOf(String... values) {
- ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
- for (int i = 0; i < values.length; i++) {
- String key = values[i];
- String value = values[i + 1];
+ private static Map<String, Object> mapOf(String firstColumn, Object... values) {
+ ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
+ List<Object> args = Lists.asList(firstColumn, values);
+ for (int i = 0; i < args.size(); i++) {
+ String key = args.get(i).toString();
+ Object value = args.get(i + 1);
if (value != null) {
builder.put(key, value);
}
* Very simple helper method to insert some data into a table.
* It's the responsibility of the caller to convert column values to string.
*/
- public void executeInsert(String table, Map<String, String> valuesByColumn) {
+ public void executeInsert(String table, Map<String, Object> valuesByColumn) {
if (valuesByColumn.isEmpty()) {
throw new IllegalArgumentException("Values cannot be empty");
}
") values (" +
COMMA_JOINER.join(Collections.nCopies(valuesByColumn.size(), '?')) +
")";
- executeUpdateSql(sql, valuesByColumn.values().toArray(new String[valuesByColumn.size()]));
+ executeUpdateSql(sql, valuesByColumn.values().toArray(new Object[valuesByColumn.size()]));
}
/**
--- /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.db.ce;
+
+import java.io.InputStream;
+import java.util.Optional;
+import org.apache.commons.io.IOUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CeTaskDataDaoTest {
+
+ private static final String A_UUID = "U1";
+ private static final String SOME_DATA = "this_is_a_report";
+ private static final long NOW = 1_500_000_000_000L;
+ private static final String TABLE_NAME = "CE_TASK_DATA";
+
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private System2 system = mock(System2.class);
+ private CeTaskDataDao underTest = new CeTaskDataDao(system);
+
+ @Test
+ public void insert_and_select_data_stream() throws Exception {
+ when(system.now()).thenReturn(NOW);
+
+ InputStream report = IOUtils.toInputStream(SOME_DATA);
+ underTest.insert(dbTester.getSession(), A_UUID, report);
+
+ Optional<CeTaskDataDao.DataStream> result = underTest.selectData(dbTester.getSession(), A_UUID);
+ assertThat(result).isPresent();
+ try {
+ assertThat(IOUtils.toString(result.get().getInputStream())).isEqualTo(SOME_DATA);
+ } finally {
+ result.get().close();
+ }
+ }
+
+ @Test
+ public void fail_to_insert_invalid_row() throws Exception {
+ expectedException.expectMessage("Fail to insert data of CE task null");
+ underTest.insert(dbTester.getSession(), null, IOUtils.toInputStream(SOME_DATA));
+ }
+
+ @Test
+ public void selectData_returns_absent_if_uuid_not_found() {
+ Optional<CeTaskDataDao.DataStream> result = underTest.selectData(dbTester.getSession(), A_UUID);
+ assertThat(result).isNotPresent();
+ }
+
+ @Test
+ public void selectData_returns_absent_if_uuid_exists_but_data_is_null() {
+ insertData(A_UUID);
+ dbTester.commit();
+
+ Optional<CeTaskDataDao.DataStream> result = underTest.selectData(dbTester.getSession(), A_UUID);
+ assertThat(result).isNotPresent();
+ }
+
+ @Test
+ public void selectUuidsNotInQueue() {
+ assertThat(underTest.selectUuidsNotInQueue(dbTester.getSession())).isEmpty();
+
+ insertData("U1");
+ insertData("U2");
+ assertThat(underTest.selectUuidsNotInQueue(dbTester.getSession())).containsOnly("U1", "U2");
+
+ CeQueueDto inQueue = new CeQueueDto().setUuid("U2").setTaskType(CeTaskTypes.REPORT).setStatus(CeQueueDto.Status.IN_PROGRESS);
+ new CeQueueDao(system).insert(dbTester.getSession(), inQueue);
+ assertThat(underTest.selectUuidsNotInQueue(dbTester.getSession())).containsOnly("U1");
+ }
+
+ @Test
+ public void deleteByUuids() {
+ insertData(A_UUID);
+ assertThat(dbTester.countRowsOfTable(TABLE_NAME)).isEqualTo(1);
+
+ underTest.deleteByUuids(dbTester.getSession(), asList(A_UUID));
+ dbTester.commit();
+ assertThat(dbTester.countRowsOfTable(TABLE_NAME)).isEqualTo(0);
+ }
+
+ private void insertData(String uuid) {
+
+ dbTester.executeInsert(TABLE_NAME, "TASK_UUID", uuid, "CREATED_AT", NOW, "UPDATED_AT", NOW);
+ dbTester.commit();
+ }
+}
*/
package org.sonar.db.version.v56;
-import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import org.junit.Before;
import org.sonar.db.DbTester;
import org.sonar.db.version.MigrationStep;
-import static com.google.common.collect.Maps.newHashMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
}
private void insertUser(String login, @Nullable String externalIdentity, @Nullable String externalIdentityProvider, long updatedAt) {
- Map<String, String> params = newHashMap(ImmutableMap.of(
- "LOGIN", login,
- "CREATED_AT", Long.toString(PAST),
- "UPDATED_AT", Long.toString(updatedAt)));
+ Map<String, Object> params = new HashMap<>();
+ params.put("LOGIN", login);
+ params.put("CREATED_AT", Long.toString(PAST));
+ params.put("UPDATED_AT", Long.toString(updatedAt));
if (externalIdentity != null) {
params.put("EXTERNAL_IDENTITY", externalIdentity);
}