diff options
Diffstat (limited to 'server/sonar-server')
353 files changed, 95 insertions, 37674 deletions
diff --git a/server/sonar-server/build.gradle b/server/sonar-server/build.gradle index 4084fea8809..13ff9a20c67 100644 --- a/server/sonar-server/build.gradle +++ b/server/sonar-server/build.gradle @@ -4,15 +4,6 @@ sonarqube { } } -sourceSets { - test { - resources { - srcDirs += ['src/test/projects'] - } - } -} - - import org.apache.tools.ant.filters.ReplaceTokens processResources { filesMatching('build.properties') { @@ -53,7 +44,6 @@ dependencies { compile project(':server:sonar-webserver-auth') compile project(':server:sonar-webserver-common') compile project(':server:sonar-webserver-es') - compile project(':server:sonar-webserver-ws') compile project(':sonar-core') compile project(':sonar-duplications') compile project(':sonar-scanner-protocol') diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java b/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java deleted file mode 100644 index 44bdc4377e3..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.app; - -public interface ProcessCommandWrapper { - /** - * Requests to the main process that SQ be restarted. - */ - void requestSQRestart(); - - /** - * Requests to the main process that the WebServer is stopped. - */ - void requestHardStop(); - - /** - * Notifies any listening process that the WebServer is operational. - */ - void notifyOperational(); - - /** - * Checks whether the Compute Engine is operational. - */ - boolean isCeOperational(); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java b/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java deleted file mode 100644 index 12b3f68543c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.app; - -import java.io.File; -import org.sonar.api.config.Configuration; -import org.sonar.process.ProcessId; -import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; -import org.sonar.process.sharedmemoryfile.ProcessCommands; - -import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; -import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; - -public class ProcessCommandWrapperImpl implements ProcessCommandWrapper { - - private static final ProcessMethod<Void> SET_OPERATIONAL = processCommands -> { - processCommands.setOperational(); - return null; - }; - private static final ProcessMethod<Void> ASK_FOR_RESTART = processCommands -> { - processCommands.askForRestart(); - return null; - }; - private static final ProcessMethod<Void> ASK_FOR_HARD_STOP = processCommands -> { - processCommands.askForHardStop(); - return null; - }; - private static final ProcessMethod<Boolean> IS_OPERATIONAL = ProcessCommands::isOperational; - - private final Configuration config; - - public ProcessCommandWrapperImpl(Configuration config) { - this.config = config; - } - - @Override - public void requestSQRestart() { - call(ASK_FOR_RESTART, selfProcessNumber()); - } - - @Override - public void requestHardStop() { - call(ASK_FOR_HARD_STOP, selfProcessNumber()); - } - - @Override - public void notifyOperational() { - call(SET_OPERATIONAL, selfProcessNumber()); - } - - @Override - public boolean isCeOperational() { - return call(IS_OPERATIONAL, ProcessId.COMPUTE_ENGINE.getIpcIndex()); - } - - private int selfProcessNumber() { - return nonNullAsInt(PROPERTY_PROCESS_INDEX); - } - - private <T> T call(ProcessMethod<T> command, int processNumber) { - File shareDir = nonNullValueAsFile(PROPERTY_SHARED_PATH); - try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(shareDir, processNumber)) { - return command.callOn(commands); - } - } - - private interface ProcessMethod<T> { - T callOn(ProcessCommands processCommands); - } - - private int nonNullAsInt(String key) { - return config.getInt(key).orElseThrow(() -> new IllegalArgumentException(String.format("Property %s is not set", key))); - } - - private File nonNullValueAsFile(String key) { - return new File(config.get(key).orElseThrow(() -> new IllegalArgumentException(String.format("Property %s is not set", key)))); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java b/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java deleted file mode 100644 index dfc6c8c8414..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.app; - -/** - * Holds a boolean flag representing the restarting status of the WebServer. - * This boolean is {@code false} by default and can safely be changed concurrently using methods {@link #set()} and - * {@link #unset()}. - */ -public interface RestartFlagHolder { - /** - * @return whether restarting flag has been set or not. - */ - boolean isRestarting(); - - /** - * Sets the restarting flag to {@code true}, no matter it already is or not. - */ - void set(); - - /** - * Sets the restarting flag to {@code false}, no matter it already is or not. - */ - void unset(); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java deleted file mode 100644 index 98354a8e77b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.app; - -import java.util.concurrent.atomic.AtomicBoolean; - -public class RestartFlagHolderImpl implements RestartFlagHolder { - private final AtomicBoolean restarting = new AtomicBoolean(false); - - @Override - public boolean isRestarting() { - return restarting.get(); - } - - @Override - public void set() { - restarting.set(true); - } - - @Override - public void unset() { - restarting.set(false); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeature.java b/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeature.java deleted file mode 100644 index 7d60949c954..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeature.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -interface BranchFeature { - - boolean isEnabled(); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureExtension.java b/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureExtension.java deleted file mode 100644 index 20fc40ff324..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureExtension.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -import org.sonar.api.server.ServerSide; - -/** - * The branch plugin needs to implement this in order to know that the branch feature is supported - */ -@ServerSide -public interface BranchFeatureExtension extends BranchFeature { - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureProxy.java b/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureProxy.java deleted file mode 100644 index 8647d7c421f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureProxy.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -/** - * The goal of this class is to handle the 2 different use case : - * - The branch plugin exists, the proxy will redirect method calls to the plugin - * - No branch plugin, feature is disabled - */ -public interface BranchFeatureProxy extends BranchFeature { - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureProxyImpl.java b/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureProxyImpl.java deleted file mode 100644 index 634e59721a7..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/BranchFeatureProxyImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -public class BranchFeatureProxyImpl implements BranchFeatureProxy { - - private final BranchFeatureExtension branchFeatureExtension; - - public BranchFeatureProxyImpl() { - this.branchFeatureExtension = null; - } - - public BranchFeatureProxyImpl(BranchFeatureExtension branchFeatureExtension) { - this.branchFeatureExtension = branchFeatureExtension; - } - - @Override - public boolean isEnabled() { - return branchFeatureExtension != null && branchFeatureExtension.isEnabled(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/branch/package-info.java deleted file mode 100644 index cb79dbcf31d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/CeModule.java b/server/sonar-server/src/main/java/org/sonar/server/ce/CeModule.java deleted file mode 100644 index c228b87ebd0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/CeModule.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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; - -import org.sonar.ce.queue.CeQueueImpl; -import org.sonar.ce.task.log.CeTaskLogging; -import org.sonar.ce.task.projectanalysis.taskprocessor.ReportTaskProcessor; -import org.sonar.core.platform.Module; -import org.sonar.server.ce.http.CeHttpClientImpl; -import org.sonar.server.ce.queue.BranchSupport; -import org.sonar.server.ce.queue.ReportSubmitter; - -public class CeModule extends Module { - @Override - protected void configureModule() { - add(CeTaskLogging.class, - CeHttpClientImpl.class, - - // Queue - CeQueueImpl.class, - BranchSupport.class, - ReportSubmitter.class, - - // Core tasks processors - ReportTaskProcessor.class); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/http/CeHttpClient.java b/server/sonar-server/src/main/java/org/sonar/server/ce/http/CeHttpClient.java deleted file mode 100644 index f86a08efb62..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/http/CeHttpClient.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.http; - -import java.util.Optional; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - -public interface CeHttpClient { - Optional<ProtobufSystemInfo.SystemInfo> retrieveSystemInfo(); - - void changeLogLevel(LoggerLevel level); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/http/CeHttpClientImpl.java b/server/sonar-server/src/main/java/org/sonar/server/ce/http/CeHttpClientImpl.java deleted file mode 100644 index 1b6a32875c4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/http/CeHttpClientImpl.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.http; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.Optional; -import okhttp3.OkHttpClient; -import okhttp3.RequestBody; -import org.apache.commons.io.IOUtils; -import org.sonar.api.config.Configuration; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; -import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - -import static java.util.Objects.requireNonNull; -import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; -import static org.sonar.process.ProcessId.COMPUTE_ENGINE; - -/** - * Client for the HTTP server of the Compute Engine. - */ -public class CeHttpClientImpl implements CeHttpClient { - - private static final String PATH_CHANGE_LOG_LEVEL = "changeLogLevel"; - private static final String PATH_SYSTEM_INFO = "systemInfo"; - - private final File ipcSharedDir; - - public CeHttpClientImpl(Configuration config) { - this.ipcSharedDir = new File(config.get(PROPERTY_SHARED_PATH).get()); - } - - /** - * Connects to the specified JVM process and requests system information. - * - * @return the system info, or absent if the process is not up or if its HTTP URL - * is not registered into IPC. - */ - @Override - public Optional<ProtobufSystemInfo.SystemInfo> retrieveSystemInfo() { - return call(SystemInfoActionClient.INSTANCE); - } - - private enum SystemInfoActionClient implements ActionClient<Optional<ProtobufSystemInfo.SystemInfo>> { - INSTANCE; - - @Override - public String getPath() { - return PATH_SYSTEM_INFO; - } - - @Override - public Optional<ProtobufSystemInfo.SystemInfo> getDefault() { - return Optional.empty(); - } - - @Override - public Optional<ProtobufSystemInfo.SystemInfo> call(String url) throws Exception { - byte[] protobuf = IOUtils.toByteArray(new URI(url)); - return Optional.of(ProtobufSystemInfo.SystemInfo.parseFrom(protobuf)); - } - } - - @Override - public void changeLogLevel(LoggerLevel level) { - requireNonNull(level, "level can't be null"); - call(new ChangeLogLevelActionClient(level)); - } - - private static final class ChangeLogLevelActionClient implements ActionClient<Void> { - private final LoggerLevel newLogLevel; - - private ChangeLogLevelActionClient(LoggerLevel newLogLevel) { - this.newLogLevel = newLogLevel; - } - - @Override - public String getPath() { - return PATH_CHANGE_LOG_LEVEL; - } - - @Override - public Void getDefault() { - return null; - } - - @Override - public Void call(String url) throws Exception { - okhttp3.Request request = new okhttp3.Request.Builder() - .post(RequestBody.create(null, new byte[0])) - .url(url + "?level=" + newLogLevel.name()) - .build(); - try (okhttp3.Response response = new OkHttpClient().newCall(request).execute()) { - if (response.code() != 200) { - throw new IOException( - String.format( - "Failed to change log level in Compute Engine. Code was '%s' and response was '%s' for url '%s'", - response.code(), - response.body().string(), - url)); - } - return null; - } - } - } - - private <T> T call(ActionClient<T> actionClient) { - try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(ipcSharedDir, COMPUTE_ENGINE.getIpcIndex())) { - if (commands.isUp()) { - return actionClient.call(commands.getHttpUrl() + "/" + actionClient.getPath()); - } - return actionClient.getDefault(); - } catch (Exception e) { - throw new IllegalStateException("Failed to call HTTP server of process " + COMPUTE_ENGINE, e); - } - } - - private interface ActionClient<T> { - /** - * Path of the action. - */ - String getPath(); - - /** - * Value to return when the Compute Engine is not ready. - */ - T getDefault(); - - /** - * Delegates to perform the call to the Compute Engine's specified absolute URL. - */ - T call(String url) throws Exception; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/http/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ce/http/package-info.java deleted file mode 100644 index 17b36c59125..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/http/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.http; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ce/package-info.java deleted file mode 100644 index 59c06da2a3f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/BranchSupport.java b/server/sonar-server/src/main/java/org/sonar/server/ce/queue/BranchSupport.java deleted file mode 100644 index 96ccac1eb56..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/BranchSupport.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; - -/** - * Branch code for {@link ReportSubmitter}. - * <p> - * Does not support branches unless an implementation of {@link BranchSupportDelegate} is available. - */ -@ServerSide -public class BranchSupport { - @CheckForNull - private final BranchSupportDelegate delegate; - - /** - * Constructor called by Pico when no implementation of {@link BranchSupportDelegate} is available. - */ - public BranchSupport() { - this(null); - } - - public BranchSupport(@Nullable BranchSupportDelegate delegate) { - this.delegate = delegate; - } - - ComponentKey createComponentKey(String projectKey, Map<String, String> characteristics) { - if (characteristics.isEmpty()) { - return new ComponentKeyImpl(projectKey, projectKey); - } else { - checkState(delegate != null, "Current edition does not support branch feature"); - } - - return delegate.createComponentKey(projectKey, characteristics); - } - - ComponentDto createBranchComponent(DbSession dbSession, ComponentKey componentKey, OrganizationDto organization, - ComponentDto mainComponentDto, BranchDto mainComponentBranchDto) { - checkState(delegate != null, "Current edition does not support branch feature"); - - return delegate.createBranchComponent(dbSession, componentKey, organization, mainComponentDto, mainComponentBranchDto); - } - - public abstract static class ComponentKey { - public abstract String getKey(); - - public abstract String getDbKey(); - - public abstract Optional<Branch> getBranch(); - - public abstract Optional<String> getPullRequestKey(); - - public final boolean isMainBranch() { - return !getBranch().isPresent() && !getPullRequestKey().isPresent(); - } - - /** - * @return the {@link ComponentKey} of the main branch for this component. - */ - public abstract ComponentKey getMainBranchComponentKey(); - } - - @Immutable - public static final class Branch { - private final String name; - private final BranchType type; - - public Branch(String name, BranchType type) { - this.name = requireNonNull(name, "name can't be null"); - this.type = requireNonNull(type, "type can't be null"); - } - - public String getName() { - return name; - } - - public BranchType getType() { - return type; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Branch branch = (Branch) o; - return name.equals(branch.name) && type == branch.type; - } - - @Override - public int hashCode() { - return Objects.hash(name, type); - } - - @Override - public String toString() { - return "Branch{" + - "name='" + name + '\'' + - ", type=" + type + - '}'; - } - } - - private static final class ComponentKeyImpl extends ComponentKey { - private final String key; - private final String dbKey; - - public ComponentKeyImpl(String key, String dbKey) { - this.key = key; - this.dbKey = dbKey; - } - - @Override - public String getKey() { - return key; - } - - @Override - public String getDbKey() { - return dbKey; - } - - @Override - public Optional<Branch> getBranch() { - return Optional.empty(); - } - - @Override - public Optional<String> getPullRequestKey() { - return Optional.empty(); - } - - @Override - public ComponentKey getMainBranchComponentKey() { - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ComponentKeyImpl that = (ComponentKeyImpl) o; - return Objects.equals(key, that.key) && - Objects.equals(dbKey, that.dbKey); - } - - @Override - public int hashCode() { - return Objects.hash(key, dbKey); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/BranchSupportDelegate.java b/server/sonar-server/src/main/java/org/sonar/server/ce/queue/BranchSupportDelegate.java deleted file mode 100644 index c8a3677cd67..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/BranchSupportDelegate.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import java.util.Map; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbSession; -import org.sonar.db.ce.CeTaskCharacteristicDto; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.ce.queue.BranchSupport.ComponentKey; - -@ServerSide -public interface BranchSupportDelegate { - /** - * Creates a {@link ComponentKey} for the specified projectKey and the specified {@code characteristics}. - * - * @throws IllegalArgumentException if {@code characteristics} is empty - * @throws IllegalArgumentException if does not contain a supported value for {@link CeTaskCharacteristicDto#BRANCH_TYPE_KEY BRANCH_TYPE_KEY} - * @throws IllegalArgumentException if does not contain a value for expected - * {@link CeTaskCharacteristicDto#BRANCH_KEY BRANCH_KEY} or {@link CeTaskCharacteristicDto#PULL_REQUEST PULL_REQUEST} - * given the value of {@link CeTaskCharacteristicDto#BRANCH_TYPE_KEY BRANCH_TYPE_KEY} - * @throws IllegalArgumentException if incorrectly contains a value in - * {@link CeTaskCharacteristicDto#BRANCH_KEY BRANCH_KEY} or {@link CeTaskCharacteristicDto#PULL_REQUEST PULL_REQUEST} - * given the value of {@link CeTaskCharacteristicDto#BRANCH_TYPE_KEY BRANCH_TYPE_KEY} - */ - ComponentKey createComponentKey(String projectKey, Map<String, String> characteristics); - - /** - * Creates the ComponentDto for the branch described in {@code componentKey} which belongs to the specified - * {@code mainComponentDto} in the specified {@code organization}. - * - * @throws IllegalArgumentException if arguments are inconsistent (such as {@code mainComponentDto} not having the same - * key as {@code componentKey.getKey()}, ...) - */ - ComponentDto createBranchComponent(DbSession dbSession, ComponentKey componentKey, - OrganizationDto organization, ComponentDto mainComponentDto, BranchDto mainComponentBranchDto); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/CeQueueCleaner.java b/server/sonar-server/src/main/java/org/sonar/server/ce/queue/CeQueueCleaner.java deleted file mode 100644 index 260f24b5a0f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/CeQueueCleaner.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import java.util.List; -import org.picocontainer.Startable; -import org.sonar.api.config.Configuration; -import org.sonar.api.platform.ServerUpgradeStatus; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.ce.queue.CeQueue; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.process.ProcessProperties; - -/** - * Cleans-up the Compute Engine queue. - */ -@ServerSide -public class CeQueueCleaner implements Startable { - - private static final Logger LOGGER = Loggers.get(CeQueueCleaner.class); - - private final DbClient dbClient; - private final ServerUpgradeStatus serverUpgradeStatus; - private final CeQueue queue; - private final Configuration configuration; - - public CeQueueCleaner(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, CeQueue queue, Configuration configuration) { - this.dbClient = dbClient; - this.serverUpgradeStatus = serverUpgradeStatus; - this.queue = queue; - this.configuration = configuration; - } - - @Override - public void start() { - if (serverUpgradeStatus.isUpgraded() && !isBlueGreenDeployment()) { - cleanOnUpgrade(); - } - cleanUpTaskInputOrphans(); - } - - private boolean isBlueGreenDeployment() { - return configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false); - } - - private void cleanOnUpgrade() { - // we assume that pending tasks are not compatible with the new version - // and can't be processed - LOGGER.info("Cancel all pending tasks (due to upgrade)"); - queue.clear(); - } - - private void cleanUpTaskInputOrphans() { - try (DbSession dbSession = dbClient.openSession(false)) { - // 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.ceTaskInputDao().selectUuidsNotInQueue(dbSession); - dbClient.ceTaskInputDao().deleteByUuids(dbSession, uuids); - dbSession.commit(); - } - } - - @Override - public void stop() { - // nothing to do - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java b/server/sonar-server/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java deleted file mode 100644 index 30cdf6ed832..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/ReportSubmitter.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import javax.annotation.Nullable; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; -import org.sonar.api.server.ServerSide; -import org.sonar.api.web.UserRole; -import org.sonar.ce.queue.CeQueue; -import org.sonar.ce.queue.CeTaskSubmit; -import org.sonar.ce.task.CeTask; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.ce.CeTaskTypes; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.OrganizationPermission; -import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.component.NewComponent; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.permission.PermissionTemplateService; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.String.format; -import static org.apache.commons.lang.StringUtils.defaultIfBlank; -import static org.sonar.server.component.NewComponent.newComponentBuilder; -import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; - -@ServerSide -public class ReportSubmitter { - - private final CeQueue queue; - private final UserSession userSession; - private final ComponentUpdater componentUpdater; - private final PermissionTemplateService permissionTemplateService; - private final DbClient dbClient; - private final BranchSupport branchSupport; - - public ReportSubmitter(CeQueue queue, UserSession userSession, ComponentUpdater componentUpdater, - PermissionTemplateService permissionTemplateService, DbClient dbClient, BranchSupport branchSupport) { - this.queue = queue; - this.userSession = userSession; - this.componentUpdater = componentUpdater; - this.permissionTemplateService = permissionTemplateService; - this.dbClient = dbClient; - this.branchSupport = branchSupport; - } - - /** - * @throws NotFoundException if the organization with the specified key does not exist - * @throws IllegalArgumentException if the organization with the specified key is not the organization of the specified project (when it already exists in DB) - */ - public CeTask submit(String organizationKey, String projectKey, @Nullable String projectName, - Map<String, String> characteristics, InputStream reportInput) { - try (DbSession dbSession = dbClient.openSession(false)) { - OrganizationDto organizationDto = getOrganizationDtoOrFail(dbSession, organizationKey); - BranchSupport.ComponentKey componentKey = branchSupport.createComponentKey(projectKey, characteristics); - Optional<ComponentDto> existingComponent = dbClient.componentDao().selectByKey(dbSession, componentKey.getDbKey()); - validateProject(dbSession, existingComponent, projectKey); - ensureOrganizationIsConsistent(existingComponent, organizationDto); - ComponentDto component = existingComponent.orElseGet(() -> createComponent(dbSession, organizationDto, componentKey, projectName)); - checkScanPermission(component); - return submitReport(dbSession, reportInput, component, characteristics); - } - } - - private void checkScanPermission(ComponentDto project) { - // this is a specific and inconsistent behavior. For legacy reasons, "technical users" - // defined on an organization should be able to analyze a project even if - // they don't have the direct permission on the project. - // That means that dropping the permission on the project does not have any effects - // if user has still the permission on the organization - if (!userSession.hasComponentPermission(UserRole.SCAN, project) && - !userSession.hasPermission(OrganizationPermission.SCAN, project.getOrganizationUuid())) { - throw insufficientPrivilegesException(); - } - } - - private OrganizationDto getOrganizationDtoOrFail(DbSession dbSession, String organizationKey) { - return dbClient.organizationDao().selectByKey(dbSession, organizationKey) - .orElseThrow(() -> new NotFoundException(format("Organization with key '%s' does not exist", organizationKey))); - } - - private void validateProject(DbSession dbSession, Optional<ComponentDto> project, String rawProjectKey) { - List<String> errors = new ArrayList<>(); - if (!project.isPresent()) { - return; - } - - ComponentDto component = project.get(); - if (!Qualifiers.PROJECT.equals(component.qualifier()) || !Scopes.PROJECT.equals(component.scope())) { - errors.add(format("Component '%s' is not a project", rawProjectKey)); - } - if (!component.projectUuid().equals(component.uuid())) { - // Project key is already used as a module of another project - ComponentDto anotherBaseProject = dbClient.componentDao().selectOrFailByUuid(dbSession, component.projectUuid()); - errors.add(format("The project '%s' is already defined in SonarQube but as a module of project '%s'. " - + "If you really want to stop directly analysing project '%s', please first delete it from SonarQube and then relaunch the analysis of project '%s'.", - rawProjectKey, anotherBaseProject.getKey(), anotherBaseProject.getKey(), rawProjectKey)); - } - if (!errors.isEmpty()) { - throw BadRequestException.create(errors); - } - } - - private static void ensureOrganizationIsConsistent(Optional<ComponentDto> project, OrganizationDto organizationDto) { - if (project.isPresent()) { - checkArgument(project.get().getOrganizationUuid().equals(organizationDto.getUuid()), - "Organization of component with key '%s' does not match specified organization '%s'", - project.get().getDbKey(), organizationDto.getKey()); - } - } - - private ComponentDto createComponent(DbSession dbSession, OrganizationDto organization, BranchSupport.ComponentKey componentKey, @Nullable String projectName) { - if (componentKey.isMainBranch()) { - ComponentDto project = createProject(dbSession, organization, componentKey, projectName); - componentUpdater.commitAndIndex(dbSession, project); - return project; - } - - Optional<ComponentDto> existingMainComponent = dbClient.componentDao().selectByKey(dbSession, componentKey.getKey()); - ComponentDto mainComponentDto = existingMainComponent - .orElseGet(() -> createProject(dbSession, organization, componentKey.getMainBranchComponentKey(), projectName)); - BranchDto mainComponentBranchDto = dbClient.branchDao().selectByUuid(dbSession, mainComponentDto.uuid()) - .orElseThrow(() -> new IllegalStateException("Branch of main component does not exist")); - ComponentDto branchComponent = branchSupport.createBranchComponent(dbSession, componentKey, organization, mainComponentDto, mainComponentBranchDto); - if (existingMainComponent.isPresent()) { - dbSession.commit(); - } else { - componentUpdater.commitAndIndex(dbSession, mainComponentDto); - } - return branchComponent; - } - - private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, BranchSupport.ComponentKey componentKey, - @Nullable String projectName) { - userSession.checkPermission(OrganizationPermission.PROVISION_PROJECTS, organization); - Integer userId = userSession.getUserId(); - - boolean wouldCurrentUserHaveScanPermission = permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate( - dbSession, organization.getUuid(), userId, componentKey.getDbKey()); - if (!wouldCurrentUserHaveScanPermission) { - throw insufficientPrivilegesException(); - } - - boolean newProjectPrivate = dbClient.organizationDao().getNewProjectPrivate(dbSession, organization); - - NewComponent newProject = newComponentBuilder() - .setOrganizationUuid(organization.getUuid()) - .setKey(componentKey.getKey()) - .setName(defaultIfBlank(projectName, componentKey.getKey())) - .setQualifier(Qualifiers.PROJECT) - .setPrivate(newProjectPrivate) - .build(); - return componentUpdater.createWithoutCommit(dbSession, newProject, userId); - } - - private CeTask submitReport(DbSession dbSession, InputStream reportInput, ComponentDto project, Map<String, String> characteristics) { - CeTaskSubmit.Builder submit = queue.prepareSubmit(); - - // the report file must be saved before submitting the task - dbClient.ceTaskInputDao().insert(dbSession, submit.getUuid(), reportInput); - dbSession.commit(); - - submit.setType(CeTaskTypes.REPORT); - submit.setComponent(CeTaskSubmit.Component.fromDto(project)); - submit.setSubmitterUuid(userSession.getUuid()); - submit.setCharacteristics(characteristics); - return queue.submit(submit.build()); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ce/queue/package-info.java deleted file mode 100644 index da7a3657d27..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/queue/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java deleted file mode 100644 index 0b4fe475a7b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import java.util.List; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.resources.Scopes; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.es.ProjectIndexers; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Collections.singletonList; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION; - -@ServerSide -public class ComponentCleanerService { - - private final DbClient dbClient; - private final ResourceTypes resourceTypes; - private final ProjectIndexers projectIndexers; - - public ComponentCleanerService(DbClient dbClient, ResourceTypes resourceTypes, ProjectIndexers projectIndexers) { - this.dbClient = dbClient; - this.resourceTypes = resourceTypes; - this.projectIndexers = projectIndexers; - } - - public void delete(DbSession dbSession, List<ComponentDto> projects) { - for (ComponentDto project : projects) { - delete(dbSession, project); - } - } - - public void deleteBranch(DbSession dbSession, ComponentDto branch) { - // TODO: detect if other branches depend on it? - dbClient.purgeDao().deleteBranch(dbSession, branch.uuid()); - projectIndexers.commitAndIndex(dbSession, singletonList(branch), PROJECT_DELETION); - } - - public void delete(DbSession dbSession, ComponentDto project) { - checkArgument(!hasNotProjectScope(project) && !isNotDeletable(project) && project.getMainBranchProjectUuid() == null, "Only projects can be deleted"); - dbClient.purgeDao().deleteProject(dbSession, project.uuid()); - dbClient.userDao().cleanHomepage(dbSession, project); - projectIndexers.commitAndIndex(dbSession, singletonList(project), PROJECT_DELETION); - } - - private static boolean hasNotProjectScope(ComponentDto project) { - return !Scopes.PROJECT.equals(project.scope()); - } - - private boolean isNotDeletable(ComponentDto project) { - ResourceType resourceType = resourceTypes.get(project.qualifier()); - return resourceType == null || !resourceType.getBooleanProperty("deletable"); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java deleted file mode 100644 index 86259eb3d01..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import java.util.Collection; -import java.util.Optional; -import java.util.Set; -import javax.annotation.Nullable; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.resources.Scopes; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.exceptions.NotFoundException; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.String.format; -import static org.sonar.server.exceptions.NotFoundException.checkFoundWithOptional; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public class ComponentFinder { - private static final String MSG_COMPONENT_ID_OR_KEY_TEMPLATE = "Either '%s' or '%s' must be provided"; - private static final String MSG_PARAMETER_MUST_NOT_BE_EMPTY = "The '%s' parameter must not be empty"; - private static final String LABEL_PROJECT = "Project"; - private static final String LABEL_COMPONENT = "Component"; - - private final DbClient dbClient; - private final ResourceTypes resourceTypes; - - public ComponentFinder(DbClient dbClient, ResourceTypes resourceTypes) { - this.dbClient = dbClient; - this.resourceTypes = resourceTypes; - } - - public ComponentDto getByUuidOrKey(DbSession dbSession, @Nullable String componentUuid, @Nullable String componentKey, ParamNames parameterNames) { - checkByUuidOrKey(componentUuid, componentKey, parameterNames); - - if (componentUuid != null) { - return getByUuid(dbSession, checkParamNotEmpty(componentUuid, parameterNames.getUuidParam())); - } - - return getByKey(dbSession, checkParamNotEmpty(componentKey, parameterNames.getKeyParam())); - } - - private static String checkParamNotEmpty(String value, String param) { - checkArgument(!value.isEmpty(), MSG_PARAMETER_MUST_NOT_BE_EMPTY, param); - return value; - } - - private static void checkByUuidOrKey(@Nullable String componentUuid, @Nullable String componentKey, ParamNames parameterNames) { - checkArgument(componentUuid != null ^ componentKey != null, MSG_COMPONENT_ID_OR_KEY_TEMPLATE, parameterNames.getUuidParam(), parameterNames.getKeyParam()); - } - - public ComponentDto getByKey(DbSession dbSession, String key) { - return getByKey(dbSession, key, LABEL_COMPONENT); - } - - private ComponentDto getByKey(DbSession dbSession, String key, String label) { - return checkComponent(dbClient.componentDao().selectByKey(dbSession, key), "%s key '%s' not found", label, key); - } - - public ComponentDto getByUuid(DbSession dbSession, String uuid) { - return getByUuid(dbSession, uuid, LABEL_COMPONENT); - } - - private ComponentDto getByUuid(DbSession dbSession, String uuid, String label) { - return checkComponent(dbClient.componentDao().selectByUuid(dbSession, uuid), "%s id '%s' not found", label, uuid); - } - - private static ComponentDto checkComponent(Optional<ComponentDto> componentDto, String message, Object... messageArguments) { - if (componentDto.isPresent() && componentDto.get().isEnabled() && componentDto.get().getMainBranchProjectUuid() == null) { - return componentDto.get(); - } - throw new NotFoundException(format(message, messageArguments)); - } - - public ComponentDto getRootComponentByUuidOrKey(DbSession dbSession, @Nullable String projectUuid, @Nullable String projectKey) { - ComponentDto project; - if (projectUuid != null) { - project = getByUuid(dbSession, projectUuid, LABEL_PROJECT); - } else { - project = getByKey(dbSession, projectKey, LABEL_PROJECT); - } - checkIsProject(project); - - return project; - } - - private ComponentDto checkIsProject(ComponentDto component) { - Set<String> rootQualifiers = getRootQualifiers(resourceTypes); - - checkRequest(component.scope().equals(Scopes.PROJECT) && rootQualifiers.contains(component.qualifier()), - format( - "Component '%s' (id: %s) must be a project%s.", - component.getDbKey(), component.uuid(), - rootQualifiers.contains(Qualifiers.VIEW) ? " or a view" : "")); - - return component; - } - - private static Set<String> getRootQualifiers(ResourceTypes resourceTypes) { - Collection<ResourceType> rootTypes = resourceTypes.getRoots(); - return rootTypes - .stream() - .map(ResourceType::getQualifier) - .collect(MoreCollectors.toSet(rootTypes.size())); - } - - public OrganizationDto getOrganization(DbSession dbSession, ComponentDto component) { - String organizationUuid = component.getOrganizationUuid(); - Optional<OrganizationDto> organizationDto = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid); - return checkFoundWithOptional(organizationDto, "Organization with uuid '%s' not found", organizationUuid); - } - - public ComponentDto getByKeyAndBranch(DbSession dbSession, String key, String branch) { - Optional<ComponentDto> componentDto = dbClient.componentDao().selectByKeyAndBranch(dbSession, key, branch); - if (componentDto.isPresent() && componentDto.get().isEnabled()) { - return componentDto.get(); - } - throw new NotFoundException(format("Component '%s' on branch '%s' not found", key, branch)); - } - - public ComponentDto getByKeyAndPullRequest(DbSession dbSession, String key, String pullRequest) { - Optional<ComponentDto> componentDto = dbClient.componentDao().selectByKeyAndPullRequest(dbSession, key, pullRequest); - if (componentDto.isPresent() && componentDto.get().isEnabled()) { - return componentDto.get(); - } - throw new NotFoundException(format("Component '%s' of pull request '%s' not found", key, pullRequest)); - } - - public ComponentDto getByKeyAndOptionalBranchOrPullRequest(DbSession dbSession, String key, @Nullable String branch, @Nullable String pullRequest) { - checkArgument(branch == null || pullRequest == null, "Either branch or pull request can be provided, not both"); - if (branch != null) { - return getByKeyAndBranch(dbSession, key, branch); - } - if (pullRequest != null) { - return getByKeyAndPullRequest(dbSession, key, pullRequest); - } - - return getByKey(dbSession, key); - } - - public enum ParamNames { - PROJECT_ID_AND_KEY("projectId", "projectKey"), - PROJECT_UUID_AND_KEY("projectUuid", "projectKey"), - PROJECT_UUID_AND_PROJECT("projectUuid", "project"), - UUID_AND_KEY("uuid", "key"), - ID_AND_KEY("id", "key"), - COMPONENT_ID_AND_KEY("componentId", "componentKey"), - BASE_COMPONENT_ID_AND_KEY("baseComponentId", "component"), - DEVELOPER_ID_AND_KEY("developerId", "developerKey"), - COMPONENT_ID_AND_COMPONENT("componentId", "component"), - PROJECT_ID_AND_PROJECT("projectId", "project"), - PROJECT_ID_AND_FROM("projectId", "from"); - - private final String uuidParamName; - private final String keyParamName; - - ParamNames(String uuidParamName, String keyParamName) { - this.uuidParamName = uuidParamName; - this.keyParamName = keyParamName; - } - - public String getUuidParam() { - return uuidParamName; - } - - public String getKeyParam() { - return keyParamName; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java deleted file mode 100644 index bdef35a72ff..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import java.util.Set; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; -import org.sonar.api.server.ServerSide; -import org.sonar.api.web.UserRole; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentKeyUpdaterDao; -import org.sonar.db.component.ResourceDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.project.Project; -import org.sonar.server.project.ProjectLifeCycleListeners; -import org.sonar.server.project.RekeyedProject; -import org.sonar.server.user.UserSession; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static org.sonar.core.component.ComponentKeys.isValidProjectKey; -import static org.sonar.db.component.ComponentKeyUpdaterDao.checkIsProjectOrModule; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -@ServerSide -public class ComponentService { - private final DbClient dbClient; - private final UserSession userSession; - private final ProjectIndexers projectIndexers; - private final ProjectLifeCycleListeners projectLifeCycleListeners; - - public ComponentService(DbClient dbClient, UserSession userSession, ProjectIndexers projectIndexers, ProjectLifeCycleListeners projectLifeCycleListeners) { - this.dbClient = dbClient; - this.userSession = userSession; - this.projectIndexers = projectIndexers; - this.projectLifeCycleListeners = projectLifeCycleListeners; - } - - public void updateKey(DbSession dbSession, ComponentDto projectOrModule, String newKey) { - userSession.checkComponentPermission(UserRole.ADMIN, projectOrModule); - checkIsProjectOrModule(projectOrModule); - checkProjectOrModuleKeyFormat(newKey); - dbClient.componentKeyUpdaterDao().updateKey(dbSession, projectOrModule.uuid(), newKey); - projectIndexers.commitAndIndex(dbSession, singletonList(projectOrModule), ProjectIndexer.Cause.PROJECT_KEY_UPDATE); - if (isMainProject(projectOrModule)) { - Project newProject = new Project(projectOrModule.uuid(), newKey, projectOrModule.name(), projectOrModule.description(), projectOrModule.getTags()); - projectLifeCycleListeners.onProjectsRekeyed(singleton(new RekeyedProject(newProject, projectOrModule.getDbKey()))); - } - } - - private static boolean isMainProject(ComponentDto projectOrModule) { - return projectOrModule.isRootProject() && projectOrModule.getMainBranchProjectUuid() == null; - } - - public void bulkUpdateKey(DbSession dbSession, ComponentDto projectOrModule, String stringToReplace, String replacementString) { - Set<ComponentKeyUpdaterDao.RekeyedResource> rekeyedProjects = dbClient.componentKeyUpdaterDao().bulkUpdateKey( - dbSession, projectOrModule.uuid(), stringToReplace, replacementString, - ComponentService::isMainProject); - projectIndexers.commitAndIndex(dbSession, singletonList(projectOrModule), ProjectIndexer.Cause.PROJECT_KEY_UPDATE); - if (!rekeyedProjects.isEmpty()) { - projectLifeCycleListeners.onProjectsRekeyed(rekeyedProjects.stream() - .map(ComponentService::toRekeyedProject) - .collect(MoreCollectors.toSet(rekeyedProjects.size()))); - } - } - - private static boolean isMainProject(ComponentKeyUpdaterDao.RekeyedResource rekeyedResource) { - ResourceDto resource = rekeyedResource.getResource(); - String resourceKey = resource.getKey(); - return Scopes.PROJECT.equals(resource.getScope()) - && Qualifiers.PROJECT.equals(resource.getQualifier()) - && !resourceKey.contains(ComponentDto.BRANCH_KEY_SEPARATOR) - && !resourceKey.contains(ComponentDto.PULL_REQUEST_SEPARATOR); - } - - private static RekeyedProject toRekeyedProject(ComponentKeyUpdaterDao.RekeyedResource rekeyedResource) { - ResourceDto resource = rekeyedResource.getResource(); - Project project = new Project(resource.getUuid(), resource.getKey(), resource.getName(), resource.getDescription(), emptyList()); - return new RekeyedProject(project, rekeyedResource.getOldKey()); - } - - private static void checkProjectOrModuleKeyFormat(String key) { - checkRequest(isValidProjectKey(key), "Malformed key for '%s'. It cannot be empty nor contain whitespaces.", key); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java deleted file mode 100644 index f39283fef5f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import com.google.common.collect.ImmutableSet; -import java.util.Date; -import java.util.Locale; -import java.util.Set; -import javax.annotation.Nullable; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; -import org.sonar.api.utils.System2; -import org.sonar.core.i18n.I18n; -import org.sonar.core.util.Uuids; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.es.ProjectIndexer.Cause; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.favorite.FavoriteUpdater; -import org.sonar.server.permission.PermissionTemplateService; - -import static java.util.Collections.singletonList; -import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.core.component.ComponentKeys.isValidProjectKey; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public class ComponentUpdater { - - private static final Set<String> MAIN_BRANCH_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP); - - private final DbClient dbClient; - private final I18n i18n; - private final System2 system2; - private final PermissionTemplateService permissionTemplateService; - private final FavoriteUpdater favoriteUpdater; - private final ProjectIndexers projectIndexers; - - public ComponentUpdater(DbClient dbClient, I18n i18n, System2 system2, - PermissionTemplateService permissionTemplateService, FavoriteUpdater favoriteUpdater, - ProjectIndexers projectIndexers) { - this.dbClient = dbClient; - this.i18n = i18n; - this.system2 = system2; - this.permissionTemplateService = permissionTemplateService; - this.favoriteUpdater = favoriteUpdater; - this.projectIndexers = projectIndexers; - } - - /** - * - Create component - * - Apply default permission template - * - Add component to favorite if the component has the 'Project Creators' permission - * - Index component in es indexes - */ - public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable Integer userId) { - ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userId); - commitAndIndex(dbSession, componentDto); - return componentDto; - } - - /** - * Create component without committing. - * Don't forget to call commitAndIndex(...) when ready to commit. - */ - public ComponentDto createWithoutCommit(DbSession dbSession, NewComponent newComponent, @Nullable Integer userId) { - checkKeyFormat(newComponent.qualifier(), newComponent.key()); - ComponentDto componentDto = createRootComponent(dbSession, newComponent); - if (isRootProject(componentDto)) { - createMainBranch(dbSession, componentDto.uuid()); - } - handlePermissionTemplate(dbSession, componentDto, userId); - return componentDto; - } - - public void commitAndIndex(DbSession dbSession, ComponentDto componentDto) { - projectIndexers.commitAndIndex(dbSession, singletonList(componentDto), Cause.PROJECT_CREATION); - } - - private ComponentDto createRootComponent(DbSession session, NewComponent newComponent) { - checkRequest(!dbClient.componentDao().selectByKey(session, newComponent.key()).isPresent(), - "Could not create %s, key already exists: %s", getQualifierToDisplay(newComponent.qualifier()), newComponent.key()); - - String uuid = Uuids.create(); - ComponentDto component = new ComponentDto() - .setOrganizationUuid(newComponent.getOrganizationUuid()) - .setUuid(uuid) - .setUuidPath(ComponentDto.UUID_PATH_OF_ROOT) - .setRootUuid(uuid) - .setModuleUuid(null) - .setModuleUuidPath(ComponentDto.UUID_PATH_SEPARATOR + uuid + ComponentDto.UUID_PATH_SEPARATOR) - .setProjectUuid(uuid) - .setDbKey(newComponent.key()) - .setName(newComponent.name()) - .setLongName(newComponent.name()) - .setScope(Scopes.PROJECT) - .setQualifier(newComponent.qualifier()) - .setPrivate(newComponent.isPrivate()) - .setCreatedAt(new Date(system2.now())); - dbClient.componentDao().insert(session, component); - - return component; - } - - private static boolean isRootProject(ComponentDto componentDto) { - return Scopes.PROJECT.equals(componentDto.scope()) - && MAIN_BRANCH_QUALIFIERS.contains(componentDto.qualifier()); - } - - private void createMainBranch(DbSession session, String componentUuid) { - BranchDto branch = new BranchDto() - .setBranchType(BranchType.LONG) - .setUuid(componentUuid) - .setKey(BranchDto.DEFAULT_MAIN_BRANCH_NAME) - .setMergeBranchUuid(null) - .setProjectUuid(componentUuid); - dbClient.branchDao().upsert(session, branch); - } - - private void handlePermissionTemplate(DbSession dbSession, ComponentDto componentDto, @Nullable Integer userId) { - permissionTemplateService.applyDefault(dbSession, componentDto, userId); - if (componentDto.qualifier().equals(PROJECT) - && permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(dbSession, componentDto)) { - favoriteUpdater.add(dbSession, componentDto, userId, false); - } - } - - private void checkKeyFormat(String qualifier, String key) { - checkRequest(isValidProjectKey(key), "Malformed key for %s: '%s'. It cannot be empty nor contain whitespaces.", getQualifierToDisplay(qualifier), key); - } - - private String getQualifierToDisplay(String qualifier) { - return i18n.message(Locale.getDefault(), "qualifier." + qualifier, "Project"); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/NewComponent.java b/server/sonar-server/src/main/java/org/sonar/server/component/NewComponent.java deleted file mode 100644 index 75c0d962f50..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/NewComponent.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import javax.annotation.concurrent.Immutable; - -import static java.util.Objects.requireNonNull; -import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.db.component.ComponentValidator.checkComponentKey; -import static org.sonar.db.component.ComponentValidator.checkComponentName; -import static org.sonar.db.component.ComponentValidator.checkComponentQualifier; - -@Immutable -public class NewComponent { - private final String organizationUuid; - private final String key; - private final String qualifier; - private final String name; - private final boolean isPrivate; - - private NewComponent(NewComponent.Builder builder) { - this.organizationUuid = builder.organizationUuid; - this.key = builder.key; - this.qualifier = builder.qualifier; - this.name = builder.name; - this.isPrivate = builder.isPrivate; - } - - public static Builder newComponentBuilder() { - return new Builder(); - } - - public String getOrganizationUuid() { - return organizationUuid; - } - - public String key() { - return key; - } - - public String name() { - return name; - } - - public String qualifier() { - return qualifier; - } - - public boolean isPrivate() { - return isPrivate; - } - - public static class Builder { - private String organizationUuid; - private String key; - private String qualifier = PROJECT; - private String name; - private boolean isPrivate = false; - - private Builder() { - // use static factory method newComponentBuilder() - } - - public Builder setOrganizationUuid(String organizationUuid) { - this.organizationUuid = organizationUuid; - return this; - } - - public Builder setKey(String key) { - this.key = key; - return this; - } - - public Builder setQualifier(String qualifier) { - this.qualifier = qualifier; - return this; - } - - public Builder setName(String name) { - this.name = name; - return this; - } - - public Builder setPrivate(boolean isPrivate) { - this.isPrivate = isPrivate; - return this; - } - - public NewComponent build() { - requireNonNull(organizationUuid, "organization uuid can't be null"); - checkComponentKey(key); - checkComponentName(name); - checkComponentQualifier(qualifier); - return new NewComponent(this); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/component/package-info.java deleted file mode 100644 index 82634a5336a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/component/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/favorite/FavoriteFinder.java b/server/sonar-server/src/main/java/org/sonar/server/favorite/FavoriteFinder.java deleted file mode 100644 index 0a75c3df70f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/favorite/FavoriteFinder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.favorite; - -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.property.PropertyDto; -import org.sonar.db.property.PropertyQuery; -import org.sonar.server.user.UserSession; - -import static java.util.Collections.emptyList; -import static org.sonar.core.util.stream.MoreCollectors.toList; -import static org.sonar.server.favorite.FavoriteUpdater.PROP_FAVORITE_KEY; - -public class FavoriteFinder { - private final DbClient dbClient; - private final UserSession userSession; - - public FavoriteFinder(DbClient dbClient, UserSession userSession) { - this.dbClient = dbClient; - this.userSession = userSession; - } - - /** - * @return the list of favorite components of the authenticated user. Empty list if the user is not authenticated - */ - public List<ComponentDto> list() { - if (!userSession.isLoggedIn()) { - return emptyList(); - } - - try (DbSession dbSession = dbClient.openSession(false)) { - PropertyQuery dbQuery = PropertyQuery.builder() - .setKey(PROP_FAVORITE_KEY) - .setUserId(userSession.getUserId()) - .build(); - Set<Long> componentIds = dbClient.propertiesDao().selectByQuery(dbQuery, dbSession).stream().map(PropertyDto::getResourceId).collect(Collectors.toSet()); - - return dbClient.componentDao().selectByIds(dbSession, componentIds).stream() - .sorted(Comparator.comparing(ComponentDto::name)) - .collect(toList()); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/favorite/FavoriteModule.java b/server/sonar-server/src/main/java/org/sonar/server/favorite/FavoriteModule.java deleted file mode 100644 index fa5805627c0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/favorite/FavoriteModule.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.favorite; - -import org.sonar.core.platform.Module; - -public class FavoriteModule extends Module { - - @Override - protected void configureModule() { - add( - FavoriteFinder.class, - FavoriteUpdater.class - - ); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/favorite/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/favorite/package-info.java deleted file mode 100644 index 323232ae563..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/favorite/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.favorite; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/AppNodeClusterCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/AppNodeClusterCheck.java deleted file mode 100644 index c0667dd3363..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/AppNodeClusterCheck.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Arrays; -import java.util.Set; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; - -import static org.sonar.core.util.stream.MoreCollectors.toSet; -import static org.sonar.process.cluster.health.NodeHealth.Status.GREEN; -import static org.sonar.process.cluster.health.NodeHealth.Status.RED; -import static org.sonar.process.cluster.health.NodeHealth.Status.YELLOW; -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -public class AppNodeClusterCheck implements ClusterHealthCheck { - - @Override - public Health check(Set<NodeHealth> nodeHealths) { - Set<NodeHealth> appNodes = nodeHealths.stream() - .filter(s -> s.getDetails().getType() == NodeDetails.Type.APPLICATION) - .collect(toSet()); - - return Arrays.stream(AppNodeClusterHealthSubChecks.values()) - .map(s -> s.check(appNodes)) - .reduce(Health.GREEN, HealthReducer.INSTANCE); - } - - private enum AppNodeClusterHealthSubChecks implements ClusterHealthSubCheck { - NO_APPLICATION_NODE() { - @Override - public Health check(Set<NodeHealth> appNodes) { - int appNodeCount = appNodes.size(); - if (appNodeCount == 0) { - return newHealthCheckBuilder() - .setStatus(Health.Status.RED) - .addCause("No application node") - .build(); - } - return Health.GREEN; - } - }, - MIN_APPLICATION_NODE_COUNT() { - @Override - public Health check(Set<NodeHealth> appNodes) { - int appNodeCount = appNodes.size(); - if (appNodeCount == 1) { - return newHealthCheckBuilder() - .setStatus(Health.Status.YELLOW) - .addCause("There should be at least two application nodes") - .build(); - } - return Health.GREEN; - } - }, - REPORT_RED_OR_YELLOW_NODES() { - @Override - public Health check(Set<NodeHealth> appNodes) { - int appNodeCount = appNodes.size(); - if (appNodeCount == 0) { - // skipping this check - return Health.GREEN; - } - - long redNodesCount = withStatus(appNodes, RED).count(); - long yellowNodesCount = withStatus(appNodes, YELLOW).count(); - if (redNodesCount == 0 && yellowNodesCount == 0) { - return Health.GREEN; - } - - Health.Builder builder = newHealthCheckBuilder(); - if (redNodesCount == appNodeCount) { - return builder - .setStatus(Health.Status.RED) - .addCause("Status of all application nodes is RED") - .build(); - } else if (redNodesCount > 0) { - builder.addCause("At least one application node is RED"); - } - if (yellowNodesCount == appNodeCount) { - return builder - .setStatus(Health.Status.YELLOW) - .addCause("Status of all application nodes is YELLOW") - .build(); - } else if (yellowNodesCount > 0) { - builder.addCause("At least one application node is YELLOW"); - } - long greenNodesCount = withStatus(appNodes, GREEN).count(); - builder.setStatus(greenNodesCount > 0 || yellowNodesCount > 0 ? Health.Status.YELLOW : Health.Status.RED); - - return builder.build(); - } - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/CeStatusNodeCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/CeStatusNodeCheck.java deleted file mode 100644 index 90d42e048c4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/CeStatusNodeCheck.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.sonar.server.app.ProcessCommandWrapper; - -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -public class CeStatusNodeCheck implements NodeHealthCheck { - private static final Health RED_HEALTH = newHealthCheckBuilder() - .setStatus(Health.Status.RED) - .addCause("Compute Engine is not operational") - .build(); - - private final ProcessCommandWrapper processCommandWrapper; - - public CeStatusNodeCheck(ProcessCommandWrapper processCommandWrapper) { - this.processCommandWrapper = processCommandWrapper; - } - - @Override - public Health check() { - if (processCommandWrapper.isCeOperational()) { - return Health.GREEN; - } - - return RED_HEALTH; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java b/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java deleted file mode 100644 index 23fcfca9f7a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import org.sonar.process.cluster.health.NodeHealth; - -import static com.google.common.collect.ImmutableSet.copyOf; -import static java.util.Objects.requireNonNull; - -public class ClusterHealth { - private final Health health; - private final Set<NodeHealth> nodes; - - public ClusterHealth(Health health, Set<NodeHealth> nodes) { - this.health = requireNonNull(health, "health can't be null"); - this.nodes = copyOf(requireNonNull(nodes, "nodes can't be null")); - } - - public Health getHealth() { - return health; - } - - public Set<NodeHealth> getNodes() { - return nodes; - } - - public Optional<NodeHealth> getNodeHealth(String nodeName) { - return nodes.stream() - .filter(node -> nodeName.equals(node.getDetails().getName())) - .findFirst(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ClusterHealth that = (ClusterHealth) o; - return Objects.equals(health, that.health) && - Objects.equals(nodes, that.nodes); - } - - @Override - public int hashCode() { - return Objects.hash(health, nodes); - } - - @Override - public String toString() { - return "ClusterHealth{" + - "health=" + health + - ", nodes=" + nodes + - '}'; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealthCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealthCheck.java deleted file mode 100644 index 66718d4778e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealthCheck.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Set; -import org.sonar.process.cluster.health.NodeHealth; - -public interface ClusterHealthCheck { - Health check(Set<NodeHealth> nodeHealths); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealthSubCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealthSubCheck.java deleted file mode 100644 index a9849d135f6..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealthSubCheck.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Set; -import java.util.stream.Stream; -import org.sonar.process.cluster.health.NodeHealth; - -interface ClusterHealthSubCheck extends ClusterHealthCheck { - - default Stream<NodeHealth> withStatus(Set<NodeHealth> searchNodes, NodeHealth.Status... statuses) { - return searchNodes.stream() - .filter(t -> { - for (NodeHealth.Status status : statuses) { - if (status == t.getStatus()) { - return true; - } - } - return false; - }); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/DbConnectionNodeCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/DbConnectionNodeCheck.java deleted file mode 100644 index bbaa3d5fccd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/DbConnectionNodeCheck.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.IsAliveMapper; - -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -/** - * Checks Web Server can connect to the Database. - */ -public class DbConnectionNodeCheck implements NodeHealthCheck { - private static final Logger LOGGER = Loggers.get(DbConnectionNodeCheck.class); - private static final Health RED_HEALTH = newHealthCheckBuilder().setStatus(Health.Status.RED).addCause("Can't connect to DB").build(); - - private final DbClient dbClient; - - public DbConnectionNodeCheck(DbClient dbClient) { - this.dbClient = dbClient; - } - - @Override - public Health check() { - if (isConnectedToDB()) { - return Health.GREEN; - } - return RED_HEALTH; - } - - private boolean isConnectedToDB() { - try (DbSession dbSession = dbClient.openSession(false)) { - return dbSession.getMapper(IsAliveMapper.class).isAlive() == IsAliveMapper.IS_ALIVE_RETURNED_VALUE; - } catch (RuntimeException e) { - LOGGER.trace("DB connection is down: {}", e); - return false; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusCheck.java deleted file mode 100644 index 1dbc5fc21ab..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusCheck.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.elasticsearch.cluster.health.ClusterHealthStatus; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.server.es.EsClient; - -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -abstract class EsStatusCheck { - private static final Logger LOG = Loggers.get(EsStatusCheck.class); - - private static final Health YELLOW_HEALTH = newHealthCheckBuilder() - .setStatus(Health.Status.YELLOW) - .addCause("Elasticsearch status is YELLOW") - .build(); - private static final Health RED_HEALTH = newHealthCheckBuilder() - .setStatus(Health.Status.RED) - .addCause("Elasticsearch status is RED") - .build(); - private static final Health RED_HEALTH_UNAVAILABLE = newHealthCheckBuilder() - .setStatus(Health.Status.RED) - .addCause("Elasticsearch status is RED (unavailable)") - .build(); - - private final EsClient esClient; - - EsStatusCheck(EsClient esClient) { - this.esClient = esClient; - } - - Health checkEsStatus() { - try { - ClusterHealthStatus esStatus = esClient.prepareClusterStats().get().getStatus(); - if (esStatus == null) { - return RED_HEALTH_UNAVAILABLE; - } - switch (esStatus) { - case GREEN: - return Health.GREEN; - case YELLOW: - return YELLOW_HEALTH; - case RED: - return RED_HEALTH; - default: - throw new IllegalArgumentException("Unsupported Elasticsearch status " + esStatus); - } - } catch (Exception e) { - LOG.error("Failed to query ES status", e); - return RED_HEALTH_UNAVAILABLE; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusClusterCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusClusterCheck.java deleted file mode 100644 index 74df9fd3e50..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusClusterCheck.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Set; -import org.sonar.process.cluster.health.NodeHealth; -import org.sonar.server.es.EsClient; - -public class EsStatusClusterCheck extends EsStatusCheck implements ClusterHealthCheck { - - public EsStatusClusterCheck(EsClient esClient) { - super(esClient); - } - - @Override - public Health check(Set<NodeHealth> nodeHealths) { - return checkEsStatus(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusNodeCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusNodeCheck.java deleted file mode 100644 index 3bfbbaf2c08..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/EsStatusNodeCheck.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.sonar.server.es.EsClient; - -/** - * Checks the ElasticSearch cluster status. - */ -public class EsStatusNodeCheck extends EsStatusCheck implements NodeHealthCheck { - - public EsStatusNodeCheck(EsClient esClient) { - super(esClient); - } - - @Override - public Health check() { - return super.checkEsStatus(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/Health.java b/server/sonar-server/src/main/java/org/sonar/server/health/Health.java deleted file mode 100644 index d5b49449bbe..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/Health.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import com.google.common.collect.ImmutableSet; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; - -public class Health { - /** - * The GREEN status without any cause as a constant, for convenience and optimisation. - */ - public static final Health GREEN = newHealthCheckBuilder() - .setStatus(Status.GREEN) - .build(); - - private final Status status; - private final Set<String> causes; - - public Health(Builder builder) { - this.status = builder.status; - this.causes = ImmutableSet.copyOf(builder.causes); - } - - public Status getStatus() { - return status; - } - - public Set<String> getCauses() { - return causes; - } - - public static Builder newHealthCheckBuilder() { - return new Builder(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Health health = (Health) o; - return status == health.status && - Objects.equals(causes, health.causes); - } - - @Override - public int hashCode() { - return Objects.hash(status, causes); - } - - @Override - public String toString() { - return "Health{" + status + - ", causes=" + causes + - '}'; - } - - /** - * Builder of {@link Health} which supports being reused for optimization. - */ - public static class Builder { - private Status status; - private Set<String> causes = new HashSet<>(0); - - private Builder() { - // use static factory method - } - - public Builder clear() { - this.status = null; - this.causes.clear(); - return this; - } - - public Builder setStatus(Status status) { - this.status = checkStatus(status); - return this; - } - - public Builder addCause(String cause) { - requireNonNull(cause, "cause can't be null"); - checkArgument(!cause.trim().isEmpty(), "cause can't be empty"); - causes.add(cause); - return this; - } - - public Health build() { - checkStatus(this.status); - return new Health(this); - } - - private static Status checkStatus(Status status) { - return requireNonNull(status, "status can't be null"); - } - } - - public enum Status { - /** - * Fully working - */ - GREEN, - /** - * Yellow: Working but something must be fixed to make SQ fully operational - */ - YELLOW, - /** - * Red: Not working - */ - RED - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/HealthChecker.java b/server/sonar-server/src/main/java/org/sonar/server/health/HealthChecker.java deleted file mode 100644 index 80fb8aed1bf..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/HealthChecker.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -public interface HealthChecker { - /** - * Perform a check of the health of the current SonarQube node, either as a standalone node or as a member - * of a cluster. - */ - Health checkNode(); - - /** - * Perform a check of the health of the SonarQube cluster. - * - * @throws IllegalStateException if clustering is not enabled. - */ - ClusterHealth checkCluster(); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/HealthCheckerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/health/HealthCheckerImpl.java deleted file mode 100644 index eee06d3e35d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/HealthCheckerImpl.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.List; -import java.util.Set; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.process.cluster.health.NodeHealth; -import org.sonar.process.cluster.health.SharedHealthState; -import org.sonar.server.platform.WebServer; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableList.copyOf; - -/** - * Implementation of {@link HealthChecker} based on {@link NodeHealthCheck} and {@link ClusterHealthCheck} instances - * available in the container. - */ -public class HealthCheckerImpl implements HealthChecker { - private final WebServer webServer; - private final List<NodeHealthCheck> nodeHealthChecks; - private final List<ClusterHealthCheck> clusterHealthChecks; - @CheckForNull - private final SharedHealthState sharedHealthState; - - /** - * Constructor used by Pico in standalone mode and in safe mode. - */ - public HealthCheckerImpl(WebServer webServer, NodeHealthCheck[] nodeHealthChecks) { - this(webServer, nodeHealthChecks, new ClusterHealthCheck[0], null); - } - - /** - * Constructor used by Pico in cluster mode. - */ - public HealthCheckerImpl(WebServer webServer, NodeHealthCheck[] nodeHealthChecks, ClusterHealthCheck[] clusterHealthChecks, - @Nullable SharedHealthState sharedHealthState) { - this.webServer = webServer; - this.nodeHealthChecks = copyOf(nodeHealthChecks); - this.clusterHealthChecks = copyOf(clusterHealthChecks); - this.sharedHealthState = sharedHealthState; - } - - @Override - public Health checkNode() { - return nodeHealthChecks.stream() - .map(NodeHealthCheck::check) - .reduce(Health.GREEN, HealthReducer.INSTANCE); - } - - @Override - public ClusterHealth checkCluster() { - checkState(!webServer.isStandalone(), "Clustering is not enabled"); - checkState(sharedHealthState != null, "HealthState instance can't be null when clustering is enabled"); - - Set<NodeHealth> nodeHealths = sharedHealthState.readAll(); - Health health = clusterHealthChecks.stream() - .map(clusterHealthCheck -> clusterHealthCheck.check(nodeHealths)) - .reduce(Health.GREEN, HealthReducer.INSTANCE); - return new ClusterHealth(health, nodeHealths); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/HealthReducer.java b/server/sonar-server/src/main/java/org/sonar/server/health/HealthReducer.java deleted file mode 100644 index 3f5d1d30b4f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/HealthReducer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.function.BinaryOperator; -import java.util.stream.Stream; - -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -public enum HealthReducer implements BinaryOperator<Health> { - INSTANCE; - - /** - * According to Javadoc, {@link BinaryOperator} used in method - * {@link java.util.stream.Stream#reduce(Object, BinaryOperator)} is supposed to be stateless. - * - * But as we are sure this {@link BinaryOperator} won't be used on a Stream with {@link Stream#parallel()} - * feature on, we allow ourselves this optimisation. - */ - private final Health.Builder builder = newHealthCheckBuilder(); - - @Override - public Health apply(Health left, Health right) { - builder.clear(); - builder.setStatus(worseOf(left.getStatus(), right.getStatus())); - left.getCauses().forEach(builder::addCause); - right.getCauses().forEach(builder::addCause); - return builder.build(); - } - - private static Health.Status worseOf(Health.Status left, Health.Status right) { - if (left == right) { - return left; - } - if (left.ordinal() > right.ordinal()) { - return left; - } - return right; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/HealthStateRefresherExecutorServiceImpl.java b/server/sonar-server/src/main/java/org/sonar/server/health/HealthStateRefresherExecutorServiceImpl.java deleted file mode 100644 index 03abdd08cca..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/HealthStateRefresherExecutorServiceImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.sonar.process.cluster.health.HealthStateRefresherExecutorService; -import org.sonar.server.util.AbstractStoppableScheduledExecutorServiceImpl; - -public class HealthStateRefresherExecutorServiceImpl - extends AbstractStoppableScheduledExecutorServiceImpl<ScheduledExecutorService> - implements HealthStateRefresherExecutorService { - public HealthStateRefresherExecutorServiceImpl() { - super(Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder() - .setDaemon(false) - .setNameFormat("health_state_refresh-%d") - .build())); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthCheck.java deleted file mode 100644 index 5955347d089..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthCheck.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -public interface NodeHealthCheck { - Health check(); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthModule.java b/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthModule.java deleted file mode 100644 index 870eae9ae5d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthModule.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.sonar.core.platform.Module; -import org.sonar.process.cluster.health.HealthStateRefresher; -import org.sonar.process.cluster.health.SharedHealthStateImpl; - -public class NodeHealthModule extends Module { - @Override - protected void configureModule() { - add( - NodeHealthProviderImpl.class, - HealthStateRefresherExecutorServiceImpl.class, - HealthStateRefresher.class, - SharedHealthStateImpl.class); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthProviderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthProviderImpl.java deleted file mode 100644 index 237bb94994b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/NodeHealthProviderImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.function.Supplier; -import org.sonar.api.config.Configuration; -import org.sonar.api.platform.Server; -import org.sonar.process.NetworkUtils; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; -import org.sonar.process.cluster.health.NodeHealthProvider; - -import static java.lang.String.format; -import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_HOST; -import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME; -import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_HZ_PORT; -import static org.sonar.process.cluster.health.NodeDetails.newNodeDetailsBuilder; -import static org.sonar.process.cluster.health.NodeHealth.newNodeHealthBuilder; - -public class NodeHealthProviderImpl implements NodeHealthProvider { - private final HealthChecker healthChecker; - private final NodeHealth.Builder nodeHealthBuilder; - private final NodeDetails nodeDetails; - - public NodeHealthProviderImpl(Configuration configuration, HealthChecker healthChecker, Server server, NetworkUtils networkUtils) { - this.healthChecker = healthChecker; - this.nodeHealthBuilder = newNodeHealthBuilder(); - this.nodeDetails = newNodeDetailsBuilder() - .setName(computeName(configuration)) - .setType(NodeDetails.Type.APPLICATION) - .setHost(computeHost(configuration, networkUtils)) - .setPort(computePort(configuration)) - .setStartedAt(server.getStartedAt().getTime()) - .build(); - } - - private static String computeName(Configuration configuration) { - return configuration.get(CLUSTER_NODE_NAME.getKey()) - .orElseThrow(missingPropertyISE(CLUSTER_NODE_NAME.getKey())); - } - - private static String computeHost(Configuration configuration, NetworkUtils networkUtils) { - return configuration.get(CLUSTER_NODE_HOST.getKey()) - .filter(s -> !s.isEmpty()) - .orElseGet(networkUtils::getHostname); - } - - private static int computePort(Configuration configuration) { - return configuration.getInt(CLUSTER_NODE_HZ_PORT.getKey()) - .orElseThrow(missingPropertyISE(CLUSTER_NODE_HZ_PORT.getKey())); - } - - private static Supplier<IllegalStateException> missingPropertyISE(String propertyName) { - return () -> new IllegalStateException(format("Property %s is not defined", propertyName)); - } - - @Override - public NodeHealth get() { - Health nodeHealth = healthChecker.checkNode(); - this.nodeHealthBuilder - .clearCauses() - .setStatus(NodeHealth.Status.valueOf(nodeHealth.getStatus().name())); - nodeHealth.getCauses().forEach(this.nodeHealthBuilder::addCause); - - return this.nodeHealthBuilder - .setDetails(nodeDetails) - .build(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/WebServerSafemodeNodeCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/WebServerSafemodeNodeCheck.java deleted file mode 100644 index 2ee3f57e9e8..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/WebServerSafemodeNodeCheck.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -/** - * Checks the running status of the WebServer when the WebServer is in safemode. - * Obviously, it statically returns a red health status. - */ -public class WebServerSafemodeNodeCheck implements NodeHealthCheck { - - private static final Health RED_HEALTH = newHealthCheckBuilder() - .setStatus(Health.Status.RED) - .addCause("SonarQube webserver is not up") - .build(); - - @Override - public Health check() { - return RED_HEALTH; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/WebServerStatusNodeCheck.java b/server/sonar-server/src/main/java/org/sonar/server/health/WebServerStatusNodeCheck.java deleted file mode 100644 index b25525337f0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/WebServerStatusNodeCheck.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.EnumSet; -import org.sonar.server.app.RestartFlagHolder; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.db.migration.DatabaseMigrationState; - -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -/** - * Checks the running status of the WebServer when it is not anymore in safemode. - */ -public class WebServerStatusNodeCheck implements NodeHealthCheck { - private static final EnumSet<DatabaseMigrationState.Status> VALID_DATABASEMIGRATION_STATUSES = EnumSet.of( - DatabaseMigrationState.Status.NONE, DatabaseMigrationState.Status.SUCCEEDED); - - private final DatabaseMigrationState migrationState; - private final Platform platform; - private final RestartFlagHolder restartFlagHolder; - - public WebServerStatusNodeCheck(DatabaseMigrationState migrationState, Platform platform, RestartFlagHolder restartFlagHolder) { - this.migrationState = migrationState; - this.platform = platform; - this.restartFlagHolder = restartFlagHolder; - } - - @Override - public Health check() { - Platform.Status platformStatus = platform.status(); - if (platformStatus == Platform.Status.UP - && VALID_DATABASEMIGRATION_STATUSES.contains(migrationState.getStatus()) - && !restartFlagHolder.isRestarting()) { - return Health.GREEN; - } - return newHealthCheckBuilder() - .setStatus(Health.Status.RED) - .addCause("SonarQube webserver is not up") - .build(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/health/package-info.java deleted file mode 100644 index 18ea762c56b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/health/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java deleted file mode 100644 index 8f15fc7aa74..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.base.Splitter; -import com.google.common.base.Strings; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import org.sonar.server.issue.workflow.IsUnResolved; -import org.sonar.api.server.ServerSide; -import org.sonar.api.server.rule.RuleTagFormat; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.server.user.UserSession; - -@ServerSide -public abstract class AbstractChangeTagsAction extends Action { - - public static final String TAGS_PARAMETER = "tags"; - - private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); - - private final IssueFieldsSetter issueUpdater; - - protected AbstractChangeTagsAction(String key, IssueFieldsSetter issueUpdater) { - super(key); - this.issueUpdater = issueUpdater; - super.setConditions(new IsUnResolved()); - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - parseTags(properties); - return true; - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - Collection<String> tags = getTagsToSet(context, parseTags(properties)); - return issueUpdater.setTags(context.issue(), tags, context.issueChangeContext()); - } - - protected abstract Collection<String> getTagsToSet(Context context, Collection<String> tagsFromParams); - - @Override - public boolean shouldRefreshMeasures() { - return false; - } - - private Set<String> parseTags(Map<String, Object> properties) { - Set<String> result = new HashSet<>(); - String tagsString = (String) properties.get(TAGS_PARAMETER); - if (!Strings.isNullOrEmpty(tagsString)) { - for (String tag : TAGS_SPLITTER.split(tagsString)) { - RuleTagFormat.validate(tag); - result.add(tag); - } - } - return result; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java b/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java deleted file mode 100644 index f409a82b30c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import org.sonar.api.server.ServerSide; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.issue.workflow.Condition; -import org.sonar.server.user.UserSession; - -import static com.google.common.collect.Lists.newArrayList; - -/** - * @since 3.7 - */ -@ServerSide -public abstract class Action { - - private final String key; - private final List<Condition> conditions; - - public Action(String key) { - Preconditions.checkArgument(!Strings.isNullOrEmpty(key), "Action key must be set"); - this.key = key; - this.conditions = newArrayList(); - } - - public String key() { - return key; - } - - public Action setConditions(Condition... conditions) { - this.conditions.addAll(ImmutableList.copyOf(conditions)); - return this; - } - - public List<Condition> conditions() { - return conditions; - } - - public boolean supports(DefaultIssue issue) { - for (Condition condition : conditions) { - if (!condition.matches(issue)) { - return false; - } - } - return true; - } - - public abstract boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession); - - public abstract boolean execute(Map<String, Object> properties, Context context); - - public abstract boolean shouldRefreshMeasures(); - - public interface Context { - DefaultIssue issue(); - - IssueChangeContext issueChangeContext(); - - ComponentDto project(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ActionContext.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ActionContext.java deleted file mode 100644 index 9f9a12368fe..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ActionContext.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.component.ComponentDto; - -public class ActionContext implements Action.Context { - private final DefaultIssue issue; - private final IssueChangeContext changeContext; - private final ComponentDto project; - - public ActionContext(DefaultIssue issue, IssueChangeContext changeContext, ComponentDto project) { - this.issue = issue; - this.changeContext = changeContext; - this.project = project; - } - - @Override - public DefaultIssue issue() { - return issue; - } - - @Override - public IssueChangeContext issueChangeContext() { - return changeContext; - } - - @Override - public ComponentDto project() { - return project; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/AddTagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/AddTagsAction.java deleted file mode 100644 index 27b46a86c93..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/AddTagsAction.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import org.sonar.api.server.ServerSide; - -@ServerSide -public class AddTagsAction extends AbstractChangeTagsAction { - - public static final String KEY = "add_tags"; - - public AddTagsAction(IssueFieldsSetter issueUpdater) { - super(KEY, issueUpdater); - } - - @Override - protected Collection<String> getTagsToSet(Context context, Collection<String> tagsFromParams) { - Set<String> allTags = new HashSet<>(context.issue().tags()); - allTags.addAll(tagsFromParams); - return allTags; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java deleted file mode 100644 index 884fad73b69..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nullable; -import org.sonar.api.server.ServerSide; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.user.UserDto; -import org.sonar.server.issue.workflow.IsUnResolved; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Strings.isNullOrEmpty; -import static org.sonar.server.exceptions.NotFoundException.checkFound; - -@ServerSide -public class AssignAction extends Action { - - public static final String ASSIGN_KEY = "assign"; - public static final String ASSIGNEE_PARAMETER = "assignee"; - private static final String VERIFIED_ASSIGNEE = "verifiedAssignee"; - private static final String ASSIGNEE_ORGANIZATIONS = "assigneeOrganizationUuids"; - - private final DbClient dbClient; - private final IssueFieldsSetter issueFieldsSetter; - - public AssignAction(DbClient dbClient, IssueFieldsSetter issueFieldsSetter) { - super(ASSIGN_KEY); - this.dbClient = dbClient; - this.issueFieldsSetter = issueFieldsSetter; - super.setConditions(new IsUnResolved()); - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - String assigneeLogin = getAssigneeValue(properties); - UserDto assignee = isNullOrEmpty(assigneeLogin) ? null : getUser(assigneeLogin); - properties.put(VERIFIED_ASSIGNEE, assignee); - properties.put(ASSIGNEE_ORGANIZATIONS, loadUserOrganizations(assignee)); - return true; - } - - private static String getAssigneeValue(Map<String, Object> properties) { - return (String) properties.get(ASSIGNEE_PARAMETER); - } - - private UserDto getUser(String assigneeKey) { - try (DbSession dbSession = dbClient.openSession(false)) { - return checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, assigneeKey), "Unknown user: %s", assigneeKey); - } - } - - private Set<String> loadUserOrganizations(@Nullable UserDto assignee) { - if (assignee == null) { - return Collections.emptySet(); - } - try (DbSession dbSession = dbClient.openSession(false)) { - return dbClient.organizationMemberDao().selectOrganizationUuidsByUser(dbSession, assignee.getId()); - } - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - checkArgument(properties.containsKey(VERIFIED_ASSIGNEE), "Assignee is missing from the execution parameters"); - UserDto assignee = (UserDto) properties.get(VERIFIED_ASSIGNEE); - return isAssigneeMemberOfIssueOrganization(assignee, properties, context) && issueFieldsSetter.assign(context.issue(), assignee, context.issueChangeContext()); - } - - @Override - public boolean shouldRefreshMeasures() { - return false; - } - - private static boolean isAssigneeMemberOfIssueOrganization(@Nullable UserDto assignee, Map<String, Object> properties, Context context) { - return assignee == null || ((Set<String>) properties.get(ASSIGNEE_ORGANIZATIONS)).contains(context.project().getOrganizationUuid()); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java deleted file mode 100644 index 1f0e2b573f0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.base.Strings; -import java.util.Collection; -import java.util.Map; -import org.sonar.api.server.ServerSide; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.server.user.UserSession; - -@ServerSide -public class CommentAction extends Action { - - public static final String COMMENT_KEY = "comment"; - public static final String COMMENT_PROPERTY = "comment"; - - private final IssueFieldsSetter issueUpdater; - - public CommentAction(IssueFieldsSetter issueUpdater) { - super(COMMENT_KEY); - this.issueUpdater = issueUpdater; - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - comment(properties); - return true; - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - issueUpdater.addComment(context.issue(), comment(properties), context.issueChangeContext()); - return true; - } - - @Override - public boolean shouldRefreshMeasures() { - return false; - } - - private static String comment(Map<String, Object> properties) { - String param = (String) properties.get(COMMENT_PROPERTY); - if (Strings.isNullOrEmpty(param)) { - throw new IllegalArgumentException("Missing parameter : '" + COMMENT_PROPERTY + "'"); - } - return param; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangePostProcessor.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangePostProcessor.java deleted file mode 100644 index b19de964705..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangePostProcessor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.List; -import org.sonar.api.server.ServerSide; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; - -@ServerSide -public interface IssueChangePostProcessor { - - /** - * Refresh measures, quality gate status and send webhooks - * - * @param components the components of changed issues - */ - void process(DbSession dbSession, List<DefaultIssue> changedIssues, Collection<ComponentDto> components); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangePostProcessorImpl.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangePostProcessorImpl.java deleted file mode 100644 index b4805d7e34b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangePostProcessorImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.List; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.measure.live.LiveMeasureComputer; -import org.sonar.server.qualitygate.changeevent.QGChangeEvent; -import org.sonar.server.qualitygate.changeevent.QGChangeEventListeners; - -public class IssueChangePostProcessorImpl implements IssueChangePostProcessor { - - private final LiveMeasureComputer liveMeasureComputer; - private final QGChangeEventListeners qualityGateListeners; - - public IssueChangePostProcessorImpl(LiveMeasureComputer liveMeasureComputer, QGChangeEventListeners qualityGateListeners) { - this.liveMeasureComputer = liveMeasureComputer; - this.qualityGateListeners = qualityGateListeners; - } - - @Override - public void process(DbSession dbSession, List<DefaultIssue> changedIssues, Collection<ComponentDto> components) { - List<QGChangeEvent> gateChangeEvents = liveMeasureComputer.refresh(dbSession, components); - qualityGateListeners.broadcastOnIssueChange(changedIssues, gateChangeEvents); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFinder.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFinder.java deleted file mode 100644 index 2ac34416a9b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueFinder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import org.sonar.api.web.UserRole; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.issue.IssueDto; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.user.UserSession; - -import static java.lang.String.format; -import static java.util.Objects.requireNonNull; - -public class IssueFinder { - - private final DbClient dbClient; - private final UserSession userSession; - - public IssueFinder(DbClient dbClient, UserSession userSession) { - this.dbClient = dbClient; - this.userSession = userSession; - } - - public IssueDto getByKey(DbSession session, String issueKey) { - IssueDto issue = dbClient.issueDao().selectByKey(session, issueKey).orElseThrow(() -> new NotFoundException(format("Issue with key '%s' does not exist", issueKey))); - userSession.checkComponentUuidPermission(UserRole.USER, requireNonNull(issue.getProjectUuid())); - return issue; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssuesFinderSort.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssuesFinderSort.java deleted file mode 100644 index 3694122ddfe..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssuesFinderSort.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.base.Function; -import com.google.common.collect.Ordering; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import javax.annotation.Nonnull; -import org.sonar.api.rule.Severity; -import org.sonar.db.issue.IssueDto; -import org.sonar.server.issue.index.IssueQuery; - -/** - * @since 3.6 - */ -class IssuesFinderSort { - - private List<IssueDto> issues; - private IssueQuery query; - - public IssuesFinderSort(List<IssueDto> issues, IssueQuery query) { - this.issues = issues; - this.query = query; - } - - public List<IssueDto> sort() { - String sort = query.sort(); - Boolean asc = query.asc(); - if (sort != null && asc != null) { - return getIssueProcessor(sort).sort(issues, asc); - } - return issues; - } - - private static IssueProcessor getIssueProcessor(String sort) { - if (IssueQuery.SORT_BY_SEVERITY.equals(sort)) { - return new SeveritySortIssueProcessor(); - } - if (IssueQuery.SORT_BY_STATUS.equals(sort)) { - return new StatusSortIssueProcessor(); - } - if (IssueQuery.SORT_BY_CREATION_DATE.equals(sort)) { - return new CreationDateSortIssueProcessor(); - } - if (IssueQuery.SORT_BY_UPDATE_DATE.equals(sort)) { - return new UpdateDateSortIssueProcessor(); - } - if (IssueQuery.SORT_BY_CLOSE_DATE.equals(sort)) { - return new CloseDateSortIssueProcessor(); - } - throw new IllegalArgumentException("Cannot sort on field : " + sort); - } - - interface IssueProcessor { - Function sortFieldFunction(); - - Ordering sortFieldOrdering(boolean ascending); - - default List<IssueDto> sort(Collection<IssueDto> issueDtos, boolean ascending) { - Ordering<IssueDto> ordering = sortFieldOrdering(ascending).onResultOf(sortFieldFunction()); - return ordering.immutableSortedCopy(issueDtos); - } - } - - abstract static class TextSortIssueProcessor implements IssueProcessor { - @Override - public Function sortFieldFunction() { - return new Function<IssueDto, String>() { - @Override - public String apply(IssueDto issueDto) { - return sortField(issueDto); - } - }; - } - - abstract String sortField(IssueDto issueDto); - - @Override - public Ordering sortFieldOrdering(boolean ascending) { - Ordering<String> ordering = Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); - if (!ascending) { - ordering = ordering.reverse(); - } - return ordering; - } - } - - static class StatusSortIssueProcessor extends TextSortIssueProcessor { - @Override - String sortField(IssueDto issueDto) { - return issueDto.getStatus(); - } - } - - static class SeveritySortIssueProcessor implements IssueProcessor { - @Override - public Function sortFieldFunction() { - return IssueDtoToSeverity.INSTANCE; - } - - @Override - public Ordering sortFieldOrdering(boolean ascending) { - Ordering<Integer> ordering = Ordering.<Integer>natural().nullsLast(); - if (!ascending) { - ordering = ordering.reverse(); - } - return ordering; - } - } - - abstract static class DateSortRowProcessor implements IssueProcessor { - @Override - public Function sortFieldFunction() { - return new Function<IssueDto, Date>() { - @Override - public Date apply(IssueDto issueDto) { - return sortField(issueDto); - } - }; - } - - abstract Date sortField(IssueDto issueDto); - - @Override - public Ordering sortFieldOrdering(boolean ascending) { - Ordering<Date> ordering = Ordering.<Date>natural().nullsLast(); - if (!ascending) { - ordering = ordering.reverse(); - } - return ordering; - } - } - - static class CreationDateSortIssueProcessor extends DateSortRowProcessor { - @Override - Date sortField(IssueDto issueDto) { - return issueDto.getIssueCreationDate(); - } - } - - static class UpdateDateSortIssueProcessor extends DateSortRowProcessor { - @Override - Date sortField(IssueDto issueDto) { - return issueDto.getIssueUpdateDate(); - } - } - - static class CloseDateSortIssueProcessor extends DateSortRowProcessor { - @Override - Date sortField(IssueDto issueDto) { - return issueDto.getIssueCloseDate(); - } - } - - private enum IssueDtoToSeverity implements Function<IssueDto, Integer> { - INSTANCE; - - @Override - public Integer apply(@Nonnull IssueDto issueDto) { - return Severity.ALL.indexOf(issueDto.getSeverity()); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/RemoveTagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/RemoveTagsAction.java deleted file mode 100644 index 1d0f1d0d7ac..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/RemoveTagsAction.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import org.sonar.api.server.ServerSide; - -@ServerSide -public class RemoveTagsAction extends AbstractChangeTagsAction { - - public static final String KEY = "remove_tags"; - - public RemoveTagsAction(IssueFieldsSetter issueUpdater) { - super(KEY, issueUpdater); - } - - @Override - protected Collection<String> getTagsToSet(Context context, Collection<String> tagsFromParams) { - Set<String> newTags = new HashSet<>(context.issue().tags()); - newTags.removeAll(tagsFromParams); - return newTags; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/Result.java b/server/sonar-server/src/main/java/org/sonar/server/issue/Result.java deleted file mode 100644 index 4d09fa750ab..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/Result.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Arrays; -import java.util.List; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.apache.commons.lang.builder.ReflectionToStringBuilder; - -import static com.google.common.collect.Lists.newArrayList; - -/** - * @since 3.6 - */ -public class Result<T> { - - private T object = null; - private final List<Message> errors = newArrayList(); - - private Result(@Nullable T object) { - this.object = object; - } - - public static <T> Result<T> of() { - return new Result<>(null); - } - - public Result<T> set(@Nullable T object) { - this.object = object; - return this; - } - - public T get() { - return object; - } - - public Result<T> addError(String text) { - return addError(Message.of(text)); - } - - public Result<T> addError(Message message) { - errors.add(message); - return this; - } - - /** - * List of error messages. Empty if there are no errors. - */ - public List<Message> errors() { - return errors; - } - - /** - * True if there are no errors. - */ - public boolean ok() { - return errors.isEmpty(); - } - - public int httpStatus() { - if (ok()) { - return 200; - } - // TODO support 401, 403 and 500 - return 400; - } - - public static class Message { - private final String l10nKey; - private final Object[] l10nParams; - private final String text; - - private Message(@Nullable String l10nKey, @Nullable Object[] l10nParams, @Nullable String text) { - this.l10nKey = l10nKey; - this.l10nParams = l10nParams; - this.text = text; - } - - public static Message of(String text) { - return new Message(null, null, text); - } - - public static Message ofL10n(String l10nKey, Object... l10nParams) { - return new Message(l10nKey, l10nParams, null); - } - - @CheckForNull - public String text() { - return text; - } - - @CheckForNull - public String l10nKey() { - return l10nKey; - } - - @CheckForNull - public Object[] l10nParams() { - return l10nParams; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Message message = (Message) o; - - if ((l10nKey != null) ? !l10nKey.equals(message.l10nKey) : (message.l10nKey != null)) { - return false; - } - // Probably incorrect - comparing Object[] arrays with Arrays.equals - return Arrays.equals(l10nParams, message.l10nParams) && ((text != null) ? text.equals(message.text) : (message.text == null)); - } - - @Override - public int hashCode() { - int result = l10nKey != null ? l10nKey.hashCode() : 0; - result = 31 * result + (l10nParams != null ? Arrays.hashCode(l10nParams) : 0); - result = 31 * result + (text != null ? text.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return new ReflectionToStringBuilder(this).toString(); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java deleted file mode 100644 index 7bd9b2906b0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.Map; -import org.sonar.api.issue.Issue; -import org.sonar.server.issue.workflow.IsUnResolved; -import org.sonar.api.rules.RuleType; -import org.sonar.api.server.ServerSide; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Strings.isNullOrEmpty; -import static org.sonar.api.web.UserRole.ISSUE_ADMIN; - -@ServerSide -public class SetSeverityAction extends Action { - - public static final String SET_SEVERITY_KEY = "set_severity"; - public static final String SEVERITY_PARAMETER = "severity"; - - private final IssueFieldsSetter issueUpdater; - private final UserSession userSession; - - public SetSeverityAction(IssueFieldsSetter issueUpdater, UserSession userSession) { - super(SET_SEVERITY_KEY); - this.issueUpdater = issueUpdater; - this.userSession = userSession; - super.setConditions(new IsUnResolved(), this::isCurrentUserIssueAdminAndNotSecurityHotspot); - } - - private boolean isCurrentUserIssueAdminAndNotSecurityHotspot(Issue issue) { - DefaultIssue defaultIssue = (DefaultIssue) issue; - return (defaultIssue.type() != RuleType.SECURITY_HOTSPOT && userSession.hasComponentUuidPermission(ISSUE_ADMIN, issue.projectUuid())); - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - verifySeverityParameter(properties); - return true; - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - return issueUpdater.setManualSeverity(context.issue(), verifySeverityParameter(properties), context.issueChangeContext()); - } - - @Override - public boolean shouldRefreshMeasures() { - return true; - } - - private static String verifySeverityParameter(Map<String, Object> properties) { - String param = (String) properties.get(SEVERITY_PARAMETER); - checkArgument(!isNullOrEmpty(param), "Missing parameter : '%s'", SEVERITY_PARAMETER); - return param; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/SetTypeAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/SetTypeAction.java deleted file mode 100644 index fb76d59939a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/SetTypeAction.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.Map; -import org.sonar.api.issue.Issue; -import org.sonar.server.issue.workflow.IsUnResolved; -import org.sonar.api.rules.RuleType; -import org.sonar.api.web.UserRole; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Strings.isNullOrEmpty; - -public class SetTypeAction extends Action { - - public static final String SET_TYPE_KEY = "set_type"; - public static final String TYPE_PARAMETER = "type"; - - private final IssueFieldsSetter issueUpdater; - private final UserSession userSession; - - public SetTypeAction(IssueFieldsSetter issueUpdater, UserSession userSession) { - super(SET_TYPE_KEY); - this.issueUpdater = issueUpdater; - this.userSession = userSession; - super.setConditions(new IsUnResolved(), this::isCurrentUserIssueAdmin); - } - - private boolean isCurrentUserIssueAdmin(Issue issue) { - return !((DefaultIssue) issue).isFromHotspot() && userSession.hasComponentUuidPermission(UserRole.ISSUE_ADMIN, issue.projectUuid()); - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - verifyTypeParameter(properties); - return true; - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - String type = verifyTypeParameter(properties); - return issueUpdater.setType(context.issue(), RuleType.valueOf(type), context.issueChangeContext()); - } - - @Override - public boolean shouldRefreshMeasures() { - return true; - } - - private static String verifyTypeParameter(Map<String, Object> properties) { - String type = (String) properties.get(TYPE_PARAMETER); - checkArgument(!isNullOrEmpty(type), "Missing parameter : '%s'", TYPE_PARAMETER); - checkArgument(RuleType.names().contains(type), "Unknown type : %s", type); - return type; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java deleted file mode 100644 index 9ffe778effe..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.Map; -import org.sonar.api.server.ServerSide; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.server.issue.workflow.Transition; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Strings.isNullOrEmpty; - -@ServerSide -public class TransitionAction extends Action { - - public static final String DO_TRANSITION_KEY = "do_transition"; - public static final String TRANSITION_PARAMETER = "transition"; - - private final TransitionService transitionService; - - public TransitionAction(TransitionService transitionService) { - super(DO_TRANSITION_KEY); - this.transitionService = transitionService; - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - transition(properties); - return true; - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - DefaultIssue issue = context.issue(); - String transition = transition(properties); - return canExecuteTransition(issue, transition) && transitionService.doTransition(context.issue(), context.issueChangeContext(), transition(properties)); - } - - @Override - public boolean shouldRefreshMeasures() { - return true; - } - - private boolean canExecuteTransition(DefaultIssue issue, String transitionKey) { - return transitionService.listTransitions(issue) - .stream() - .map(Transition::key) - .collect(MoreCollectors.toSet()) - .contains(transitionKey); - } - - private static String transition(Map<String, Object> properties) { - String param = (String) properties.get(TRANSITION_PARAMETER); - checkArgument(!isNullOrEmpty(param), "Missing parameter : 'transition'"); - return param; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionService.java deleted file mode 100644 index 1648de2ad78..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionService.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collections; -import java.util.List; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.server.issue.workflow.IssueWorkflow; -import org.sonar.server.issue.workflow.Transition; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; -import static org.apache.commons.lang.StringUtils.isBlank; -import static org.apache.commons.lang.StringUtils.isNotBlank; - -/** - * This service is a kind of overlay of {@link IssueWorkflow} that also deals with permission checking - */ -public class TransitionService { - - private final UserSession userSession; - private final IssueWorkflow workflow; - - public TransitionService(UserSession userSession, IssueWorkflow workflow) { - this.userSession = userSession; - this.workflow = workflow; - } - - public List<Transition> listTransitions(DefaultIssue issue) { - if (issue.isFromExternalRuleEngine()){ - return Collections.emptyList(); - } - String projectUuid = requireNonNull(issue.projectUuid()); - return workflow.outTransitions(issue) - .stream() - .filter(transition -> (userSession.isLoggedIn() && isBlank(transition.requiredProjectPermission())) - || userSession.hasComponentUuidPermission(transition.requiredProjectPermission(), projectUuid)) - .collect(MoreCollectors.toList()); - } - - public boolean doTransition(DefaultIssue defaultIssue, IssueChangeContext issueChangeContext, String transitionKey) { - checkArgument(!defaultIssue.isFromExternalRuleEngine(), "Transition is not allowed on issues imported from external rule engines"); - return workflow.doManualTransition(defaultIssue, transitionKey, issueChangeContext); - } - - public void checkTransitionPermission(String transitionKey, DefaultIssue defaultIssue) { - String projectUuid = requireNonNull(defaultIssue.projectUuid()); - workflow.outTransitions(defaultIssue) - .stream() - .filter(transition -> transition.key().equals(transitionKey) && isNotBlank(transition.requiredProjectPermission())) - .forEach(transition -> userSession.checkComponentUuidPermission(transition.requiredProjectPermission(), projectUuid)); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/WebIssueStorage.java b/server/sonar-server/src/main/java/org/sonar/server/issue/WebIssueStorage.java deleted file mode 100644 index 219a9a9fa39..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/WebIssueStorage.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import javax.annotation.CheckForNull; -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.System2; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.db.BatchSession; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueChangeMapper; -import org.sonar.db.issue.IssueDto; -import org.sonar.server.issue.index.IssueIndexer; - -import static com.google.common.base.MoreObjects.firstNonNull; -import static com.google.common.collect.Lists.newArrayList; -import static java.util.Collections.emptyList; -import static java.util.Objects.requireNonNull; -import static org.sonar.core.util.stream.MoreCollectors.toSet; - -/** - * Save issues into database. It is executed : - * <ul> - * <li>once at the end of scan, even on multi-module projects</li> - * <li>on each server-side action initiated by UI or web service</li> - * </ul> - */ -@ServerSide -public class WebIssueStorage extends IssueStorage { - - private final System2 system2; - private final RuleFinder ruleFinder; - private final DbClient dbClient; - private final IssueIndexer indexer; - - public WebIssueStorage(System2 system2, DbClient dbClient, RuleFinder ruleFinder, IssueIndexer indexer) { - this.system2 = system2; - this.dbClient = dbClient; - this.ruleFinder = ruleFinder; - this.indexer = indexer; - } - - protected DbClient getDbClient() { - return dbClient; - } - - public Collection<IssueDto> save(DbSession dbSession, Iterable<DefaultIssue> issues) { - // Batch session can not be used for updates. It does not return the number of updated rows, - // required for detecting conflicts. - long now = system2.now(); - - Map<Boolean, List<DefaultIssue>> issuesNewOrUpdated = StreamSupport.stream(issues.spliterator(), true).collect(Collectors.groupingBy(DefaultIssue::isNew)); - List<DefaultIssue> issuesToInsert = firstNonNull(issuesNewOrUpdated.get(true), emptyList()); - List<DefaultIssue> issuesToUpdate = firstNonNull(issuesNewOrUpdated.get(false), emptyList()); - - Collection<IssueDto> inserted = insert(dbSession, issuesToInsert, now); - Collection<IssueDto> updated = update(issuesToUpdate, now); - - doAfterSave(dbSession, Stream.concat(inserted.stream(), updated.stream()) - .collect(toSet(issuesToInsert.size() + issuesToUpdate.size()))); - - return Stream.concat(inserted.stream(), updated.stream()) - .collect(toSet(issuesToInsert.size() + issuesToUpdate.size())); - } - - private void doAfterSave(DbSession dbSession, Collection<IssueDto> issues) { - indexer.commitAndIndexIssues(dbSession, issues); - } - - /** - * @return the keys of the inserted issues - */ - private Collection<IssueDto> insert(DbSession session, Iterable<DefaultIssue> issuesToInsert, long now) { - List<IssueDto> inserted = newArrayList(); - int count = 0; - IssueChangeMapper issueChangeMapper = session.getMapper(IssueChangeMapper.class); - for (DefaultIssue issue : issuesToInsert) { - IssueDto issueDto = doInsert(session, now, issue); - inserted.add(issueDto); - insertChanges(issueChangeMapper, issue); - if (count > BatchSession.MAX_BATCH_SIZE) { - session.commit(); - count = 0; - } - count++; - } - session.commit(); - return inserted; - } - - private IssueDto doInsert(DbSession session, long now, DefaultIssue issue) { - ComponentDto component = component(session, issue); - ComponentDto project = project(session, issue); - int ruleId = requireNonNull(getRuleId(issue), "Rule not found: " + issue.ruleKey()); - IssueDto dto = IssueDto.toDtoForServerInsert(issue, component, project, ruleId, now); - - getDbClient().issueDao().insert(session, dto); - return dto; - } - - ComponentDto component(DbSession session, DefaultIssue issue) { - return getDbClient().componentDao().selectOrFailByUuid(session, issue.componentUuid()); - } - - ComponentDto project(DbSession session, DefaultIssue issue) { - return getDbClient().componentDao().selectOrFailByUuid(session, issue.projectUuid()); - } - - /** - * @return the keys of the updated issues - */ - private Collection<IssueDto> update(List<DefaultIssue> issuesToUpdate, long now) { - Collection<IssueDto> updated = new ArrayList<>(); - if (!issuesToUpdate.isEmpty()) { - try (DbSession dbSession = dbClient.openSession(false)) { - IssueChangeMapper issueChangeMapper = dbSession.getMapper(IssueChangeMapper.class); - for (DefaultIssue issue : issuesToUpdate) { - IssueDto issueDto = doUpdate(dbSession, now, issue); - updated.add(issueDto); - insertChanges(issueChangeMapper, issue); - } - dbSession.commit(); - } - } - return updated; - } - - private IssueDto doUpdate(DbSession session, long now, DefaultIssue issue) { - IssueDto dto = IssueDto.toDtoForUpdate(issue, now); - getDbClient().issueDao().update(session, dto); - // Rule id does not exist in DefaultIssue - Integer ruleId = getRuleId(issue); - return dto.setRuleId(ruleId); - } - - @CheckForNull - protected Integer getRuleId(Issue issue) { - Rule rule = ruleFinder.findByKey(issue.ruleKey()); - return rule != null ? rule.getId() : null; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/issue/package-info.java deleted file mode 100644 index 43edc60ed09..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueCounter.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueCounter.java deleted file mode 100644 index 250629129b8..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueCounter.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.Collection; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import javax.annotation.Nullable; -import org.sonar.api.rule.Severity; -import org.sonar.api.rules.RuleType; -import org.sonar.db.issue.IssueGroupDto; -import org.sonar.db.rule.SeverityUtil; - -import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; - -class IssueCounter { - - private final Map<RuleType, HighestSeverity> highestSeverityOfUnresolved = new EnumMap<>(RuleType.class); - private final Map<RuleType, Effort> effortOfUnresolved = new EnumMap<>(RuleType.class); - private final Map<String, Count> unresolvedBySeverity = new HashMap<>(); - private final Map<RuleType, Count> unresolvedByType = new EnumMap<>(RuleType.class); - private final Map<String, Count> byResolution = new HashMap<>(); - private final Map<String, Count> byStatus = new HashMap<>(); - private final Count unresolved = new Count(); - - IssueCounter(Collection<IssueGroupDto> groups) { - for (IssueGroupDto group : groups) { - RuleType ruleType = RuleType.valueOf(group.getRuleType()); - if (ruleType.equals(SECURITY_HOTSPOT)) { - if (group.getResolution() == null) { - unresolvedByType - .computeIfAbsent(SECURITY_HOTSPOT, k -> new Count()) - .add(group); - } - continue; - } - if (group.getResolution() == null) { - highestSeverityOfUnresolved - .computeIfAbsent(ruleType, k -> new HighestSeverity()) - .add(group); - effortOfUnresolved - .computeIfAbsent(ruleType, k -> new Effort()) - .add(group); - unresolvedBySeverity - .computeIfAbsent(group.getSeverity(), k -> new Count()) - .add(group); - unresolvedByType - .computeIfAbsent(ruleType, k -> new Count()) - .add(group); - unresolved.add(group); - } else { - byResolution - .computeIfAbsent(group.getResolution(), k -> new Count()) - .add(group); - } - if (group.getStatus() != null) { - byStatus - .computeIfAbsent(group.getStatus(), k -> new Count()) - .add(group); - } - } - } - - public Optional<String> getHighestSeverityOfUnresolved(RuleType ruleType, boolean onlyInLeak) { - return Optional.ofNullable(highestSeverityOfUnresolved.get(ruleType)) - .map(hs -> hs.severity(onlyInLeak)); - } - - public double sumEffortOfUnresolved(RuleType type, boolean onlyInLeak) { - Effort effort = effortOfUnresolved.get(type); - if (effort == null) { - return 0.0; - } - return onlyInLeak ? effort.leak : effort.absolute; - } - - public long countUnresolvedBySeverity(String severity, boolean onlyInLeak) { - return value(unresolvedBySeverity.get(severity), onlyInLeak); - } - - public long countByResolution(String resolution, boolean onlyInLeak) { - return value(byResolution.get(resolution), onlyInLeak); - } - - public long countUnresolvedByType(RuleType type, boolean onlyInLeak) { - return value(unresolvedByType.get(type), onlyInLeak); - } - - public long countByStatus(String status, boolean onlyInLeak) { - return value(byStatus.get(status), onlyInLeak); - } - - public long countUnresolved(boolean onlyInLeak) { - return value(unresolved, onlyInLeak); - } - - private static long value(@Nullable Count count, boolean onlyInLeak) { - if (count == null) { - return 0; - } - return onlyInLeak ? count.leak : count.absolute; - } - - private static class Count { - private long absolute = 0L; - private long leak = 0L; - - void add(IssueGroupDto group) { - absolute += group.getCount(); - if (group.isInLeak()) { - leak += group.getCount(); - } - } - } - - private static class Effort { - private double absolute = 0.0; - private double leak = 0.0; - - void add(IssueGroupDto group) { - absolute += group.getEffort(); - if (group.isInLeak()) { - leak += group.getEffort(); - } - } - } - - private static class HighestSeverity { - private int absolute = SeverityUtil.getOrdinalFromSeverity(Severity.INFO); - private int leak = SeverityUtil.getOrdinalFromSeverity(Severity.INFO); - - void add(IssueGroupDto group) { - int severity = SeverityUtil.getOrdinalFromSeverity(group.getSeverity()); - absolute = Math.max(severity, absolute); - if (group.isInLeak()) { - leak = Math.max(severity, leak); - } - } - - String severity(boolean inLeak) { - return SeverityUtil.getSeverityFromOrdinal(inLeak ? leak : absolute); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormula.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormula.java deleted file mode 100644 index 67a5cb12341..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormula.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.Collection; -import java.util.Optional; -import java.util.function.BiConsumer; -import org.sonar.api.measures.Metric; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.measure.DebtRatingGrid; -import org.sonar.server.measure.Rating; - -import static java.util.Collections.emptyList; - -class IssueMetricFormula { - - private final Metric metric; - private final boolean onLeak; - private final BiConsumer<Context, IssueCounter> formula; - private final Collection<Metric> dependentMetrics; - - IssueMetricFormula(Metric metric, boolean onLeak, BiConsumer<Context, IssueCounter> formula) { - this(metric, onLeak, formula, emptyList()); - } - - IssueMetricFormula(Metric metric, boolean onLeak, BiConsumer<Context, IssueCounter> formula, Collection<Metric> dependentMetrics) { - this.metric = metric; - this.onLeak = onLeak; - this.formula = formula; - this.dependentMetrics = dependentMetrics; - } - - Metric getMetric() { - return metric; - } - - boolean isOnLeak() { - return onLeak; - } - - Collection<Metric> getDependentMetrics() { - return dependentMetrics; - } - - void compute(Context context, IssueCounter issues) { - formula.accept(context, issues); - } - - interface Context { - ComponentDto getComponent(); - - DebtRatingGrid getDebtRatingGrid(); - - /** - * Value that was just refreshed, otherwise value as computed - * during last analysis. - * The metric must be declared in the formula dependencies - * (see {@link IssueMetricFormula#getDependentMetrics()}). - */ - Optional<Double> getValue(Metric metric); - - Optional<Double> getLeakValue(Metric metric); - - void setValue(double value); - - void setValue(Rating value); - - void setLeakValue(double value); - - void setLeakValue(Rating value); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormulaFactory.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormulaFactory.java deleted file mode 100644 index a7a9339fa3a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormulaFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.sonar.api.measures.Metric; -import org.sonar.api.server.ServerSide; - -@ServerSide -public interface IssueMetricFormulaFactory { - List<IssueMetricFormula> getFormulas(); - - Set<Metric> getFormulaMetrics(); - - static Set<Metric> extractMetrics(List<IssueMetricFormula> formulas) { - return formulas.stream() - .flatMap(f -> Stream.concat(Stream.of(f.getMetric()), f.getDependentMetrics().stream())) - .collect(Collectors.toSet()); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormulaFactoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormulaFactoryImpl.java deleted file mode 100644 index e7bb34eecbb..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/IssueMetricFormulaFactoryImpl.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.List; -import java.util.Optional; -import java.util.Set; -import org.sonar.api.issue.Issue; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.rule.Severity; -import org.sonar.api.rules.RuleType; -import org.sonar.server.measure.Rating; -import org.sonar.server.security.SecurityReviewRating; - -import static java.util.Arrays.asList; -import static org.sonar.server.measure.Rating.RATING_BY_SEVERITY; - -public class IssueMetricFormulaFactoryImpl implements IssueMetricFormulaFactory { - - private static final List<IssueMetricFormula> FORMULAS = asList( - new IssueMetricFormula(CoreMetrics.CODE_SMELLS, false, - (context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.CODE_SMELL, false))), - - new IssueMetricFormula(CoreMetrics.BUGS, false, - (context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.BUG, false))), - - new IssueMetricFormula(CoreMetrics.VULNERABILITIES, false, - (context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.VULNERABILITY, false))), - - new IssueMetricFormula(CoreMetrics.SECURITY_HOTSPOTS, false, - (context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.SECURITY_HOTSPOT, false))), - - new IssueMetricFormula(CoreMetrics.VIOLATIONS, false, - (context, issues) -> context.setValue(issues.countUnresolved(false))), - - new IssueMetricFormula(CoreMetrics.BLOCKER_VIOLATIONS, false, - (context, issues) -> context.setValue(issues.countUnresolvedBySeverity(Severity.BLOCKER, false))), - - new IssueMetricFormula(CoreMetrics.CRITICAL_VIOLATIONS, false, - (context, issues) -> context.setValue(issues.countUnresolvedBySeverity(Severity.CRITICAL, false))), - - new IssueMetricFormula(CoreMetrics.MAJOR_VIOLATIONS, false, - (context, issues) -> context.setValue(issues.countUnresolvedBySeverity(Severity.MAJOR, false))), - - new IssueMetricFormula(CoreMetrics.MINOR_VIOLATIONS, false, - (context, issues) -> context.setValue(issues.countUnresolvedBySeverity(Severity.MINOR, false))), - - new IssueMetricFormula(CoreMetrics.INFO_VIOLATIONS, false, - (context, issues) -> context.setValue(issues.countUnresolvedBySeverity(Severity.INFO, false))), - - new IssueMetricFormula(CoreMetrics.FALSE_POSITIVE_ISSUES, false, - (context, issues) -> context.setValue(issues.countByResolution(Issue.RESOLUTION_FALSE_POSITIVE, false))), - - new IssueMetricFormula(CoreMetrics.WONT_FIX_ISSUES, false, - (context, issues) -> context.setValue(issues.countByResolution(Issue.RESOLUTION_WONT_FIX, false))), - - new IssueMetricFormula(CoreMetrics.OPEN_ISSUES, false, - (context, issues) -> context.setValue(issues.countByStatus(Issue.STATUS_OPEN, false))), - - new IssueMetricFormula(CoreMetrics.REOPENED_ISSUES, false, - (context, issues) -> context.setValue(issues.countByStatus(Issue.STATUS_REOPENED, false))), - - new IssueMetricFormula(CoreMetrics.CONFIRMED_ISSUES, false, - (context, issues) -> context.setValue(issues.countByStatus(Issue.STATUS_CONFIRMED, false))), - - new IssueMetricFormula(CoreMetrics.TECHNICAL_DEBT, false, - (context, issues) -> context.setValue(issues.sumEffortOfUnresolved(RuleType.CODE_SMELL, false))), - - new IssueMetricFormula(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, false, - (context, issues) -> context.setValue(issues.sumEffortOfUnresolved(RuleType.BUG, false))), - - new IssueMetricFormula(CoreMetrics.SECURITY_REMEDIATION_EFFORT, false, - (context, issues) -> context.setValue(issues.sumEffortOfUnresolved(RuleType.VULNERABILITY, false))), - - new IssueMetricFormula(CoreMetrics.SQALE_DEBT_RATIO, false, - (context, issues) -> context.setValue(100.0 * debtDensity(context)), - asList(CoreMetrics.TECHNICAL_DEBT, CoreMetrics.DEVELOPMENT_COST)), - - new IssueMetricFormula(CoreMetrics.SQALE_RATING, false, - (context, issues) -> context - .setValue(context.getDebtRatingGrid().getRatingForDensity(debtDensity(context))), - asList(CoreMetrics.TECHNICAL_DEBT, CoreMetrics.DEVELOPMENT_COST)), - - new IssueMetricFormula(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, false, - (context, issues) -> context.setValue(effortToReachMaintainabilityRatingA(context)), asList(CoreMetrics.TECHNICAL_DEBT, CoreMetrics.DEVELOPMENT_COST)), - - new IssueMetricFormula(CoreMetrics.RELIABILITY_RATING, false, - (context, issues) -> context.setValue(RATING_BY_SEVERITY.get(issues.getHighestSeverityOfUnresolved(RuleType.BUG, false).orElse(Severity.INFO)))), - - new IssueMetricFormula(CoreMetrics.SECURITY_RATING, false, - (context, issues) -> context.setValue(RATING_BY_SEVERITY.get(issues.getHighestSeverityOfUnresolved(RuleType.VULNERABILITY, false).orElse(Severity.INFO)))), - - new IssueMetricFormula(CoreMetrics.SECURITY_REVIEW_RATING, false, - (context, issues) -> context.setValue(SecurityReviewRating.compute(context.getValue(CoreMetrics.NCLOC).orElse(0d).intValue(), - context.getValue(CoreMetrics.SECURITY_HOTSPOTS).orElse(0d).intValue())), - asList(CoreMetrics.NCLOC, CoreMetrics.SECURITY_HOTSPOTS)), - - new IssueMetricFormula(CoreMetrics.NEW_CODE_SMELLS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedByType(RuleType.CODE_SMELL, true))), - - new IssueMetricFormula(CoreMetrics.NEW_BUGS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedByType(RuleType.BUG, true))), - - new IssueMetricFormula(CoreMetrics.NEW_VULNERABILITIES, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedByType(RuleType.VULNERABILITY, true))), - - new IssueMetricFormula(CoreMetrics.NEW_SECURITY_HOTSPOTS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedByType(RuleType.SECURITY_HOTSPOT, true))), - - new IssueMetricFormula(CoreMetrics.NEW_VIOLATIONS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolved(true))), - - new IssueMetricFormula(CoreMetrics.NEW_BLOCKER_VIOLATIONS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedBySeverity(Severity.BLOCKER, true))), - - new IssueMetricFormula(CoreMetrics.NEW_CRITICAL_VIOLATIONS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedBySeverity(Severity.CRITICAL, true))), - - new IssueMetricFormula(CoreMetrics.NEW_MAJOR_VIOLATIONS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedBySeverity(Severity.MAJOR, true))), - - new IssueMetricFormula(CoreMetrics.NEW_MINOR_VIOLATIONS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedBySeverity(Severity.MINOR, true))), - - new IssueMetricFormula(CoreMetrics.NEW_INFO_VIOLATIONS, true, - (context, issues) -> context.setLeakValue(issues.countUnresolvedBySeverity(Severity.INFO, true))), - - new IssueMetricFormula(CoreMetrics.NEW_TECHNICAL_DEBT, true, - (context, issues) -> context.setLeakValue(issues.sumEffortOfUnresolved(RuleType.CODE_SMELL, true))), - - new IssueMetricFormula(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, true, - (context, issues) -> context.setLeakValue(issues.sumEffortOfUnresolved(RuleType.BUG, true))), - - new IssueMetricFormula(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, true, - (context, issues) -> context.setLeakValue(issues.sumEffortOfUnresolved(RuleType.VULNERABILITY, true))), - - new IssueMetricFormula(CoreMetrics.NEW_RELIABILITY_RATING, true, - (context, issues) -> { - String highestSeverity = issues.getHighestSeverityOfUnresolved(RuleType.BUG, true).orElse(Severity.INFO); - context.setLeakValue(RATING_BY_SEVERITY.get(highestSeverity)); - }), - - new IssueMetricFormula(CoreMetrics.NEW_SECURITY_RATING, true, - (context, issues) -> { - String highestSeverity = issues.getHighestSeverityOfUnresolved(RuleType.VULNERABILITY, true).orElse(Severity.INFO); - context.setLeakValue(RATING_BY_SEVERITY.get(highestSeverity)); - }), - - new IssueMetricFormula(CoreMetrics.NEW_SQALE_DEBT_RATIO, true, - (context, issues) -> context.setLeakValue(100.0 * newDebtDensity(context)), - asList(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_DEVELOPMENT_COST)), - - new IssueMetricFormula(CoreMetrics.NEW_MAINTAINABILITY_RATING, true, - (context, issues) -> context.setLeakValue(context.getDebtRatingGrid().getRatingForDensity( - newDebtDensity(context))), - asList(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_DEVELOPMENT_COST))); - - private static final Set<Metric> FORMULA_METRICS = IssueMetricFormulaFactory.extractMetrics(FORMULAS); - - private static double debtDensity(IssueMetricFormula.Context context) { - double debt = Math.max(context.getValue(CoreMetrics.TECHNICAL_DEBT).orElse(0.0), 0.0); - Optional<Double> devCost = context.getValue(CoreMetrics.DEVELOPMENT_COST); - if (devCost.isPresent() && Double.doubleToRawLongBits(devCost.get()) > 0L) { - return debt / devCost.get(); - } - return 0d; - } - - private static double newDebtDensity(IssueMetricFormula.Context context) { - double debt = Math.max(context.getLeakValue(CoreMetrics.NEW_TECHNICAL_DEBT).orElse(0.0), 0.0); - Optional<Double> devCost = context.getLeakValue(CoreMetrics.NEW_DEVELOPMENT_COST); - if (devCost.isPresent() && Double.doubleToRawLongBits(devCost.get()) > 0L) { - return debt / devCost.get(); - } - return 0d; - } - - private static double effortToReachMaintainabilityRatingA(IssueMetricFormula.Context context) { - double developmentCost = context.getValue(CoreMetrics.DEVELOPMENT_COST).orElse(0.0); - double effort = context.getValue(CoreMetrics.TECHNICAL_DEBT).orElse(0.0); - double upperGradeCost = context.getDebtRatingGrid().getGradeLowerBound(Rating.B) * developmentCost; - return upperGradeCost < effort ? (effort - upperGradeCost) : 0.0; - } - - @Override - public List<IssueMetricFormula> getFormulas() { - return FORMULAS; - } - - @Override - public Set<Metric> getFormulaMetrics() { - return FORMULA_METRICS; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureComputer.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureComputer.java deleted file mode 100644 index 56dc06dc4c6..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureComputer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.Collection; -import java.util.List; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.qualitygate.changeevent.QGChangeEvent; - -/** - * Refresh and persist the measures of some files, directories, modules - * or projects. Measures include status of quality gate. - * - * Touching a file updates the related directory, module and project. - * Status of Quality gate is refreshed but webhooks are not triggered. - * - * Branches are supported. - */ -@ServerSide -public interface LiveMeasureComputer { - - List<QGChangeEvent> refresh(DbSession dbSession, Collection<ComponentDto> components); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java deleted file mode 100644 index f46daa3255e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import javax.annotation.CheckForNull; -import org.sonar.api.config.Configuration; -import org.sonar.api.measures.Metric; -import org.sonar.api.utils.log.Loggers; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.db.measure.LiveMeasureComparator; -import org.sonar.db.measure.LiveMeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.measure.DebtRatingGrid; -import org.sonar.server.measure.Rating; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.QualityGate; -import org.sonar.server.qualitygate.changeevent.QGChangeEvent; -import org.sonar.server.settings.ProjectConfigurationLoader; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static java.util.stream.Collectors.groupingBy; -import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.core.util.stream.MoreCollectors.toArrayList; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; - -public class LiveMeasureComputerImpl implements LiveMeasureComputer { - - private final DbClient dbClient; - private final IssueMetricFormulaFactory formulaFactory; - private final LiveQualityGateComputer qGateComputer; - private final ProjectConfigurationLoader projectConfigurationLoader; - private final ProjectIndexers projectIndexer; - - public LiveMeasureComputerImpl(DbClient dbClient, IssueMetricFormulaFactory formulaFactory, - LiveQualityGateComputer qGateComputer, ProjectConfigurationLoader projectConfigurationLoader, ProjectIndexers projectIndexer) { - this.dbClient = dbClient; - this.formulaFactory = formulaFactory; - this.qGateComputer = qGateComputer; - this.projectConfigurationLoader = projectConfigurationLoader; - this.projectIndexer = projectIndexer; - } - - @Override - public List<QGChangeEvent> refresh(DbSession dbSession, Collection<ComponentDto> components) { - if (components.isEmpty()) { - return emptyList(); - } - - List<QGChangeEvent> result = new ArrayList<>(); - Map<String, List<ComponentDto>> componentsByProjectUuid = components.stream().collect(groupingBy(ComponentDto::projectUuid)); - for (List<ComponentDto> groupedComponents : componentsByProjectUuid.values()) { - Optional<QGChangeEvent> qgChangeEvent = refreshComponentsOnSameProject(dbSession, groupedComponents); - qgChangeEvent.ifPresent(result::add); - } - return result; - } - - private Optional<QGChangeEvent> refreshComponentsOnSameProject(DbSession dbSession, List<ComponentDto> touchedComponents) { - // load all the components to be refreshed, including their ancestors - List<ComponentDto> components = loadTreeOfComponents(dbSession, touchedComponents); - ComponentDto project = findProject(components); - OrganizationDto organization = loadOrganization(dbSession, project); - BranchDto branch = loadBranch(dbSession, project); - - Optional<SnapshotDto> lastAnalysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, project.uuid()); - if (!lastAnalysis.isPresent()) { - return Optional.empty(); - } - - QualityGate qualityGate = qGateComputer.loadQualityGate(dbSession, organization, project, branch); - Collection<String> metricKeys = getKeysOfAllInvolvedMetrics(qualityGate); - - List<MetricDto> metrics = dbClient.metricDao().selectByKeys(dbSession, metricKeys); - Map<Integer, MetricDto> metricsPerId = metrics.stream() - .collect(uniqueIndex(MetricDto::getId)); - List<String> componentUuids = components.stream().map(ComponentDto::uuid).collect(toArrayList(components.size())); - List<LiveMeasureDto> dbMeasures = dbClient.liveMeasureDao().selectByComponentUuidsAndMetricIds(dbSession, componentUuids, metricsPerId.keySet()); - // previous status must be load now as MeasureMatrix mutate the LiveMeasureDto which are passed to it - Metric.Level previousStatus = loadPreviousStatus(metrics, dbMeasures); - - Configuration config = projectConfigurationLoader.loadProjectConfiguration(dbSession, project); - DebtRatingGrid debtRatingGrid = new DebtRatingGrid(config); - - MeasureMatrix matrix = new MeasureMatrix(components, metricsPerId.values(), dbMeasures); - FormulaContextImpl context = new FormulaContextImpl(matrix, debtRatingGrid); - long beginningOfLeak = getBeginningOfLeakPeriod(lastAnalysis, branch); - - components.forEach(c -> { - IssueCounter issueCounter = new IssueCounter(dbClient.issueDao().selectIssueGroupsByBaseComponent(dbSession, c, beginningOfLeak)); - for (IssueMetricFormula formula : formulaFactory.getFormulas()) { - // use formulas when the leak period is defined, it's a PR/SLB, or the formula is not about the leak period - if (shouldUseLeakFormulas(lastAnalysis.get(), branch) || !formula.isOnLeak()) { - context.change(c, formula); - try { - formula.compute(context, issueCounter); - } catch (RuntimeException e) { - throw new IllegalStateException("Fail to compute " + formula.getMetric().getKey() + " on " + context.getComponent().getDbKey(), e); - } - } - } - }); - - EvaluatedQualityGate evaluatedQualityGate = qGateComputer.refreshGateStatus(project, qualityGate, matrix); - - // persist the measures that have been created or updated - matrix.getChanged().sorted(LiveMeasureComparator.INSTANCE) - .forEach(m -> dbClient.liveMeasureDao().insertOrUpdate(dbSession, m)); - projectIndexer.commitAndIndex(dbSession, singleton(project), ProjectIndexer.Cause.MEASURE_CHANGE); - - return Optional.of( - new QGChangeEvent(project, branch, lastAnalysis.get(), config, previousStatus, () -> Optional.of(evaluatedQualityGate))); - } - - private static long getBeginningOfLeakPeriod(Optional<SnapshotDto> lastAnalysis, BranchDto branch) { - if (isSLBorPR(branch)) { - return 0L; - } else { - Optional<Long> beginningOfLeakPeriod = lastAnalysis.map(SnapshotDto::getPeriodDate); - return beginningOfLeakPeriod.orElse(Long.MAX_VALUE); - } - } - - private static boolean isSLBorPR(BranchDto branch) { - return branch.getBranchType() == BranchType.SHORT || branch.getBranchType() == BranchType.PULL_REQUEST; - } - - private static boolean shouldUseLeakFormulas(SnapshotDto lastAnalysis, BranchDto branch) { - return lastAnalysis.getPeriodDate() != null || isSLBorPR(branch); - } - - @CheckForNull - private static Metric.Level loadPreviousStatus(List<MetricDto> metrics, List<LiveMeasureDto> dbMeasures) { - MetricDto alertStatusMetric = metrics.stream() - .filter(m -> ALERT_STATUS_KEY.equals(m.getKey())) - .findAny() - .orElseThrow(() -> new IllegalStateException(String.format("Metric with key %s is not registered", ALERT_STATUS_KEY))); - return dbMeasures.stream() - .filter(m -> m.getMetricId() == alertStatusMetric.getId()) - .map(LiveMeasureDto::getTextValue) - .filter(Objects::nonNull) - .map(m -> { - try { - return Metric.Level.valueOf(m); - } catch (IllegalArgumentException e) { - Loggers.get(LiveMeasureComputerImpl.class) - .trace("Failed to parse value of metric '{}'", m, e); - return null; - } - }) - .filter(Objects::nonNull) - .findAny() - .orElse(null); - } - - private List<ComponentDto> loadTreeOfComponents(DbSession dbSession, List<ComponentDto> touchedComponents) { - Set<String> componentUuids = new HashSet<>(); - for (ComponentDto component : touchedComponents) { - componentUuids.add(component.uuid()); - // ancestors, excluding self - componentUuids.addAll(component.getUuidPathAsList()); - } - // Contrary to the formulas in Compute Engine, - // measures do not aggregate values of descendant components. - // As a consequence nodes do not need to be sorted. Formulas can be applied - // on components in any order. - return dbClient.componentDao().selectByUuids(dbSession, componentUuids); - } - - private Set<String> getKeysOfAllInvolvedMetrics(QualityGate gate) { - Set<String> metricKeys = new HashSet<>(); - for (Metric metric : formulaFactory.getFormulaMetrics()) { - metricKeys.add(metric.getKey()); - } - metricKeys.addAll(qGateComputer.getMetricsRelatedTo(gate)); - return metricKeys; - } - - private static ComponentDto findProject(Collection<ComponentDto> components) { - return components.stream().filter(ComponentDto::isRootProject).findFirst() - .orElseThrow(() -> new IllegalStateException("No project found in " + components)); - } - - private BranchDto loadBranch(DbSession dbSession, ComponentDto project) { - return dbClient.branchDao().selectByUuid(dbSession, project.uuid()) - .orElseThrow(() -> new IllegalStateException("Branch not found: " + project.uuid())); - } - - private OrganizationDto loadOrganization(DbSession dbSession, ComponentDto project) { - String organizationUuid = project.getOrganizationUuid(); - return dbClient.organizationDao().selectByUuid(dbSession, organizationUuid) - .orElseThrow(() -> new IllegalStateException("No organization with UUID " + organizationUuid)); - } - - private static class FormulaContextImpl implements IssueMetricFormula.Context { - private final MeasureMatrix matrix; - private final DebtRatingGrid debtRatingGrid; - private ComponentDto currentComponent; - private IssueMetricFormula currentFormula; - - private FormulaContextImpl(MeasureMatrix matrix, DebtRatingGrid debtRatingGrid) { - this.matrix = matrix; - this.debtRatingGrid = debtRatingGrid; - } - - private void change(ComponentDto component, IssueMetricFormula formula) { - this.currentComponent = component; - this.currentFormula = formula; - } - - @Override - public ComponentDto getComponent() { - return currentComponent; - } - - @Override - public DebtRatingGrid getDebtRatingGrid() { - return debtRatingGrid; - } - - @Override - public Optional<Double> getValue(Metric metric) { - Optional<LiveMeasureDto> measure = matrix.getMeasure(currentComponent, metric.getKey()); - return measure.map(LiveMeasureDto::getValue); - } - - @Override - public Optional<Double> getLeakValue(Metric metric) { - Optional<LiveMeasureDto> measure = matrix.getMeasure(currentComponent, metric.getKey()); - return measure.map(LiveMeasureDto::getVariation); - } - - @Override - public void setValue(double value) { - String metricKey = currentFormula.getMetric().getKey(); - checkState(!currentFormula.isOnLeak(), "Formula of metric %s accepts only leak values", metricKey); - matrix.setValue(currentComponent, metricKey, value); - } - - @Override - public void setLeakValue(double value) { - String metricKey = currentFormula.getMetric().getKey(); - checkState(currentFormula.isOnLeak(), "Formula of metric %s does not accept leak values", metricKey); - matrix.setLeakValue(currentComponent, metricKey, value); - } - - @Override - public void setValue(Rating value) { - String metricKey = currentFormula.getMetric().getKey(); - checkState(!currentFormula.isOnLeak(), "Formula of metric %s accepts only leak values", metricKey); - matrix.setValue(currentComponent, metricKey, value); - } - - @Override - public void setLeakValue(Rating value) { - String metricKey = currentFormula.getMetric().getKey(); - checkState(currentFormula.isOnLeak(), "Formula of metric %s does not accept leak values", metricKey); - matrix.setLeakValue(currentComponent, metricKey, value); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureModule.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureModule.java deleted file mode 100644 index c753200d70e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveMeasureModule.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import org.sonar.core.platform.Module; - -public class LiveMeasureModule extends Module { - @Override - protected void configureModule() { - add( - IssueMetricFormulaFactoryImpl.class, - LiveMeasureComputerImpl.class, - LiveQualityGateComputerImpl.class); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputer.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputer.java deleted file mode 100644 index 6c0e8962b38..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.Set; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.QualityGate; - -@ServerSide -public interface LiveQualityGateComputer { - - QualityGate loadQualityGate(DbSession dbSession, OrganizationDto organization, ComponentDto project, BranchDto branch); - - EvaluatedQualityGate refreshGateStatus(ComponentDto project, QualityGate gate, MeasureMatrix measureMatrix); - - Set<String> getMetricsRelatedTo(QualityGate gate); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java deleted file mode 100644 index 95455db3e02..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.Set; -import java.util.stream.Stream; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.measure.LiveMeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.db.qualitygate.QualityGateDto; -import org.sonar.server.qualitygate.Condition; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.QualityGate; -import org.sonar.server.qualitygate.QualityGateConverter; -import org.sonar.server.qualitygate.QualityGateEvaluator; -import org.sonar.server.qualitygate.QualityGateFinder; - -import static java.lang.String.format; -import static org.sonar.core.util.stream.MoreCollectors.toHashSet; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; - -public class LiveQualityGateComputerImpl implements LiveQualityGateComputer { - - private final DbClient dbClient; - private final QualityGateFinder qGateFinder; - private final QualityGateEvaluator evaluator; - - public LiveQualityGateComputerImpl(DbClient dbClient, QualityGateFinder qGateFinder, QualityGateEvaluator evaluator) { - this.dbClient = dbClient; - this.qGateFinder = qGateFinder; - this.evaluator = evaluator; - } - - @Override - public QualityGate loadQualityGate(DbSession dbSession, OrganizationDto organization, ComponentDto project, BranchDto branch) { - ComponentDto mainProject = project.getMainBranchProjectUuid() == null ? project : dbClient.componentDao().selectOrFailByKey(dbSession, project.getKey()); - QualityGateDto gateDto = qGateFinder.getQualityGate(dbSession, organization, mainProject) - .orElseThrow(() -> new IllegalStateException(format("Quality Gate not found for project %s", mainProject.getKey()))) - .getQualityGate(); - Collection<QualityGateConditionDto> conditionDtos = dbClient.gateConditionDao().selectForQualityGate(dbSession, gateDto.getId()); - Set<Integer> metricIds = conditionDtos.stream().map(c -> (int) c.getMetricId()) - .collect(toHashSet(conditionDtos.size())); - Map<Integer, MetricDto> metricsById = dbClient.metricDao().selectByIds(dbSession, metricIds).stream() - .collect(uniqueIndex(MetricDto::getId)); - - Stream<Condition> conditions = conditionDtos.stream().map(conditionDto -> { - String metricKey = metricsById.get((int) conditionDto.getMetricId()).getKey(); - Condition.Operator operator = Condition.Operator.fromDbValue(conditionDto.getOperator()); - return new Condition(metricKey, operator, conditionDto.getErrorThreshold()); - }); - - if (branch.getBranchType() == BranchType.PULL_REQUEST || branch.getBranchType() == BranchType.SHORT) { - conditions = conditions.filter(Condition::isOnLeakPeriod); - } - - return new QualityGate(String.valueOf(gateDto.getId()), gateDto.getName(), conditions.collect(toHashSet(conditionDtos.size()))); - } - - @Override - public EvaluatedQualityGate refreshGateStatus(ComponentDto project, QualityGate gate, MeasureMatrix measureMatrix) { - QualityGateEvaluator.Measures measures = metricKey -> { - Optional<LiveMeasureDto> liveMeasureDto = measureMatrix.getMeasure(project, metricKey); - if (!liveMeasureDto.isPresent()) { - return Optional.empty(); - } - MetricDto metric = measureMatrix.getMetric(liveMeasureDto.get().getMetricId()); - return Optional.of(new LiveMeasure(liveMeasureDto.get(), metric)); - }; - - EvaluatedQualityGate evaluatedGate = evaluator.evaluate(gate, measures); - - measureMatrix.setValue(project, CoreMetrics.ALERT_STATUS_KEY, evaluatedGate.getStatus().name()); - measureMatrix.setValue(project, CoreMetrics.QUALITY_GATE_DETAILS_KEY, QualityGateConverter.toJson(evaluatedGate)); - - return evaluatedGate; - } - - @Override - public Set<String> getMetricsRelatedTo(QualityGate gate) { - Set<String> metricKeys = new HashSet<>(); - metricKeys.add(CoreMetrics.ALERT_STATUS_KEY); - metricKeys.add(CoreMetrics.QUALITY_GATE_DETAILS_KEY); - metricKeys.addAll(evaluator.getMetricKeys(gate)); - return metricKeys; - } - - private static class LiveMeasure implements QualityGateEvaluator.Measure { - private final LiveMeasureDto dto; - private final MetricDto metric; - - LiveMeasure(LiveMeasureDto dto, MetricDto metric) { - this.dto = dto; - this.metric = metric; - } - - @Override - public Metric.ValueType getType() { - return Metric.ValueType.valueOf(metric.getValueType()); - } - - @Override - public OptionalDouble getValue() { - if (dto.getValue() == null) { - return OptionalDouble.empty(); - } - return OptionalDouble.of(dto.getValue()); - } - - @Override - public Optional<String> getStringValue() { - return Optional.ofNullable(dto.getTextValue()); - } - - @Override - public OptionalDouble getNewMetricValue() { - if (dto.getVariation() == null) { - return OptionalDouble.empty(); - } - return OptionalDouble.of(dto.getVariation()); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/MeasureMatrix.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/MeasureMatrix.java deleted file mode 100644 index 7dac198818c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/MeasureMatrix.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import com.google.common.collect.ArrayTable; -import com.google.common.collect.Collections2; -import com.google.common.collect.Table; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.measure.LiveMeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.server.measure.Rating; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; - -/** - * Keep the measures in memory during refresh of live measures: - * <ul> - * <li>the values of last analysis, restricted to the needed metrics</li> - * <li>the refreshed values</li> - * </ul> - */ -class MeasureMatrix { - - // component uuid -> metric key -> measure - private final Table<String, String, MeasureCell> table; - - private final Map<String, MetricDto> metricsByKeys = new HashMap<>(); - private final Map<Integer, MetricDto> metricsByIds = new HashMap<>(); - - MeasureMatrix(Collection<ComponentDto> components, Collection<MetricDto> metrics, List<LiveMeasureDto> dbMeasures) { - for (MetricDto metric : metrics) { - this.metricsByKeys.put(metric.getKey(), metric); - this.metricsByIds.put(metric.getId(), metric); - } - this.table = ArrayTable.create(Collections2.transform(components, ComponentDto::uuid), metricsByKeys.keySet()); - for (LiveMeasureDto dbMeasure : dbMeasures) { - table.put(dbMeasure.getComponentUuid(), metricsByIds.get(dbMeasure.getMetricId()).getKey(), new MeasureCell(dbMeasure, false)); - } - } - - MetricDto getMetric(int id) { - return requireNonNull(metricsByIds.get(id), () -> String.format("Metric with id %d not found", id)); - } - - private MetricDto getMetric(String key) { - return requireNonNull(metricsByKeys.get(key), () -> String.format("Metric with key %s not found", key)); - } - - Optional<LiveMeasureDto> getMeasure(ComponentDto component, String metricKey) { - checkArgument(table.containsColumn(metricKey), "Metric with key %s is not registered", metricKey); - MeasureCell cell = table.get(component.uuid(), metricKey); - return cell == null ? Optional.empty() : Optional.of(cell.measure); - } - - void setValue(ComponentDto component, String metricKey, double value) { - changeCell(component, metricKey, m -> { - MetricDto metric = getMetric(metricKey); - double newValue = scale(metric, value); - - Double initialValue = m.getValue(); - if (initialValue != null && Double.compare(initialValue, newValue) == 0) { - return false; - } - m.setValue(newValue); - Double initialVariation = m.getVariation(); - if (initialValue != null && initialVariation != null) { - double leakInitialValue = initialValue - initialVariation; - m.setVariation(scale(metric, value - leakInitialValue)); - } - return true; - }); - } - - void setValue(ComponentDto component, String metricKey, Rating value) { - changeCell(component, metricKey, m -> { - Double initialValue = m.getValue(); - if (initialValue != null && Double.compare(initialValue, (double) value.getIndex()) == 0) { - return false; - } - m.setData(value.name()); - m.setValue((double) value.getIndex()); - - Double initialVariation = m.getVariation(); - if (initialValue != null && initialVariation != null) { - double leakInitialValue = initialValue - initialVariation; - m.setVariation(value.getIndex() - leakInitialValue); - } - return true; - }); - } - - void setValue(ComponentDto component, String metricKey, @Nullable String data) { - changeCell(component, metricKey, m -> { - if (Objects.equals(m.getDataAsString(), data)) { - return false; - } - m.setData(data); - return true; - }); - } - - void setLeakValue(ComponentDto component, String metricKey, double variation) { - changeCell(component, metricKey, c -> { - double newVariation = scale(getMetric(metricKey), variation); - if (c.getVariation() != null && Double.compare(c.getVariation(), newVariation) == 0) { - return false; - } - MetricDto metric = metricsByKeys.get(metricKey); - c.setVariation(scale(metric, variation)); - return true; - }); - } - - void setLeakValue(ComponentDto component, String metricKey, Rating variation) { - setLeakValue(component, metricKey, (double) variation.getIndex()); - } - - Stream<LiveMeasureDto> getChanged() { - return table.values() - .stream() - .filter(Objects::nonNull) - .filter(MeasureCell::isChanged) - .map(MeasureCell::getMeasure); - } - - private void changeCell(ComponentDto component, String metricKey, Function<LiveMeasureDto, Boolean> changer) { - MeasureCell cell = table.get(component.uuid(), metricKey); - if (cell == null) { - LiveMeasureDto measure = new LiveMeasureDto() - .setComponentUuid(component.uuid()) - .setProjectUuid(component.projectUuid()) - .setMetricId(metricsByKeys.get(metricKey).getId()); - cell = new MeasureCell(measure, true); - table.put(component.uuid(), metricKey, cell); - changer.apply(cell.getMeasure()); - } else if (changer.apply(cell.getMeasure())) { - cell.setChanged(true); - } - } - - /** - * Round a measure value by applying the scale defined on the metric. - * Example: scale(0.1234) returns 0.12 if metric scale is 2 - */ - private static double scale(MetricDto metric, double value) { - if (metric.getDecimalScale() == null) { - return value; - } - BigDecimal bd = BigDecimal.valueOf(value); - return bd.setScale(metric.getDecimalScale(), RoundingMode.HALF_UP).doubleValue(); - } - - private static class MeasureCell { - private final LiveMeasureDto measure; - private boolean changed; - - private MeasureCell(LiveMeasureDto measure, boolean changed) { - this.measure = measure; - this.changed = changed; - } - - public LiveMeasureDto getMeasure() { - return measure; - } - - public boolean isChanged() { - return changed; - } - - public void setChanged(boolean b) { - this.changed = b; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/package-info.java deleted file mode 100644 index 3f727297666..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/MetricToDto.java b/server/sonar-server/src/main/java/org/sonar/server/metric/MetricToDto.java deleted file mode 100644 index 73b4a2599b1..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/metric/MetricToDto.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.metric; - -import com.google.common.base.Function; -import javax.annotation.Nonnull; -import org.sonar.api.measures.Metric; -import org.sonar.db.metric.MetricDto; - -public enum MetricToDto implements Function<Metric, MetricDto> { - INSTANCE; - @Override - @Nonnull - public MetricDto apply(@Nonnull Metric metric) { - MetricDto dto = new MetricDto(); - dto.setId(metric.getId()); - dto.setKey(metric.getKey()); - dto.setDescription(metric.getDescription()); - dto.setShortName(metric.getName()); - dto.setBestValue(metric.getBestValue()); - dto.setDomain(metric.getDomain()); - dto.setEnabled(metric.getEnabled()); - dto.setDirection(metric.getDirection()); - dto.setHidden(metric.isHidden()); - dto.setQualitative(metric.getQualitative()); - dto.setValueType(metric.getType().name()); - dto.setOptimizedBestValue(metric.isOptimizedBestValue()); - dto.setUserManaged(metric.getUserManaged()); - dto.setWorstValue(metric.getWorstValue()); - dto.setDeleteHistoricalData(metric.getDeleteHistoricalData()); - dto.setDecimalScale(metric.getDecimalScale()); - return dto; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ApplyPermissionTemplateQuery.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ApplyPermissionTemplateQuery.java deleted file mode 100644 index f3b58fe6c02..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/ApplyPermissionTemplateQuery.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.List; - -import static org.apache.commons.lang.StringUtils.isNotBlank; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public class ApplyPermissionTemplateQuery { - - private final String templateUuid; - private List<String> componentKeys; - - private ApplyPermissionTemplateQuery(String templateUuid, List<String> componentKeys) { - this.templateUuid = templateUuid; - this.componentKeys = componentKeys; - validate(); - } - - public static ApplyPermissionTemplateQuery create(String templateUuid, List<String> componentKeys) { - return new ApplyPermissionTemplateQuery(templateUuid, componentKeys); - } - - public String getTemplateUuid() { - return templateUuid; - } - - public List<String> getComponentKeys() { - return componentKeys; - } - - private void validate() { - checkRequest(isNotBlank(templateUuid), "Permission template is mandatory"); - checkRequest(componentKeys != null && !componentKeys.isEmpty(), "No project provided. Please provide at least one project."); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/DefaultTemplatesResolver.java b/server/sonar-server/src/main/java/org/sonar/server/permission/DefaultTemplatesResolver.java deleted file mode 100644 index fe8b1821c67..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/DefaultTemplatesResolver.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.Optional; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import org.sonar.db.organization.DefaultTemplates; - -import static java.util.Objects.requireNonNull; -import static java.util.Optional.ofNullable; - -public interface DefaultTemplatesResolver { - /** - * Resolve the effective default templates uuid for the specified {@link DefaultTemplates}. - * <ul> - * <li>{@link ResolvedDefaultTemplates#project} is always the same as {@link DefaultTemplates#projectUuid}</li> - * <li>when Governance is not installed, {@link ResolvedDefaultTemplates#application} is always {@code null}</li> - * <li>when Governance is installed, {@link ResolvedDefaultTemplates#application} is {@link DefaultTemplates#applicationsUuid} - * when it is non {@code null}, otherwise it is {@link DefaultTemplates#projectUuid}</li> - * <li>when Governance is installed, {@link ResolvedDefaultTemplates#portfolio} is {@link DefaultTemplates#portfoliosUuid} - * when it is non {@code null}, otherwise it is {@link DefaultTemplates#projectUuid}</li> - * </ul> - */ - ResolvedDefaultTemplates resolve(DefaultTemplates defaultTemplates); - - @Immutable - final class ResolvedDefaultTemplates { - private final String project; - private final String application; - private final String portfolio; - - public ResolvedDefaultTemplates(String project, @Nullable String application, @Nullable String portfolio) { - this.project = requireNonNull(project, "project can't be null"); - this.application = application; - this.portfolio = portfolio; - } - - public String getProject() { - return project; - } - - public Optional<String> getApplication() { - return ofNullable(application); - } - - public Optional<String> getPortfolio() { - return ofNullable(portfolio); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/DefaultTemplatesResolverImpl.java b/server/sonar-server/src/main/java/org/sonar/server/permission/DefaultTemplatesResolverImpl.java deleted file mode 100644 index b7d88ae00e1..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/DefaultTemplatesResolverImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.db.organization.DefaultTemplates; - -import static java.util.Optional.ofNullable; - -public class DefaultTemplatesResolverImpl implements DefaultTemplatesResolver { - private final ResourceTypes resourceTypes; - - public DefaultTemplatesResolverImpl(ResourceTypes resourceTypes) { - this.resourceTypes = resourceTypes; - } - - @Override - public ResolvedDefaultTemplates resolve(DefaultTemplates defaultTemplates) { - String projectDefaultTemplate = defaultTemplates.getProjectUuid(); - - return new ResolvedDefaultTemplates( - projectDefaultTemplate, - isViewsEnabled(resourceTypes) ? ofNullable(defaultTemplates.getApplicationsUuid()).orElse(projectDefaultTemplate) : null, - isViewsEnabled(resourceTypes) ? ofNullable(defaultTemplates.getPortfoliosUuid()).orElse(projectDefaultTemplate) : null); - } - - private static boolean isViewsEnabled(ResourceTypes resourceTypes) { - return resourceTypes.getRoots() - .stream() - .map(ResourceType::getQualifier) - .anyMatch(Qualifiers.VIEW::equals); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChange.java b/server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChange.java deleted file mode 100644 index 488da6d6351..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChange.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import javax.annotation.Nullable; - -public class GroupPermissionChange extends PermissionChange { - - private final GroupIdOrAnyone groupId; - - public GroupPermissionChange(Operation operation, String permission, @Nullable ProjectId projectId, - GroupIdOrAnyone groupId, PermissionService permissionService) { - super(operation, groupId.getOrganizationUuid(), permission, projectId, permissionService); - this.groupId = groupId; - } - - public GroupIdOrAnyone getGroupIdOrAnyone() { - return groupId; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChanger.java b/server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChanger.java deleted file mode 100644 index 947310f2274..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChanger.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.List; -import java.util.Optional; -import org.sonar.core.permission.GlobalPermissions; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.permission.GroupPermissionDto; - -import static java.lang.String.format; -import static org.sonar.api.web.UserRole.PUBLIC_PERMISSIONS; -import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; -import static org.sonar.server.permission.PermissionChange.Operation.ADD; -import static org.sonar.server.permission.PermissionChange.Operation.REMOVE; - -public class GroupPermissionChanger { - - private final DbClient dbClient; - - public GroupPermissionChanger(DbClient dbClient) { - this.dbClient = dbClient; - } - - public boolean apply(DbSession dbSession, GroupPermissionChange change) { - ensureConsistencyWithVisibility(change); - if (isImplicitlyAlreadyDone(change)) { - return false; - } - switch (change.getOperation()) { - case ADD: - return addPermission(dbSession, change); - case REMOVE: - return removePermission(dbSession, change); - default: - throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation()); - } - } - - private static boolean isImplicitlyAlreadyDone(GroupPermissionChange change) { - return change.getProjectId() - .map(projectId -> isImplicitlyAlreadyDone(projectId, change)) - .orElse(false); - } - - private static boolean isImplicitlyAlreadyDone(ProjectId projectId, GroupPermissionChange change) { - return isAttemptToAddPublicPermissionToPublicComponent(change, projectId) - || isAttemptToRemovePermissionFromAnyoneOnPrivateComponent(change, projectId); - } - - private static boolean isAttemptToAddPublicPermissionToPublicComponent(GroupPermissionChange change, ProjectId projectId) { - return !projectId.isPrivate() - && change.getOperation() == ADD - && PUBLIC_PERMISSIONS.contains(change.getPermission()); - } - - private static boolean isAttemptToRemovePermissionFromAnyoneOnPrivateComponent(GroupPermissionChange change, ProjectId projectId) { - return projectId.isPrivate() - && change.getOperation() == REMOVE - && change.getGroupIdOrAnyone().isAnyone(); - } - - private static void ensureConsistencyWithVisibility(GroupPermissionChange change) { - change.getProjectId() - .ifPresent(projectId -> { - checkRequest( - !isAttemptToAddPermissionToAnyoneOnPrivateComponent(change, projectId), - "No permission can be granted to Anyone on a private component"); - checkRequest( - !isAttemptToRemovePublicPermissionFromPublicComponent(change, projectId), - "Permission %s can't be removed from a public component", change.getPermission()); - }); - } - - private static boolean isAttemptToAddPermissionToAnyoneOnPrivateComponent(GroupPermissionChange change, ProjectId projectId) { - return projectId.isPrivate() - && change.getOperation() == ADD - && change.getGroupIdOrAnyone().isAnyone(); - } - - private static boolean isAttemptToRemovePublicPermissionFromPublicComponent(GroupPermissionChange change, ProjectId projectId) { - return !projectId.isPrivate() - && change.getOperation() == REMOVE - && PUBLIC_PERMISSIONS.contains(change.getPermission()); - } - - private boolean addPermission(DbSession dbSession, GroupPermissionChange change) { - if (loadExistingPermissions(dbSession, change).contains(change.getPermission())) { - return false; - } - - validateNotAnyoneAndAdminPermission(change.getPermission(), change.getGroupIdOrAnyone()); - GroupPermissionDto addedDto = new GroupPermissionDto() - .setRole(change.getPermission()) - .setOrganizationUuid(change.getOrganizationUuid()) - .setGroupId(change.getGroupIdOrAnyone().getId()) - .setResourceId(change.getNullableProjectId()); - dbClient.groupPermissionDao().insert(dbSession, addedDto); - return true; - } - - private static void validateNotAnyoneAndAdminPermission(String permission, GroupIdOrAnyone group) { - checkRequest(!GlobalPermissions.SYSTEM_ADMIN.equals(permission) || !group.isAnyone(), - format("It is not possible to add the '%s' permission to group 'Anyone'.", permission)); - } - - private boolean removePermission(DbSession dbSession, GroupPermissionChange change) { - if (!loadExistingPermissions(dbSession, change).contains(change.getPermission())) { - return false; - } - checkIfRemainingGlobalAdministrators(dbSession, change); - dbClient.groupPermissionDao().delete(dbSession, - change.getPermission(), - change.getOrganizationUuid(), - change.getGroupIdOrAnyone().getId(), - change.getNullableProjectId()); - return true; - } - - private List<String> loadExistingPermissions(DbSession dbSession, GroupPermissionChange change) { - Optional<ProjectId> projectId = change.getProjectId(); - if (projectId.isPresent()) { - return dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, - change.getOrganizationUuid(), - change.getGroupIdOrAnyone().getId(), - projectId.get().getId()); - } - return dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, - change.getOrganizationUuid(), - change.getGroupIdOrAnyone().getId()); - } - - private void checkIfRemainingGlobalAdministrators(DbSession dbSession, GroupPermissionChange change) { - if (SYSTEM_ADMIN.equals(change.getPermission()) && - !change.getGroupIdOrAnyone().isAnyone() && - !change.getProjectId().isPresent()) { - // removing global admin permission from group - int remaining = dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingGroup(dbSession, - change.getOrganizationUuid(), SYSTEM_ADMIN, change.getGroupIdOrAnyone().getId()); - checkRequest(remaining > 0, "Last group with permission '%s'. Permission cannot be removed.", SYSTEM_ADMIN); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionChange.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionChange.java deleted file mode 100644 index 94ed74562d5..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionChange.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.Optional; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.db.permission.OrganizationPermission; - -import static java.util.Objects.requireNonNull; -import static org.sonar.core.util.stream.MoreCollectors.toList; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public abstract class PermissionChange { - - public enum Operation { - ADD, REMOVE - } - - private final Operation operation; - private final String organizationUuid; - private final String permission; - private final ProjectId projectId; - protected final PermissionService permissionService; - - public PermissionChange(Operation operation, String organizationUuid, String permission, @Nullable ProjectId projectId, PermissionService permissionService) { - this.operation = requireNonNull(operation); - this.organizationUuid = requireNonNull(organizationUuid); - this.permission = requireNonNull(permission); - this.projectId = projectId; - this.permissionService = permissionService; - if (projectId == null) { - checkRequest(permissionService.getAllOrganizationPermissions().stream().anyMatch(p -> p.getKey().equals(permission)), - "Invalid global permission '%s'. Valid values are %s", permission, - permissionService.getAllOrganizationPermissions().stream().map(OrganizationPermission::getKey).collect(toList())); - } else { - checkRequest(permissionService.getAllProjectPermissions().contains(permission), "Invalid project permission '%s'. Valid values are %s", permission, - permissionService.getAllProjectPermissions()); - } - } - - public Operation getOperation() { - return operation; - } - - public String getOrganizationUuid() { - return organizationUuid; - } - - public String getPermission() { - return permission; - } - - public Optional<ProjectId> getProjectId() { - return Optional.ofNullable(projectId); - } - - /** - * Shortcut based on {@link #getProjectId()} - */ - @CheckForNull - public String getProjectUuid() { - return projectId == null ? null : projectId.getUuid(); - } - - /** - * Shortcut based on {@link #getProjectId()} - */ - @CheckForNull - public Long getNullableProjectId() { - return projectId == null ? null : projectId.getId(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java deleted file mode 100644 index 3dcfff32d9a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -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.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.DefaultTemplates; -import org.sonar.db.permission.GroupPermissionDto; -import org.sonar.db.permission.UserPermissionDto; -import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto; -import org.sonar.db.permission.template.PermissionTemplateDto; -import org.sonar.db.permission.template.PermissionTemplateGroupDto; -import org.sonar.db.permission.template.PermissionTemplateUserDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.String.format; -import static java.util.Collections.singletonList; -import static org.sonar.api.security.DefaultGroups.isAnyone; -import static org.sonar.api.web.UserRole.PUBLIC_PERMISSIONS; -import static org.sonar.db.permission.OrganizationPermission.SCAN; - -@ServerSide -public class PermissionTemplateService { - - private final DbClient dbClient; - private final ProjectIndexers projectIndexers; - private final UserSession userSession; - private final DefaultTemplatesResolver defaultTemplatesResolver; - - public PermissionTemplateService(DbClient dbClient, ProjectIndexers projectIndexers, UserSession userSession, - DefaultTemplatesResolver defaultTemplatesResolver) { - this.dbClient = dbClient; - this.projectIndexers = projectIndexers; - this.userSession = userSession; - this.defaultTemplatesResolver = defaultTemplatesResolver; - } - - public boolean wouldUserHaveScanPermissionWithDefaultTemplate(DbSession dbSession, String organizationUuid, @Nullable Integer userId, String projectKey) { - if (userSession.hasPermission(SCAN, organizationUuid)) { - return true; - } - - ComponentDto dto = new ComponentDto().setOrganizationUuid(organizationUuid).setDbKey(projectKey).setQualifier(Qualifiers.PROJECT); - PermissionTemplateDto template = findTemplate(dbSession, dto); - if (template == null) { - return false; - } - - List<String> potentialPermissions = dbClient.permissionTemplateDao().selectPotentialPermissionsByUserIdAndTemplateId(dbSession, userId, template.getId()); - return potentialPermissions.contains(SCAN.getKey()); - } - - /** - * Apply a permission template to a set of projects. Authorization to administrate these projects - * is not verified. The projects must exist, so the "project creator" permissions defined in the - * template are ignored. - */ - public void applyAndCommit(DbSession dbSession, PermissionTemplateDto template, Collection<ComponentDto> projects) { - if (projects.isEmpty()) { - return; - } - - for (ComponentDto project : projects) { - copyPermissions(dbSession, template, project, null); - } - projectIndexers.commitAndIndex(dbSession, projects, ProjectIndexer.Cause.PERMISSION_CHANGE); - } - - /** - * Apply the default permission template to project. The project can already exist (so it has permissions) or - * can be provisioned (so has no permissions yet). - * @param projectCreatorUserId id of the user who creates the project, only if project is provisioned. He will - */ - public void applyDefault(DbSession dbSession, ComponentDto component, @Nullable Integer projectCreatorUserId) { - PermissionTemplateDto template = findTemplate(dbSession, component); - checkArgument(template != null, "Cannot retrieve default permission template"); - copyPermissions(dbSession, template, component, projectCreatorUserId); - } - - public boolean hasDefaultTemplateWithPermissionOnProjectCreator(DbSession dbSession, ComponentDto component) { - PermissionTemplateDto template = findTemplate(dbSession, component); - return hasProjectCreatorPermission(dbSession, template); - } - - private boolean hasProjectCreatorPermission(DbSession dbSession, @Nullable PermissionTemplateDto template) { - return template != null && dbClient.permissionTemplateCharacteristicDao().selectByTemplateIds(dbSession, singletonList(template.getId())).stream() - .anyMatch(PermissionTemplateCharacteristicDto::getWithProjectCreator); - } - - private void copyPermissions(DbSession dbSession, PermissionTemplateDto template, ComponentDto project, @Nullable Integer projectCreatorUserId) { - dbClient.groupPermissionDao().deleteByRootComponentId(dbSession, project.getId()); - dbClient.userPermissionDao().deleteProjectPermissions(dbSession, project.getId()); - - List<PermissionTemplateUserDto> usersPermissions = dbClient.permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, template.getId()); - String organizationUuid = template.getOrganizationUuid(); - usersPermissions - .stream() - .filter(up -> permissionValidForProject(project, up.getPermission())) - .forEach(up -> { - UserPermissionDto dto = new UserPermissionDto(organizationUuid, up.getPermission(), up.getUserId(), project.getId()); - dbClient.userPermissionDao().insert(dbSession, dto); - }); - - List<PermissionTemplateGroupDto> groupsPermissions = dbClient.permissionTemplateDao().selectGroupPermissionsByTemplateId(dbSession, template.getId()); - groupsPermissions - .stream() - .filter(gp -> groupNameValidForProject(project, gp.getGroupName())) - .filter(gp -> permissionValidForProject(project, gp.getPermission())) - .forEach(gp -> { - GroupPermissionDto dto = new GroupPermissionDto() - .setOrganizationUuid(organizationUuid) - .setGroupId(isAnyone(gp.getGroupName()) ? null : gp.getGroupId()) - .setRole(gp.getPermission()) - .setResourceId(project.getId()); - dbClient.groupPermissionDao().insert(dbSession, dto); - }); - - List<PermissionTemplateCharacteristicDto> characteristics = dbClient.permissionTemplateCharacteristicDao().selectByTemplateIds(dbSession, singletonList(template.getId())); - if (projectCreatorUserId != null) { - Set<String> permissionsForCurrentUserAlreadyInDb = usersPermissions.stream() - .filter(userPermission -> projectCreatorUserId.equals(userPermission.getUserId())) - .map(PermissionTemplateUserDto::getPermission) - .collect(java.util.stream.Collectors.toSet()); - characteristics.stream() - .filter(PermissionTemplateCharacteristicDto::getWithProjectCreator) - .filter(up -> permissionValidForProject(project, up.getPermission())) - .filter(characteristic -> !permissionsForCurrentUserAlreadyInDb.contains(characteristic.getPermission())) - .forEach(c -> { - UserPermissionDto dto = new UserPermissionDto(organizationUuid, c.getPermission(), projectCreatorUserId, project.getId()); - dbClient.userPermissionDao().insert(dbSession, dto); - }); - } - } - - private static boolean permissionValidForProject(ComponentDto project, String permission) { - return project.isPrivate() || !PUBLIC_PERMISSIONS.contains(permission); - } - - private static boolean groupNameValidForProject(ComponentDto project, String groupName) { - return !project.isPrivate() || !isAnyone(groupName); - } - - /** - * Return the permission template for the given component. If no template key pattern match then consider default - * template for the component qualifier. - */ - @CheckForNull - private PermissionTemplateDto findTemplate(DbSession dbSession, ComponentDto component) { - String organizationUuid = component.getOrganizationUuid(); - List<PermissionTemplateDto> allPermissionTemplates = dbClient.permissionTemplateDao().selectAll(dbSession, organizationUuid, null); - List<PermissionTemplateDto> matchingTemplates = new ArrayList<>(); - for (PermissionTemplateDto permissionTemplateDto : allPermissionTemplates) { - String keyPattern = permissionTemplateDto.getKeyPattern(); - if (StringUtils.isNotBlank(keyPattern) && component.getDbKey().matches(keyPattern)) { - matchingTemplates.add(permissionTemplateDto); - } - } - checkAtMostOneMatchForComponentKey(component.getDbKey(), matchingTemplates); - if (matchingTemplates.size() == 1) { - return matchingTemplates.get(0); - } - - DefaultTemplates defaultTemplates = dbClient.organizationDao().getDefaultTemplates(dbSession, organizationUuid) - .orElseThrow(() -> new IllegalStateException( - format("No Default templates defined for organization with uuid '%s'", organizationUuid))); - - String qualifier = component.qualifier(); - DefaultTemplatesResolverImpl.ResolvedDefaultTemplates resolvedDefaultTemplates = defaultTemplatesResolver.resolve(defaultTemplates); - switch (qualifier) { - case Qualifiers.PROJECT: - return dbClient.permissionTemplateDao().selectByUuid(dbSession, resolvedDefaultTemplates.getProject()); - case Qualifiers.VIEW: - String portDefaultTemplateUuid = resolvedDefaultTemplates.getPortfolio().orElseThrow( - () -> new IllegalStateException("Attempt to create a view when Governance plugin is not installed")); - return dbClient.permissionTemplateDao().selectByUuid(dbSession, portDefaultTemplateUuid); - case Qualifiers.APP: - String appDefaultTemplateUuid = resolvedDefaultTemplates.getApplication().orElseThrow( - () -> new IllegalStateException("Attempt to create a view when Governance plugin is not installed")); - return dbClient.permissionTemplateDao().selectByUuid(dbSession, appDefaultTemplateUuid); - default: - throw new IllegalArgumentException(format("Qualifier '%s' is not supported", qualifier)); - } - } - - private static void checkAtMostOneMatchForComponentKey(String componentKey, List<PermissionTemplateDto> matchingTemplates) { - if (matchingTemplates.size() > 1) { - StringBuilder templatesNames = new StringBuilder(); - for (Iterator<PermissionTemplateDto> it = matchingTemplates.iterator(); it.hasNext();) { - templatesNames.append("\"").append(it.next().getName()).append("\""); - if (it.hasNext()) { - templatesNames.append(", "); - } - } - throw new IllegalStateException(MessageFormat.format( - "The \"{0}\" key matches multiple permission templates: {1}." - + " A system administrator must update these templates so that only one of them matches the key.", - componentKey, - templatesNames.toString())); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java deleted file mode 100644 index 876d9026f7c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import org.sonar.db.DbSession; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.ProjectIndexers; - -/** - * Add or remove global/project permissions to a group. This class - * does not verify that caller has administration right on the related - * organization or project. - */ -public class PermissionUpdater { - - private final ProjectIndexers projectIndexers; - private final UserPermissionChanger userPermissionChanger; - private final GroupPermissionChanger groupPermissionChanger; - - public PermissionUpdater(ProjectIndexers projectIndexers, - UserPermissionChanger userPermissionChanger, GroupPermissionChanger groupPermissionChanger) { - this.projectIndexers = projectIndexers; - this.userPermissionChanger = userPermissionChanger; - this.groupPermissionChanger = groupPermissionChanger; - } - - public void apply(DbSession dbSession, Collection<PermissionChange> changes) { - List<String> projectOrViewUuids = new ArrayList<>(); - for (PermissionChange change : changes) { - boolean changed = doApply(dbSession, change); - Optional<ProjectId> projectId = change.getProjectId(); - if (changed && projectId.isPresent()) { - projectOrViewUuids.add(projectId.get().getUuid()); - } - } - projectIndexers.commitAndIndexByProjectUuids(dbSession, projectOrViewUuids, ProjectIndexer.Cause.PERMISSION_CHANGE); - } - - private boolean doApply(DbSession dbSession, PermissionChange change) { - if (change instanceof UserPermissionChange) { - return userPermissionChanger.apply(dbSession, (UserPermissionChange) change); - } - if (change instanceof GroupPermissionChange) { - return groupPermissionChanger.apply(dbSession, (GroupPermissionChange) change); - } - throw new UnsupportedOperationException("Unsupported permission change: " + change.getClass()); - - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChange.java b/server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChange.java deleted file mode 100644 index 971d24b1d0d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChange.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import javax.annotation.Nullable; - -import static java.util.Objects.requireNonNull; - -public class UserPermissionChange extends PermissionChange { - - private final UserId userId; - - public UserPermissionChange(Operation operation, String organizationUuid, String permission, @Nullable ProjectId projectId, - UserId userId, PermissionService permissionService) { - super(operation, organizationUuid, permission, projectId, permissionService); - this.userId = requireNonNull(userId); - } - - public UserId getUserId() { - return userId; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChanger.java b/server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChanger.java deleted file mode 100644 index 04239af9724..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChanger.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.List; -import java.util.Optional; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.permission.UserPermissionDto; - -import static org.sonar.api.web.UserRole.PUBLIC_PERMISSIONS; -import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; -import static org.sonar.server.permission.PermissionChange.Operation.ADD; -import static org.sonar.server.permission.PermissionChange.Operation.REMOVE; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -/** - * Adds and removes user permissions. Both global and project scopes are supported. - */ -public class UserPermissionChanger { - - private final DbClient dbClient; - - public UserPermissionChanger(DbClient dbClient) { - this.dbClient = dbClient; - } - - public boolean apply(DbSession dbSession, UserPermissionChange change) { - ensureConsistencyWithVisibility(change); - if (isImplicitlyAlreadyDone(change)) { - return false; - } - switch (change.getOperation()) { - case ADD: - return addPermission(dbSession, change); - case REMOVE: - return removePermission(dbSession, change); - default: - throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation()); - } - } - - private static boolean isImplicitlyAlreadyDone(UserPermissionChange change) { - return change.getProjectId() - .map(projectId -> isImplicitlyAlreadyDone(projectId, change)) - .orElse(false); - } - - private static boolean isImplicitlyAlreadyDone(ProjectId projectId, UserPermissionChange change) { - return isAttemptToAddPublicPermissionToPublicComponent(change, projectId); - } - - private static boolean isAttemptToAddPublicPermissionToPublicComponent(UserPermissionChange change, ProjectId projectId) { - return !projectId.isPrivate() - && change.getOperation() == ADD - && PUBLIC_PERMISSIONS.contains(change.getPermission()); - } - - private static void ensureConsistencyWithVisibility(UserPermissionChange change) { - change.getProjectId() - .ifPresent(projectId -> checkRequest( - !isAttemptToRemovePublicPermissionFromPublicComponent(change, projectId), - "Permission %s can't be removed from a public component", change.getPermission())); - } - - private static boolean isAttemptToRemovePublicPermissionFromPublicComponent(UserPermissionChange change, ProjectId projectId) { - return !projectId.isPrivate() - && change.getOperation() == REMOVE - && PUBLIC_PERMISSIONS.contains(change.getPermission()); - } - - private boolean addPermission(DbSession dbSession, UserPermissionChange change) { - if (loadExistingPermissions(dbSession, change).contains(change.getPermission())) { - return false; - } - UserPermissionDto dto = new UserPermissionDto(change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId(), change.getNullableProjectId()); - dbClient.userPermissionDao().insert(dbSession, dto); - return true; - } - - private boolean removePermission(DbSession dbSession, UserPermissionChange change) { - if (!loadExistingPermissions(dbSession, change).contains(change.getPermission())) { - return false; - } - checkOtherAdminsExist(dbSession, change); - Optional<ProjectId> projectId = change.getProjectId(); - if (projectId.isPresent()) { - dbClient.userPermissionDao().deleteProjectPermission(dbSession, change.getUserId().getId(), change.getPermission(), projectId.get().getId()); - } else { - dbClient.userPermissionDao().deleteGlobalPermission(dbSession, change.getUserId().getId(), change.getPermission(), change.getOrganizationUuid()); - } - return true; - } - - private List<String> loadExistingPermissions(DbSession dbSession, UserPermissionChange change) { - Optional<ProjectId> projectId = change.getProjectId(); - if (projectId.isPresent()) { - return dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, - change.getUserId().getId(), - projectId.get().getId()); - } - return dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession, - change.getUserId().getId(), - change.getOrganizationUuid()); - } - - private void checkOtherAdminsExist(DbSession dbSession, UserPermissionChange change) { - if (SYSTEM_ADMIN.equals(change.getPermission()) && !change.getProjectId().isPresent()) { - int remaining = dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingUserPermission(dbSession, - change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId()); - checkRequest(remaining > 0, "Last user with permission '%s'. Permission cannot be removed.", SYSTEM_ADMIN); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/permission/package-info.java deleted file mode 100644 index a66df8906dd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/AbstractSystemInfoWriter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/AbstractSystemInfoWriter.java new file mode 100644 index 00000000000..fad900559ed --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/AbstractSystemInfoWriter.java @@ -0,0 +1,93 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info 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.platform; + +import java.util.Collection; +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.process.systeminfo.SystemInfoUtils; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; +import org.sonar.server.health.Health; +import org.sonar.server.telemetry.TelemetryDataLoader; + +import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryData; + +public abstract class AbstractSystemInfoWriter implements SystemInfoWriter { + private static final String[] ORDERED_SECTION_NAMES = { + // standalone + "System", "Database", "Plugins", + + // cluster + "Web JVM State", "Web Database Connection", "Web Logging", "Web JVM Properties", + "Compute Engine Tasks", "Compute Engine JVM State", "Compute Engine Database Connection", "Compute Engine Logging", "Compute Engine JVM Properties", + "Search State", "Search Indexes"}; + + private final TelemetryDataLoader telemetry; + + AbstractSystemInfoWriter(TelemetryDataLoader telemetry) { + this.telemetry = telemetry; + } + + protected void writeSections(Collection<ProtobufSystemInfo.Section> sections, JsonWriter json) { + SystemInfoUtils + .order(sections, ORDERED_SECTION_NAMES) + .forEach(section -> writeSection(section, json)); + } + + private void writeSection(ProtobufSystemInfo.Section section, JsonWriter json) { + json.name(section.getName()); + json.beginObject(); + for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) { + writeAttribute(attribute, json); + } + json.endObject(); + } + + private void writeAttribute(ProtobufSystemInfo.Attribute attribute, JsonWriter json) { + switch (attribute.getValueCase()) { + case BOOLEAN_VALUE: + json.prop(attribute.getKey(), attribute.getBooleanValue()); + break; + case LONG_VALUE: + json.prop(attribute.getKey(), attribute.getLongValue()); + break; + case DOUBLE_VALUE: + json.prop(attribute.getKey(), attribute.getDoubleValue()); + break; + case STRING_VALUE: + json.prop(attribute.getKey(), attribute.getStringValue()); + break; + case VALUE_NOT_SET: + json.name(attribute.getKey()).beginArray().values(attribute.getStringValuesList()).endArray(); + break; + default: + throw new IllegalArgumentException("Unsupported type: " + attribute.getValueCase()); + } + } + + protected void writeHealth(Health health, JsonWriter json) { + json.prop("Health", health.getStatus().name()); + json.name("Health Causes").beginArray().values(health.getCauses()).endArray(); + } + + protected void writeTelemetry(JsonWriter json) { + json.name("Statistics"); + writeTelemetryData(json, telemetry.load()); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java b/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java index 74d7aef1e0f..818e13930c3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java @@ -25,6 +25,7 @@ import org.sonar.api.config.Settings; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.property.PropertyDto; +import org.sonar.server.setting.SettingsChangeNotifier; public class PersistentSettings { diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/SettingsChangeNotifier.java b/server/sonar-server/src/main/java/org/sonar/server/platform/SettingsChangeNotifier.java deleted file mode 100644 index 1ea0a48ec2d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/SettingsChangeNotifier.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.platform; - -import com.google.common.annotations.VisibleForTesting; -import org.sonar.api.config.GlobalPropertyChangeHandler; - -import javax.annotation.Nullable; - -public class SettingsChangeNotifier { - - @VisibleForTesting - GlobalPropertyChangeHandler[] changeHandlers; - - public SettingsChangeNotifier(GlobalPropertyChangeHandler[] changeHandlers) { - this.changeHandlers = changeHandlers; - } - - public SettingsChangeNotifier() { - this(new GlobalPropertyChangeHandler[0]); - } - - public void onGlobalPropertyChange(String key, @Nullable String value) { - GlobalPropertyChangeHandler.PropertyChange change = GlobalPropertyChangeHandler.PropertyChange.create(key, value); - for (GlobalPropertyChangeHandler changeHandler : changeHandlers) { - changeHandler.onChange(change); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPlugin.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPlugin.java deleted file mode 100644 index 0fffb7b7d78..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPlugin.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.FileUtils; -import org.sonar.core.platform.PluginInfo; - -import static java.util.Objects.requireNonNull; - -@Immutable -public class InstalledPlugin { - private final PluginInfo plugin; - private final FileAndMd5 loadedJar; - @Nullable - private final FileAndMd5 compressedJar; - - public InstalledPlugin(PluginInfo plugin, FileAndMd5 loadedJar, @Nullable FileAndMd5 compressedJar) { - this.plugin = requireNonNull(plugin); - this.loadedJar = requireNonNull(loadedJar); - this.compressedJar = compressedJar; - } - - public PluginInfo getPluginInfo() { - return plugin; - } - - public FileAndMd5 getLoadedJar() { - return loadedJar; - } - - @Nullable - public FileAndMd5 getCompressedJar() { - return compressedJar; - } - - @Immutable - public static final class FileAndMd5 { - private final File file; - private final String md5; - - public FileAndMd5(File file) { - try (InputStream fis = FileUtils.openInputStream(file)) { - this.file = file; - this.md5 = DigestUtils.md5Hex(fis); - } catch (IOException e) { - throw new IllegalStateException("Fail to compute md5 of " + file, e); - } - } - - public File getFile() { - return file; - } - - public String getMd5() { - return md5; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java deleted file mode 100644 index d61efac304c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.base.Optional; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import org.apache.commons.io.FileUtils; -import org.picocontainer.Startable; -import org.sonar.api.utils.HttpDownloader; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.server.platform.ServerFileSystem; -import org.sonar.updatecenter.common.Release; -import org.sonar.updatecenter.common.UpdateCenter; -import org.sonar.updatecenter.common.Version; - -import static org.apache.commons.io.FileUtils.copyFile; -import static org.apache.commons.io.FileUtils.copyFileToDirectory; -import static org.apache.commons.io.FileUtils.forceMkdir; -import static org.apache.commons.io.FileUtils.toFile; -import static org.apache.commons.lang.StringUtils.substringAfterLast; -import static org.sonar.core.util.FileUtils.deleteQuietly; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -/** - * Downloads plugins from update center. Files are copied in the directory extensions/downloads and then - * moved to extensions/plugins after server restart. - */ -public class PluginDownloader implements Startable { - - private static final Logger LOG = Loggers.get(PluginDownloader.class); - private static final String TMP_SUFFIX = "tmp"; - private static final String PLUGIN_EXTENSION = "jar"; - - private final UpdateCenterMatrixFactory updateCenterMatrixFactory; - private final HttpDownloader downloader; - private final File downloadDir; - - public PluginDownloader(UpdateCenterMatrixFactory updateCenterMatrixFactory, HttpDownloader downloader, - ServerFileSystem fileSystem) { - this.updateCenterMatrixFactory = updateCenterMatrixFactory; - this.downloader = downloader; - this.downloadDir = fileSystem.getDownloadedPluginsDir(); - } - - /** - * Deletes the temporary files remaining from previous downloads - */ - @Override - public void start() { - try { - forceMkdir(downloadDir); - for (File tempFile : listTempFile(this.downloadDir)) { - deleteQuietly(tempFile); - } - } catch (IOException e) { - throw new IllegalStateException("Fail to create the directory: " + downloadDir, e); - } - } - - @Override - public void stop() { - // Nothing to do - } - - public void cancelDownloads() { - try { - if (downloadDir.exists()) { - org.sonar.core.util.FileUtils.cleanDirectory(downloadDir); - } - } catch (IOException e) { - throw new IllegalStateException("Fail to clean the plugin downloads directory: " + downloadDir, e); - } - } - - public List<String> getDownloadedPluginFilenames() { - List<String> names = new ArrayList<>(); - for (File file : listPlugins(this.downloadDir)) { - names.add(file.getName()); - } - return names; - } - - /** - * @return the list of download plugins as {@link PluginInfo} instances - */ - public Collection<PluginInfo> getDownloadedPlugins() { - return listPlugins(this.downloadDir) - .stream() - .map(PluginInfo::create) - .collect(MoreCollectors.toList()); - } - - public void download(String pluginKey, Version version) { - Optional<UpdateCenter> updateCenter = updateCenterMatrixFactory.getUpdateCenter(true); - if (updateCenter.isPresent()) { - List<Release> installablePlugins = updateCenter.get().findInstallablePlugins(pluginKey, version); - checkRequest(!installablePlugins.isEmpty(), "Error while downloading plugin '%s' with version '%s'. No compatible plugin found.", pluginKey, version.getName()); - for (Release release : installablePlugins) { - try { - downloadRelease(release); - } catch (Exception e) { - String message = String.format("Fail to download the plugin (%s, version %s) from %s (error is : %s)", - release.getArtifact().getKey(), release.getVersion().getName(), release.getDownloadUrl(), e.getMessage()); - LOG.debug(message, e); - throw new IllegalStateException(message, e); - } - } - } - } - - private void downloadRelease(Release release) throws URISyntaxException, IOException { - String url = release.getDownloadUrl(); - - URI uri = new URI(url); - if (url.startsWith("file:")) { - // used for tests - File file = toFile(uri.toURL()); - copyFileToDirectory(file, downloadDir); - } else { - String filename = substringAfterLast(uri.getPath(), "/"); - if (!filename.endsWith("." + PLUGIN_EXTENSION)) { - filename = release.getKey() + "-" + release.getVersion() + "." + PLUGIN_EXTENSION; - } - File targetFile = new File(downloadDir, filename); - File tempFile = new File(downloadDir, filename + "." + TMP_SUFFIX); - downloader.download(uri, tempFile); - copyFile(tempFile, targetFile); - deleteQuietly(tempFile); - } - } - - private static Collection<File> listTempFile(File dir) { - return FileUtils.listFiles(dir, new String[] {TMP_SUFFIX}, false); - } - - private static Collection<File> listPlugins(File dir) { - return FileUtils.listFiles(dir, new String[] {PLUGIN_EXTENSION}, false); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginFileSystem.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginFileSystem.java deleted file mode 100644 index e65336a7586..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginFileSystem.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.jar.JarInputStream; -import java.util.jar.Pack200; -import java.util.zip.GZIPOutputStream; -import org.sonar.api.config.Configuration; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; -import org.sonar.core.platform.PluginInfo; -import org.sonar.server.plugins.InstalledPlugin.FileAndMd5; - -import static com.google.common.base.Preconditions.checkState; - -@ServerSide -public class PluginFileSystem { - - public static final String PROPERTY_PLUGIN_COMPRESSION_ENABLE = "sonar.pluginsCompression.enable"; - private static final Logger LOG = Loggers.get(PluginFileSystem.class); - - private final Configuration configuration; - private final Map<String, InstalledPlugin> installedFiles = new HashMap<>(); - - public PluginFileSystem(Configuration configuration) { - this.configuration = configuration; - } - - /** - * @param plugin - * @param loadedJar the JAR loaded by classloaders. It differs from {@code plugin.getJarFile()} - * which is the initial location of JAR as seen by users - */ - public void addInstalledPlugin(PluginInfo plugin, File loadedJar) { - checkState(!installedFiles.containsKey(plugin.getKey()), "Plugin %s is already loaded", plugin.getKey()); - checkState(loadedJar.exists(), "loadedJar does not exist: %s", loadedJar); - - Optional<File> compressed = compressJar(plugin, loadedJar); - InstalledPlugin installedFile = new InstalledPlugin( - plugin, - new FileAndMd5(loadedJar), - compressed.map(FileAndMd5::new).orElse(null)); - installedFiles.put(plugin.getKey(), installedFile); - } - - public Optional<InstalledPlugin> getInstalledPlugin(String pluginKey) { - return Optional.ofNullable(installedFiles.get(pluginKey)); - } - - public Collection<InstalledPlugin> getInstalledFiles() { - return installedFiles.values(); - } - - private Optional<File> compressJar(PluginInfo plugin, File jar) { - if (!configuration.getBoolean(PROPERTY_PLUGIN_COMPRESSION_ENABLE).orElse(false)) { - return Optional.empty(); - } - - Path targetPack200 = getPack200Path(jar.toPath()); - Path sourcePack200Path = getPack200Path(plugin.getNonNullJarFile().toPath()); - - // check if packed file was deployed alongside the jar. If that's the case, use it instead of generating it (SONAR-10395). - if (sourcePack200Path.toFile().exists()) { - try { - LOG.debug("Found pack200: " + sourcePack200Path); - Files.copy(sourcePack200Path, targetPack200); - } catch (IOException e) { - throw new IllegalStateException("Failed to copy pack200 file from " + sourcePack200Path + " to " + targetPack200, e); - } - } else { - pack200(jar.toPath(), targetPack200, plugin.getKey()); - } - return Optional.of(targetPack200.toFile()); - } - - private static void pack200(Path jarPath, Path toPack200Path, String pluginKey) { - Profiler profiler = Profiler.create(LOG); - profiler.startInfo("Compressing plugin " + pluginKey + " [pack200]"); - - try (JarInputStream in = new JarInputStream(new BufferedInputStream(Files.newInputStream(jarPath))); - OutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(toPack200Path)))) { - Pack200.newPacker().pack(in, out); - } catch (IOException e) { - throw new IllegalStateException(String.format("Fail to pack200 plugin [%s] '%s' to '%s'", pluginKey, jarPath, toPack200Path), e); - } - profiler.stopInfo(); - } - - private static Path getPack200Path(Path jar) { - String jarFileName = jar.getFileName().toString(); - String filename = jarFileName.substring(0, jarFileName.length() - 3) + "pack.gz"; - return jar.resolveSibling(filename); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginUninstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginUninstaller.java deleted file mode 100644 index 8253dbaf8c1..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginUninstaller.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import org.apache.commons.io.FileUtils; -import org.picocontainer.Startable; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.server.platform.ServerFileSystem; - -import static java.lang.String.format; -import static org.apache.commons.io.FileUtils.forceMkdir; - -public class PluginUninstaller implements Startable { - private static final String PLUGIN_EXTENSION = "jar"; - private final ServerPluginRepository serverPluginRepository; - private final File uninstallDir; - - public PluginUninstaller(ServerPluginRepository serverPluginRepository, ServerFileSystem fs) { - this.serverPluginRepository = serverPluginRepository; - this.uninstallDir = fs.getUninstalledPluginsDir(); - } - - private static Collection<File> listJarFiles(File dir) { - if (dir.exists()) { - return FileUtils.listFiles(dir, new String[] {PLUGIN_EXTENSION}, false); - } - return Collections.emptyList(); - } - - @Override - public void start() { - try { - forceMkdir(uninstallDir); - } catch (IOException e) { - throw new IllegalStateException("Fail to create the directory: " + uninstallDir, e); - } - } - - @Override - public void stop() { - // Nothing to do - } - - public void uninstall(String pluginKey) { - ensurePluginIsInstalled(pluginKey); - serverPluginRepository.uninstall(pluginKey, uninstallDir); - } - - public void cancelUninstalls() { - serverPluginRepository.cancelUninstalls(uninstallDir); - } - - /** - * @return the list of plugins to be uninstalled as {@link PluginInfo} instances - */ - public Collection<PluginInfo> getUninstalledPlugins() { - return listJarFiles(uninstallDir) - .stream() - .map(PluginInfo::create) - .collect(MoreCollectors.toList()); - } - - private void ensurePluginIsInstalled(String key) { - if (!serverPluginRepository.hasPlugin(key)) { - throw new IllegalArgumentException(format("Plugin [%s] is not installed", key)); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java deleted file mode 100644 index 1970d4475a5..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.File; -import org.apache.commons.io.FileUtils; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.ZipUtils; -import org.sonar.core.platform.ExplodedPlugin; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.platform.PluginJarExploder; -import org.sonar.server.platform.ServerFileSystem; - -import static org.apache.commons.io.FileUtils.forceMkdir; - -@ServerSide -public class ServerPluginJarExploder extends PluginJarExploder { - private final ServerFileSystem fs; - private final PluginFileSystem pluginFileSystem; - - public ServerPluginJarExploder(ServerFileSystem fs, PluginFileSystem pluginFileSystem) { - this.fs = fs; - this.pluginFileSystem = pluginFileSystem; - } - - /** - * JAR files of directory extensions/plugins can be moved when server is up and plugins are uninstalled. - * For this reason these files must not be locked by classloaders. They are copied to the directory - * web/deploy/plugins in order to be loaded by {@link org.sonar.core.platform.PluginLoader}. - */ - @Override - public ExplodedPlugin explode(PluginInfo pluginInfo) { - File toDir = new File(fs.getDeployedPluginsDir(), pluginInfo.getKey()); - try { - forceMkdir(toDir); - org.sonar.core.util.FileUtils.cleanDirectory(toDir); - - File jarSource = pluginInfo.getNonNullJarFile(); - File jarTarget = new File(toDir, jarSource.getName()); - - FileUtils.copyFile(jarSource, jarTarget); - ZipUtils.unzip(jarSource, toDir, newLibFilter()); - ExplodedPlugin explodedPlugin = explodeFromUnzippedDir(pluginInfo.getKey(), jarTarget, toDir); - pluginFileSystem.addInstalledPlugin(pluginInfo, jarTarget); - return explodedPlugin; - } catch (Exception e) { - throw new IllegalStateException(String.format( - "Fail to unzip plugin [%s] %s to %s", pluginInfo.getKey(), pluginInfo.getNonNullJarFile().getAbsolutePath(), toDir.getAbsolutePath()), e); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java deleted file mode 100644 index ecc3abc2d76..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Ordering; -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import javax.annotation.CheckForNull; -import org.apache.commons.io.FileUtils; -import org.picocontainer.Startable; -import org.sonar.api.Plugin; -import org.sonar.api.SonarRuntime; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.platform.PluginLoader; -import org.sonar.core.platform.PluginRepository; -import org.sonar.server.platform.ServerFileSystem; -import org.sonar.updatecenter.common.Version; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static java.lang.String.format; -import static org.apache.commons.io.FileUtils.moveFile; -import static org.apache.commons.io.FileUtils.moveFileToDirectory; -import static org.sonar.core.util.FileUtils.deleteQuietly; - -/** - * Entry point to install and load plugins on server startup. It manages - * <ul> - * <li>installation of new plugins (effective after server startup)</li> - * <li>un-installation of plugins (effective after server startup)</li> - * <li>cancel pending installations/un-installations</li> - * <li>instantiation of plugin entry-points</li> - * </ul> - */ -public class ServerPluginRepository implements PluginRepository, Startable { - - private static final Logger LOG = Loggers.get(ServerPluginRepository.class); - private static final String[] JAR_FILE_EXTENSIONS = new String[] {"jar"}; - // List of plugins that are silently removed if installed - private static final Set<String> DEFAULT_BLACKLISTED_PLUGINS = ImmutableSet.of("scmactivity", "issuesreport", "genericcoverage"); - // List of plugins that should prevent the server to finish its startup - private static final Set<String> FORBIDDEN_COMPATIBLE_PLUGINS = ImmutableSet.of("sqale", "report", "views"); - private static final Joiner SLASH_JOINER = Joiner.on(" / ").skipNulls(); - private static final String NOT_STARTED_YET = "not started yet"; - - private final SonarRuntime runtime; - private final ServerFileSystem fs; - private final PluginLoader loader; - private final AtomicBoolean started = new AtomicBoolean(false); - private Set<String> blacklistedPluginKeys = DEFAULT_BLACKLISTED_PLUGINS; - - // following fields are available after startup - private final Map<String, PluginInfo> pluginInfosByKeys = new HashMap<>(); - private final Map<String, Plugin> pluginInstancesByKeys = new HashMap<>(); - private final Map<ClassLoader, String> keysByClassLoader = new HashMap<>(); - - public ServerPluginRepository(SonarRuntime runtime, ServerFileSystem fs, PluginLoader loader) { - this.runtime = runtime; - this.fs = fs; - this.loader = loader; - } - - @VisibleForTesting - void setBlacklistedPluginKeys(Set<String> keys) { - this.blacklistedPluginKeys = keys; - } - - @Override - public void start() { - loadPreInstalledPlugins(); - moveDownloadedPlugins(); - unloadIncompatiblePlugins(); - logInstalledPlugins(); - loadInstances(); - started.set(true); - } - - @Override - public void stop() { - // close classloaders - loader.unload(pluginInstancesByKeys.values()); - pluginInstancesByKeys.clear(); - pluginInfosByKeys.clear(); - keysByClassLoader.clear(); - started.set(true); - } - - /** - * Return the key of the plugin the extension (in the sense of {@link Plugin.Context#addExtension(Object)} is coming from. - */ - @CheckForNull - public String getPluginKey(Object extension) { - return keysByClassLoader.get(extension.getClass().getClassLoader()); - } - - /** - * Load the plugins that are located in extensions/plugins. Blacklisted plugins are - * deleted. - */ - private void loadPreInstalledPlugins() { - for (File file : listJarFiles(fs.getInstalledPluginsDir())) { - PluginInfo info = PluginInfo.create(file); - registerPluginInfo(info); - } - } - - /** - * Move the plugins recently downloaded to extensions/plugins. - */ - private void moveDownloadedPlugins() { - if (fs.getDownloadedPluginsDir().exists()) { - for (File sourceFile : listJarFiles(fs.getDownloadedPluginsDir())) { - overrideAndRegisterPlugin(sourceFile); - } - } - } - - private void registerPluginInfo(PluginInfo info) { - String pluginKey = info.getKey(); - if (blacklistedPluginKeys.contains(pluginKey)) { - LOG.warn("Plugin {} [{}] is blacklisted and is being uninstalled", info.getName(), pluginKey); - deleteQuietly(info.getNonNullJarFile()); - return; - } - if (FORBIDDEN_COMPATIBLE_PLUGINS.contains(pluginKey)) { - throw MessageException.of(String.format("Plugin '%s' is no longer compatible with this version of SonarQube", pluginKey)); - } - PluginInfo existing = pluginInfosByKeys.put(pluginKey, info); - if (existing != null) { - throw MessageException.of(format("Found two versions of the plugin %s [%s] in the directory extensions/plugins. Please remove one of %s or %s.", - info.getName(), pluginKey, info.getNonNullJarFile().getName(), existing.getNonNullJarFile().getName())); - } - - } - - /** - * Move or copy plugin to directory extensions/plugins. If a version of this plugin - * already exists then it's deleted. - */ - private void overrideAndRegisterPlugin(File sourceFile) { - File destDir = fs.getInstalledPluginsDir(); - File destFile = new File(destDir, sourceFile.getName()); - if (destFile.exists()) { - // plugin with same filename already installed - deleteQuietly(destFile); - } - - try { - moveFile(sourceFile, destFile); - - } catch (IOException e) { - throw new IllegalStateException(format("Fail to move plugin: %s to %s", - sourceFile.getAbsolutePath(), destFile.getAbsolutePath()), e); - } - - PluginInfo info = PluginInfo.create(destFile); - PluginInfo existing = pluginInfosByKeys.put(info.getKey(), info); - if (existing != null) { - if (!existing.getNonNullJarFile().getName().equals(destFile.getName())) { - deleteQuietly(existing.getNonNullJarFile()); - } - LOG.info("Plugin {} [{}] updated to version {}", info.getName(), info.getKey(), info.getVersion()); - } else { - LOG.info("Plugin {} [{}] installed", info.getName(), info.getKey()); - } - } - - /** - * Removes the plugins that are not compatible with current environment. - */ - private void unloadIncompatiblePlugins() { - // loop as long as the previous loop ignored some plugins. That allows to support dependencies - // on many levels, for example D extends C, which extends B, which requires A. If A is not installed, - // then B, C and D must be ignored. That's not possible to achieve this algorithm with a single - // iteration over plugins. - Set<String> removedKeys = new HashSet<>(); - do { - removedKeys.clear(); - for (PluginInfo plugin : pluginInfosByKeys.values()) { - if (!isCompatible(plugin, runtime, pluginInfosByKeys)) { - removedKeys.add(plugin.getKey()); - } - } - for (String removedKey : removedKeys) { - pluginInfosByKeys.remove(removedKey); - } - } while (!removedKeys.isEmpty()); - } - - @VisibleForTesting - static boolean isCompatible(PluginInfo plugin, SonarRuntime runtime, Map<String, PluginInfo> allPluginsByKeys) { - if (Strings.isNullOrEmpty(plugin.getMainClass()) && Strings.isNullOrEmpty(plugin.getBasePlugin())) { - LOG.warn("Plugin {} [{}] is ignored because entry point class is not defined", plugin.getName(), plugin.getKey()); - return false; - } - - if (!plugin.isCompatibleWith(runtime.getApiVersion().toString())) { - throw MessageException.of(format( - "Plugin %s [%s] requires at least SonarQube %s", plugin.getName(), plugin.getKey(), plugin.getMinimalSqVersion())); - } - - if (!Strings.isNullOrEmpty(plugin.getBasePlugin()) && !allPluginsByKeys.containsKey(plugin.getBasePlugin())) { - // it extends a plugin that is not installed - LOG.warn("Plugin {} [{}] is ignored because its base plugin [{}] is not installed", plugin.getName(), plugin.getKey(), plugin.getBasePlugin()); - return false; - } - - for (PluginInfo.RequiredPlugin requiredPlugin : plugin.getRequiredPlugins()) { - PluginInfo installedRequirement = allPluginsByKeys.get(requiredPlugin.getKey()); - if (installedRequirement == null) { - // it requires a plugin that is not installed - LOG.warn("Plugin {} [{}] is ignored because the required plugin [{}] is not installed", plugin.getName(), plugin.getKey(), requiredPlugin.getKey()); - return false; - } - Version installedRequirementVersion = installedRequirement.getVersion(); - if (installedRequirementVersion != null && requiredPlugin.getMinimalVersion().compareToIgnoreQualifier(installedRequirementVersion) > 0) { - // it requires a more recent version - LOG.warn("Plugin {} [{}] is ignored because the version {}Â of required plugin [{}] is not supported", plugin.getName(), plugin.getKey(), - requiredPlugin.getKey(), requiredPlugin.getMinimalVersion()); - return false; - } - } - return true; - } - - private void logInstalledPlugins() { - List<PluginInfo> orderedPlugins = Ordering.natural().sortedCopy(pluginInfosByKeys.values()); - for (PluginInfo plugin : orderedPlugins) { - LOG.info("Deploy plugin {}", SLASH_JOINER.join(plugin.getName(), plugin.getVersion(), plugin.getImplementationBuild())); - } - } - - private void loadInstances() { - pluginInstancesByKeys.putAll(loader.load(pluginInfosByKeys)); - - for (Map.Entry<String, Plugin> e : pluginInstancesByKeys.entrySet()) { - keysByClassLoader.put(e.getValue().getClass().getClassLoader(), e.getKey()); - } - } - - /** - * Uninstall a plugin and its dependents - */ - public void uninstall(String pluginKey, File uninstallDir) { - Set<String> uninstallKeys = new HashSet<>(); - uninstallKeys.add(pluginKey); - appendDependentPluginKeys(pluginKey, uninstallKeys); - - for (String uninstallKey : uninstallKeys) { - PluginInfo info = getPluginInfo(uninstallKey); - - try { - if (!getPluginFile(info).exists()) { - LOG.info("Plugin already uninstalled: {} [{}]", info.getName(), info.getKey()); - continue; - } - - LOG.info("Uninstalling plugin {} [{}]", info.getName(), info.getKey()); - - File masterFile = getPluginFile(info); - moveFileToDirectory(masterFile, uninstallDir, true); - } catch (IOException e) { - throw new IllegalStateException(format("Fail to uninstall plugin %s [%s]", info.getName(), info.getKey()), e); - } - } - } - - public void cancelUninstalls(File uninstallDir) { - for (File file : listJarFiles(uninstallDir)) { - try { - moveFileToDirectory(file, fs.getInstalledPluginsDir(), false); - } catch (IOException e) { - throw new IllegalStateException("Fail to cancel plugin uninstalls", e); - } - } - } - - /** - * Appends dependent plugins, only the ones that still exist in the plugins folder. - */ - private void appendDependentPluginKeys(String pluginKey, Set<String> appendTo) { - for (PluginInfo otherPlugin : getPluginInfos()) { - if (!otherPlugin.getKey().equals(pluginKey)) { - for (PluginInfo.RequiredPlugin requirement : otherPlugin.getRequiredPlugins()) { - if (requirement.getKey().equals(pluginKey)) { - appendTo.add(otherPlugin.getKey()); - appendDependentPluginKeys(otherPlugin.getKey(), appendTo); - } - } - } - } - } - - private File getPluginFile(PluginInfo info) { - // we don't reuse info.getFile() just to be sure that file is located in from extensions/plugins - return new File(fs.getInstalledPluginsDir(), info.getNonNullJarFile().getName()); - } - - public Map<String, PluginInfo> getPluginInfosByKeys() { - return pluginInfosByKeys; - } - - @Override - public Collection<PluginInfo> getPluginInfos() { - checkState(started.get(), NOT_STARTED_YET); - return ImmutableList.copyOf(pluginInfosByKeys.values()); - } - - @Override - public PluginInfo getPluginInfo(String key) { - checkState(started.get(), NOT_STARTED_YET); - PluginInfo info = pluginInfosByKeys.get(key); - if (info == null) { - throw new IllegalArgumentException(format("Plugin [%s] does not exist", key)); - } - return info; - } - - @Override - public Plugin getPluginInstance(String key) { - checkState(started.get(), NOT_STARTED_YET); - Plugin plugin = pluginInstancesByKeys.get(key); - checkArgument(plugin != null, "Plugin [%s] does not exist", key); - return plugin; - } - - @Override - public boolean hasPlugin(String key) { - checkState(started.get(), NOT_STARTED_YET); - return pluginInfosByKeys.containsKey(key); - } - - private static Collection<File> listJarFiles(File dir) { - if (dir.exists()) { - return FileUtils.listFiles(dir, JAR_FILE_EXTENSIONS, false); - } - return Collections.emptyList(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java deleted file mode 100644 index 2f5d0b2d357..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.base.Optional; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import org.apache.commons.io.IOUtils; -import org.sonar.api.Properties; -import org.sonar.api.Property; -import org.sonar.api.config.Configuration; -import org.sonar.api.utils.UriReader; -import org.sonar.api.utils.log.Loggers; -import org.sonar.process.ProcessProperties; -import org.sonar.updatecenter.common.UpdateCenter; -import org.sonar.updatecenter.common.UpdateCenterDeserializer; -import org.sonar.updatecenter.common.UpdateCenterDeserializer.Mode; - -/** - * HTTP client to load data from the remote update center hosted at https://update.sonarsource.org. - * - * @since 2.4 - */ -@Properties({ - @Property( - key = UpdateCenterClient.URL_PROPERTY, - defaultValue = "https://update.sonarsource.org/update-center.properties", - name = "Update Center URL", - category = "Update Center", - project = false, - // hidden from UI - global = false) -}) -public class UpdateCenterClient { - - public static final String URL_PROPERTY = "sonar.updatecenter.url"; - public static final int PERIOD_IN_MILLISECONDS = 60 * 60 * 1000; - - private final URI uri; - private final UriReader uriReader; - private final boolean isActivated; - private UpdateCenter pluginCenter = null; - private long lastRefreshDate = 0; - - public UpdateCenterClient(UriReader uriReader, Configuration config) throws URISyntaxException { - this.uriReader = uriReader; - this.uri = new URI(config.get(URL_PROPERTY).get()); - this.isActivated = config.getBoolean(ProcessProperties.Property.SONAR_UPDATECENTER_ACTIVATE.getKey()).get(); - Loggers.get(getClass()).info("Update center: " + uriReader.description(uri)); - } - - public Optional<UpdateCenter> getUpdateCenter() { - return getUpdateCenter(false); - } - - public Optional<UpdateCenter> getUpdateCenter(boolean forceRefresh) { - if (!isActivated) { - return Optional.absent(); - } - - if (pluginCenter == null || forceRefresh || needsRefresh()) { - pluginCenter = init(); - lastRefreshDate = System.currentTimeMillis(); - } - return Optional.fromNullable(pluginCenter); - } - - public Date getLastRefreshDate() { - return lastRefreshDate > 0 ? new Date(lastRefreshDate) : null; - } - - private boolean needsRefresh() { - return lastRefreshDate + PERIOD_IN_MILLISECONDS < System.currentTimeMillis(); - } - - private UpdateCenter init() { - InputStream input = null; - try { - String content = uriReader.readString(uri, StandardCharsets.UTF_8); - java.util.Properties properties = new java.util.Properties(); - input = IOUtils.toInputStream(content, StandardCharsets.UTF_8); - properties.load(input); - return new UpdateCenterDeserializer(Mode.PROD, true).fromProperties(properties); - - } catch (Exception e) { - Loggers.get(getClass()).error("Fail to connect to update center", e); - return null; - - } finally { - IOUtils.closeQuietly(input); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java deleted file mode 100644 index 0c0a6730987..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.base.Optional; -import org.sonar.api.SonarRuntime; -import org.sonar.updatecenter.common.UpdateCenter; -import org.sonar.updatecenter.common.Version; - -/** - * @since 2.4 - */ -public class UpdateCenterMatrixFactory { - - private final UpdateCenterClient centerClient; - private final SonarRuntime sonarRuntime; - private final InstalledPluginReferentialFactory installedPluginReferentialFactory; - - public UpdateCenterMatrixFactory(UpdateCenterClient centerClient, SonarRuntime runtime, - InstalledPluginReferentialFactory installedPluginReferentialFactory) { - this.centerClient = centerClient; - this.sonarRuntime = runtime; - this.installedPluginReferentialFactory = installedPluginReferentialFactory; - } - - public Optional<UpdateCenter> getUpdateCenter(boolean refreshUpdateCenter) { - Optional<UpdateCenter> updateCenter = centerClient.getUpdateCenter(refreshUpdateCenter); - if (updateCenter.isPresent()) { - org.sonar.api.utils.Version fullVersion = sonarRuntime.getApiVersion(); - org.sonar.api.utils.Version semanticVersion = org.sonar.api.utils.Version.create(fullVersion.major(), fullVersion.minor(), fullVersion.patch()); - - return Optional.of(updateCenter.get().setInstalledSonarVersion(Version.create(semanticVersion.toString())).registerInstalledPlugins( - installedPluginReferentialFactory.getInstalledPluginReferential()) - .setDate(centerClient.getLastRefreshDate())); - } - return Optional.absent(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/WebServerExtensionInstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/WebServerExtensionInstaller.java deleted file mode 100644 index 9fa956d2a15..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/WebServerExtensionInstaller.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import org.sonar.api.SonarRuntime; -import org.sonar.api.server.ServerSide; -import org.sonar.core.platform.PluginRepository; - -import static java.util.Collections.singleton; - -@ServerSide -public class WebServerExtensionInstaller extends ServerExtensionInstaller { - public WebServerExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository) { - super(sonarRuntime, pluginRepository, singleton(ServerSide.class)); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java deleted file mode 100644 index f6c1db3b035..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.edition; - -import java.util.Arrays; -import org.sonar.core.platform.PluginInfo; -import org.sonar.updatecenter.common.Plugin; - -public final class EditionBundledPlugins { - - private static final String SONARSOURCE_ORGANIZATION = "SonarSource"; - private static final String[] SONARSOURCE_COMMERCIAL_LICENSES = {"SonarSource", "Commercial"}; - - private EditionBundledPlugins() { - // prevents instantiation - } - - public static boolean isEditionBundled(Plugin plugin) { - return SONARSOURCE_ORGANIZATION.equalsIgnoreCase(plugin.getOrganization()) - && Arrays.stream(SONARSOURCE_COMMERCIAL_LICENSES).anyMatch(s -> s.equalsIgnoreCase(plugin.getLicense())); - } - - public static boolean isEditionBundled(PluginInfo pluginInfo) { - return SONARSOURCE_ORGANIZATION.equalsIgnoreCase(pluginInfo.getOrganizationName()) - && Arrays.stream(SONARSOURCE_COMMERCIAL_LICENSES).anyMatch(s -> s.equalsIgnoreCase(pluginInfo.getLicense())); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/package-info.java deleted file mode 100644 index e0a7b00bbf9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.edition; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/package-info.java deleted file mode 100644 index 2ef44accfd2..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java b/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java deleted file mode 100644 index 6afdea527e9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import java.util.Set; -import org.sonar.api.server.ServerSide; - -@ServerSide -public interface ProjectLifeCycleListener { - /** - * This method is called after the specified projects have been deleted. - */ - void onProjectsDeleted(Set<Project> projects); - - /** - * This method is called after the specified projects have been deleted. - */ - void onProjectBranchesDeleted(Set<Project> projects); - - /** - * This method is called after the specified projects' keys have been modified. - */ - void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java b/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java deleted file mode 100644 index 7f3d3f1867d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import java.util.Set; - -public interface ProjectLifeCycleListeners { - /** - * This method is called after the specified projects have been deleted and will call method - * {@link ProjectLifeCycleListener#onProjectsDeleted(Set) onProjectsDeleted(Set)} of all known - * {@link ProjectLifeCycleListener} implementations. - * <p> - * This method ensures all {@link ProjectLifeCycleListener} implementations are called, even if one or more of - * them fail with an exception. - */ - void onProjectsDeleted(Set<Project> projects); - - /** - * This method is called after the specified project branches have been deleted and will call method - * {@link ProjectLifeCycleListener#onProjectBranchesDeleted(Set)} of all known - * {@link ProjectLifeCycleListener} implementations. - * <p> - * This method ensures all {@link ProjectLifeCycleListener} implementations are called, even if one or more of - * them fail with an exception. - */ - void onProjectBranchesDeleted(Set<Project> projects); - - /** - * This method is called after the specified project's key has been changed and will call method - * {@link ProjectLifeCycleListener#onProjectsRekeyed(Set) onProjectsRekeyed(Set)} of all known - * {@link ProjectLifeCycleListener} implementations. - * <p> - * This method ensures all {@link ProjectLifeCycleListener} implementations are called, even if one or more of - * them fail with an exception. - */ - void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java b/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java deleted file mode 100644 index af440d60adb..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import java.util.Arrays; -import java.util.Set; -import java.util.function.Consumer; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class ProjectLifeCycleListenersImpl implements ProjectLifeCycleListeners { - private static final Logger LOG = Loggers.get(ProjectLifeCycleListenersImpl.class); - - private final ProjectLifeCycleListener[] listeners; - - /** - * Used by Pico when there is no ProjectLifeCycleListener implementation in container. - */ - public ProjectLifeCycleListenersImpl() { - this.listeners = new ProjectLifeCycleListener[0]; - } - - /** - * Used by Pico when there is at least one ProjectLifeCycleListener implementation in container. - */ - public ProjectLifeCycleListenersImpl(ProjectLifeCycleListener[] listeners) { - this.listeners = listeners; - } - - @Override - public void onProjectsDeleted(Set<Project> projects) { - checkNotNull(projects, "projects can't be null"); - if (projects.isEmpty()) { - return; - } - - Arrays.stream(listeners) - .forEach(safelyCallListener(listener -> listener.onProjectsDeleted(projects))); - } - - @Override - public void onProjectBranchesDeleted(Set<Project> projects) { - checkNotNull(projects, "projects can't be null"); - if (projects.isEmpty()) { - return; - } - - Arrays.stream(listeners) - .forEach(safelyCallListener(listener -> listener.onProjectBranchesDeleted(projects))); - } - - @Override - public void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects) { - checkNotNull(rekeyedProjects, "rekeyedProjects can't be null"); - if (rekeyedProjects.isEmpty()) { - return; - } - - Arrays.stream(listeners) - .forEach(safelyCallListener(listener -> listener.onProjectsRekeyed(rekeyedProjects))); - } - - private static Consumer<ProjectLifeCycleListener> safelyCallListener(Consumer<ProjectLifeCycleListener> task) { - return listener -> { - try { - task.accept(listener); - } catch (Error | Exception e) { - LOG.error("Call on ProjectLifeCycleListener \"{}\" failed", listener.getClass(), e); - } - }; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/RekeyedProject.java b/server/sonar-server/src/main/java/org/sonar/server/project/RekeyedProject.java deleted file mode 100644 index ecab0b148f8..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/project/RekeyedProject.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkNotNull; - -public final class RekeyedProject { - private final Project project; - private final String previousKey; - - public RekeyedProject(Project project, String previousKey) { - this.project = checkNotNull(project, "project can't be null"); - this.previousKey = checkNotNull(previousKey, "previousKey can't be null"); - } - - public Project getProject() { - return project; - } - - public String getPreviousKey() { - return previousKey; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RekeyedProject that = (RekeyedProject) o; - return Objects.equals(project, that.project) && - Objects.equals(previousKey, that.previousKey); - } - - @Override - public int hashCode() { - return Objects.hash(project, previousKey); - } - - @Override - public String toString() { - return "RekeyedProject{" + - "project=" + project + - ", previousKey='" + previousKey + '\'' + - '}'; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/Visibility.java b/server/sonar-server/src/main/java/org/sonar/server/project/Visibility.java deleted file mode 100644 index edf05180276..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/project/Visibility.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import java.util.List; - -import static java.util.Arrays.stream; -import static org.sonar.core.util.stream.MoreCollectors.toList; - -public enum Visibility { - - PRIVATE(true, "private"), - PUBLIC(false, "public"); - - private static final List<String> LABELS = stream(values()).map(Visibility::getLabel).collect(toList(values().length)); - - private final boolean isPrivate; - private final String label; - - Visibility(boolean isPrivate, String label) { - this.isPrivate = isPrivate; - this.label = label; - } - - public String getLabel() { - return label; - } - - boolean isPrivate() { - return isPrivate; - } - - public static String getLabel(boolean isPrivate) { - return stream(values()) - .filter(v -> v.isPrivate == isPrivate) - .map(Visibility::getLabel) - .findAny() - .orElseThrow(() -> new IllegalStateException("Invalid visibility boolean '" + isPrivate + "'")); - } - - public static boolean isPrivate(String label) { - return parseVisibility(label).isPrivate(); - } - - public static Visibility parseVisibility(String label) { - return stream(values()) - .filter(v -> v.label.equals(label)) - .findAny() - .orElseThrow(() -> new IllegalStateException("Invalid visibility label '" + label + "'")); - } - - public static List<String> getLabels() { - return LABELS; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/project/package-info.java deleted file mode 100644 index 205d7058e06..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/project/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ProjectsInWarning.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ProjectsInWarning.java deleted file mode 100644 index 7591c138d28..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ProjectsInWarning.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import static com.google.common.base.Preconditions.checkArgument; - -/** - * Store number of projects in warning in order for the web service api/components/search to know if warning value should be return in the quality gate facet. - * The value is updated each time the daemon {@link ProjectsInWarningDaemon} is executed - */ -public class ProjectsInWarning { - - private Long projectsInWarning; - - public void update(long projectsInWarning) { - this.projectsInWarning = projectsInWarning; - } - - public long count() { - checkArgument(isInitialized(), "Initialization has not be done"); - return projectsInWarning; - } - - boolean isInitialized() { - return projectsInWarning != null; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ProjectsInWarningDaemon.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ProjectsInWarningDaemon.java deleted file mode 100644 index 01e9978e0d0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ProjectsInWarningDaemon.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.Optional; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import org.picocontainer.Startable; -import org.sonar.api.config.Configuration; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.server.es.SearchOptions; -import org.sonar.server.measure.index.ProjectMeasuresIndex; -import org.sonar.server.measure.index.ProjectMeasuresQuery; -import org.sonar.server.util.GlobalLockManager; - -import static org.sonar.api.measures.Metric.Level.WARN; - -/** - * This class is regularly checking the number of projects in warning state, in order to not return the "Warning" value in the quality gate facet of the Projects page when there are no more projects in warning. - * - * @see <a href="https://jira.sonarsource.com/browse/SONAR-12140">SONAR-12140</a> for more information - */ -public class ProjectsInWarningDaemon implements Startable { - - final static String PROJECTS_IN_WARNING_INTERNAL_PROPERTY = "projectsInWarning"; - - private static final Logger LOG = Loggers.get(ProjectsInWarningDaemon.class); - - private static final String FREQUENCY_IN_MILLISECONDS_PROPERTY = "sonar.projectsInWarning.frequencyInMilliseconds"; - private static final int DEFAULT_FREQUENCY_IN_MILLISECONDS = 1000 * 60 * 60 * 24; - private static final String THREAD_NAME_PREFIX = "sq-projects-in-warning-service-"; - - private static final String LOCK_NAME = "ProjectsInWarn"; - private static final int LOCK_DURATION_IN_SECOND = 60 * 60; - - private final DbClient dbClient; - private final ProjectMeasuresIndex projectMeasuresIndex; - private final Configuration config; - private final GlobalLockManager lockManager; - private final ProjectsInWarning projectsInWarning; - - private ScheduledExecutorService executorService; - - public ProjectsInWarningDaemon(DbClient dbClient, ProjectMeasuresIndex projectMeasuresIndex, Configuration config, GlobalLockManager lockManager, - ProjectsInWarning projectsInWarning) { - this.dbClient = dbClient; - this.projectMeasuresIndex = projectMeasuresIndex; - this.config = config; - this.lockManager = lockManager; - this.projectsInWarning = projectsInWarning; - } - - public void notifyStart() { - try (DbSession dbSession = dbClient.openSession(false)) { - Optional<String> internalProperty = dbClient.internalPropertiesDao().selectByKey(dbSession, PROJECTS_IN_WARNING_INTERNAL_PROPERTY); - if (internalProperty.isPresent() && internalProperty.get().equals("0")) { - projectsInWarning.update(0L); - LOG.info("Counting number of projects in warning is not started as there are no projects in this situation."); - return; - } - } - LOG.info("Counting number of projects in warning is enabled."); - executorService = Executors.newSingleThreadScheduledExecutor(newThreadFactory()); - executorService.scheduleWithFixedDelay(countProjectsInWarning(), 0, frequency(), TimeUnit.MILLISECONDS); - } - - private int frequency() { - return config.getInt(FREQUENCY_IN_MILLISECONDS_PROPERTY).orElse(DEFAULT_FREQUENCY_IN_MILLISECONDS); - } - - private Runnable countProjectsInWarning() { - return () -> { - try (DbSession dbSession = dbClient.openSession(false)) { - long nbProjectsInWarning = projectMeasuresIndex.search( - new ProjectMeasuresQuery() - .setQualityGateStatus(WARN) - .setIgnoreAuthorization(true), - // We only need the number of projects in warning - new SearchOptions().setLimit(1)).getTotal(); - projectsInWarning.update(nbProjectsInWarning); - updateProjectsInWarningInDb(dbSession, nbProjectsInWarning); - if (nbProjectsInWarning == 0L) { - LOG.info("Counting number of projects in warning will be disabled as there are no more projects in warning."); - executorService.shutdown(); - } - } catch (Exception e) { - LOG.error("Error while counting number of projects in warning: {}", e); - } - }; - } - - private void updateProjectsInWarningInDb(DbSession dbSession, long nbProjectsInWarning) { - // Only one web node should do the update in db to avoid any collision - if (!lockManager.tryLock(LOCK_NAME, LOCK_DURATION_IN_SECOND)) { - return; - } - dbClient.internalPropertiesDao().save(dbSession, PROJECTS_IN_WARNING_INTERNAL_PROPERTY, Long.toString(nbProjectsInWarning)); - dbSession.commit(); - } - - @Override - public void start() { - // Nothing is done here, as this component needs to be started after ES indexing. See PlatformLevelStartup for more info. - } - - @Override - public void stop() { - if (executorService == null) { - return; - } - try { - executorService.shutdown(); - executorService.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - private static ThreadFactory newThreadFactory() { - return new ThreadFactoryBuilder() - .setNameFormat(THREAD_NAME_PREFIX + "%d") - .setPriority(Thread.MIN_PRIORITY) - .build(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java deleted file mode 100644 index fb9400b9525..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.sonar.api.measures.Metric.ValueType; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.db.qualitygate.QualityGateDto; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.measure.Rating; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.Double.parseDouble; -import static java.lang.Integer.parseInt; -import static java.lang.Long.parseLong; -import static java.lang.String.format; -import static java.util.Arrays.stream; -import static java.util.Objects.requireNonNull; -import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY; -import static org.sonar.api.measures.Metric.DIRECTION_BETTER; -import static org.sonar.api.measures.Metric.DIRECTION_NONE; -import static org.sonar.api.measures.Metric.DIRECTION_WORST; -import static org.sonar.api.measures.Metric.ValueType.RATING; -import static org.sonar.server.measure.Rating.E; -import static org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN; -import static org.sonar.server.qualitygate.Condition.Operator.LESS_THAN; -import static org.sonar.server.qualitygate.ValidRatingMetrics.isCoreRatingMetric; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public class QualityGateConditionsUpdater { - - private static final Map<Integer, ImmutableSet<Condition.Operator>> VALID_OPERATORS_BY_DIRECTION = ImmutableMap.<Integer, ImmutableSet<Condition.Operator>>builder() - .put(DIRECTION_NONE, ImmutableSet.of(GREATER_THAN, LESS_THAN)) - .put(DIRECTION_BETTER, ImmutableSet.of(LESS_THAN)) - .put(DIRECTION_WORST, ImmutableSet.of(GREATER_THAN)) - .build(); - - private static final EnumSet<ValueType> VALID_METRIC_TYPES = EnumSet.of( - ValueType.INT, - ValueType.FLOAT, - ValueType.PERCENT, - ValueType.MILLISEC, - ValueType.LEVEL, - ValueType.RATING, - ValueType.WORK_DUR); - - private static final List<String> RATING_VALID_INT_VALUES = stream(Rating.values()).map(r -> Integer.toString(r.getIndex())).collect(Collectors.toList()); - - private static final Set<String> INVALID_METRIC_KEYS = ImmutableSet.of(ALERT_STATUS_KEY, SECURITY_REVIEW_RATING_KEY); - - private final DbClient dbClient; - - public QualityGateConditionsUpdater(DbClient dbClient) { - this.dbClient = dbClient; - } - - public QualityGateConditionDto createCondition(DbSession dbSession, QualityGateDto qualityGate, String metricKey, String operator, - String errorThreshold) { - MetricDto metric = getNonNullMetric(dbSession, metricKey); - validateCondition(metric, operator, errorThreshold); - checkConditionDoesNotExistOnSameMetric(getConditions(dbSession, qualityGate.getId()), metric); - - QualityGateConditionDto newCondition = new QualityGateConditionDto().setQualityGateId(qualityGate.getId()) - .setMetricId(metric.getId()).setMetricKey(metric.getKey()) - .setOperator(operator) - .setErrorThreshold(errorThreshold); - dbClient.gateConditionDao().insert(newCondition, dbSession); - return newCondition; - } - - public QualityGateConditionDto updateCondition(DbSession dbSession, QualityGateConditionDto condition, String metricKey, String operator, - String errorThreshold) { - MetricDto metric = getNonNullMetric(dbSession, metricKey); - validateCondition(metric, operator, errorThreshold); - - condition - .setMetricId(metric.getId()) - .setMetricKey(metric.getKey()) - .setOperator(operator) - .setErrorThreshold(errorThreshold); - dbClient.gateConditionDao().update(condition, dbSession); - return condition; - } - - private MetricDto getNonNullMetric(DbSession dbSession, String metricKey) { - MetricDto metric = dbClient.metricDao().selectByKey(dbSession, metricKey); - if (metric == null) { - throw new NotFoundException(format("There is no metric with key=%s", metricKey)); - } - return metric; - } - - private Collection<QualityGateConditionDto> getConditions(DbSession dbSession, long qGateId) { - return dbClient.gateConditionDao().selectForQualityGate(dbSession, qGateId); - } - - private static void validateCondition(MetricDto metric, String operator, String errorThreshold) { - List<String> errors = new ArrayList<>(); - validateMetric(metric, errors); - checkOperator(metric, operator, errors); - checkErrorThreshold(metric, errorThreshold, errors); - checkRatingMetric(metric, errorThreshold, errors); - checkRequest(errors.isEmpty(), errors); - } - - private static void validateMetric(MetricDto metric, List<String> errors) { - check(isValid(metric), errors, "Metric '%s' cannot be used to define a condition.", metric.getKey()); - } - - private static boolean isValid(MetricDto metric) { - return !metric.isHidden() - && VALID_METRIC_TYPES.contains(ValueType.valueOf(metric.getValueType())) - && !INVALID_METRIC_KEYS.contains(metric.getKey()); - } - - private static void checkOperator(MetricDto metric, String operator, List<String> errors) { - check( - Condition.Operator.isValid(operator) && isAllowedOperator(operator, metric), - errors, - "Operator %s is not allowed for this metric.", operator); - } - - private static void checkErrorThreshold(MetricDto metric, String errorThreshold, List<String> errors) { - requireNonNull(errorThreshold, "errorThreshold can not be null"); - validateErrorThresholdValue(metric, errorThreshold, errors); - } - - private static void checkConditionDoesNotExistOnSameMetric(Collection<QualityGateConditionDto> conditions, MetricDto metric) { - if (conditions.isEmpty()) { - return; - } - - boolean conditionExists = conditions.stream().anyMatch(c -> c.getMetricId() == metric.getId()); - checkRequest(!conditionExists, format("Condition on metric '%s' already exists.", metric.getShortName())); - } - - private static boolean isAllowedOperator(String operator, MetricDto metric) { - if (VALID_OPERATORS_BY_DIRECTION.containsKey(metric.getDirection())) { - return VALID_OPERATORS_BY_DIRECTION.get(metric.getDirection()).contains(Condition.Operator.fromDbValue(operator)); - } - - return false; - } - - private static void validateErrorThresholdValue(MetricDto metric, String errorThreshold, List<String> errors) { - try { - ValueType valueType = ValueType.valueOf(metric.getValueType()); - switch (valueType) { - case BOOL: - case INT: - case RATING: - parseInt(errorThreshold); - return; - case MILLISEC: - case WORK_DUR: - parseLong(errorThreshold); - return; - case FLOAT: - case PERCENT: - parseDouble(errorThreshold); - return; - case STRING: - case LEVEL: - return; - default: - throw new IllegalArgumentException(format("Unsupported value type %s. Cannot convert condition value", valueType)); - } - } catch (Exception e) { - errors.add(format("Invalid value '%s' for metric '%s'", errorThreshold, metric.getShortName())); - } - } - - private static void checkRatingMetric(MetricDto metric, String errorThreshold, List<String> errors) { - if (!metric.getValueType().equals(RATING.name())) { - return; - } - if (!isCoreRatingMetric(metric.getKey())) { - errors.add(format("The metric '%s' cannot be used", metric.getShortName())); - } - if (!isValidRating(errorThreshold)) { - addInvalidRatingError(errorThreshold, errors); - return; - } - checkRatingGreaterThanOperator(errorThreshold, errors); - } - - private static void addInvalidRatingError(@Nullable String value, List<String> errors) { - errors.add(format("'%s' is not a valid rating", value)); - } - - private static void checkRatingGreaterThanOperator(@Nullable String value, List<String> errors) { - check(isNullOrEmpty(value) || !Objects.equals(toRating(value), E), errors, "There's no worse rating than E (%s)", value); - } - - private static Rating toRating(String value) { - return Rating.valueOf(parseInt(value)); - } - - private static boolean isValidRating(@Nullable String value) { - return isNullOrEmpty(value) || RATING_VALID_INT_VALUES.contains(value); - } - - @SuppressWarnings("unchecked") - private static boolean check(boolean expression, List<String> errors, String message, String... args) { - if (!expression) { - errors.add(format(message, (Object[]) args)); - } - return expression; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConverter.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConverter.java deleted file mode 100644 index 8ed1b406c62..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConverter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -public class QualityGateConverter { - - private static final String FIELD_LEVEL = "level"; - private static final String FIELD_IGNORED_CONDITIONS = "ignoredConditions"; - - private QualityGateConverter() { - // prevent instantiation - } - - public static String toJson(EvaluatedQualityGate gate) { - JsonObject details = new JsonObject(); - details.addProperty(FIELD_LEVEL, gate.getStatus().name()); - JsonArray conditionResults = new JsonArray(); - for (EvaluatedCondition condition : gate.getEvaluatedConditions()) { - conditionResults.add(toJson(condition)); - } - details.add("conditions", conditionResults); - details.addProperty(FIELD_IGNORED_CONDITIONS, gate.hasIgnoredConditionsOnSmallChangeset()); - return details.toString(); - } - - private static JsonObject toJson(EvaluatedCondition evaluatedCondition) { - Condition condition = evaluatedCondition.getCondition(); - - JsonObject result = new JsonObject(); - result.addProperty("metric", condition.getMetricKey()); - result.addProperty("op", condition.getOperator().getDbValue()); - if (condition.isOnLeakPeriod()) { - result.addProperty("period", 1); - } - result.addProperty("error", condition.getErrorThreshold()); - evaluatedCondition.getValue().ifPresent(v -> result.addProperty("actual", v)); - result.addProperty(FIELD_LEVEL, evaluatedCondition.getStatus().name()); - return result; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java deleted file mode 100644 index 209fd855df4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import org.sonar.core.platform.Module; - -public class QualityGateModule extends Module { - @Override - protected void configureModule() { - add( - QualityGateUpdater.class, - QualityGateConditionsUpdater.class, - QualityGateFinder.class, - QualityGateEvaluatorImpl.class, - ProjectsInWarningDaemon.class, - ProjectsInWarning.class); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java deleted file mode 100644 index 93658d2aa27..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import org.sonar.core.util.UuidFactory; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.db.qualitygate.QualityGateDto; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.sonar.server.util.Validation.IS_ALREADY_USED_MESSAGE; - -public class QualityGateUpdater { - - private final DbClient dbClient; - private final UuidFactory uuidFactory; - - public QualityGateUpdater(DbClient dbClient, UuidFactory uuidFactory) { - this.dbClient = dbClient; - this.uuidFactory = uuidFactory; - } - - public QualityGateDto create(DbSession dbSession, OrganizationDto organizationDto, String name) { - validateQualityGate(dbSession, organizationDto, name); - QualityGateDto newQualityGate = new QualityGateDto() - .setName(name) - .setBuiltIn(false) - .setUuid(uuidFactory.create()); - dbClient.qualityGateDao().insert(dbSession, newQualityGate); - dbClient.qualityGateDao().associate(dbSession, uuidFactory.create(), organizationDto, newQualityGate); - return newQualityGate; - } - - public QualityGateDto copy(DbSession dbSession, OrganizationDto organizationDto, QualityGateDto qualityGateDto, String destinationName) { - - QualityGateDto destinationGate = create(dbSession, organizationDto, destinationName); - - for (QualityGateConditionDto sourceCondition : dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGateDto.getId())) { - dbClient.gateConditionDao().insert(new QualityGateConditionDto() - .setQualityGateId(destinationGate.getId()) - .setMetricId(sourceCondition.getMetricId()) - .setOperator(sourceCondition.getOperator()) - .setErrorThreshold(sourceCondition.getErrorThreshold()), - dbSession); - } - - return destinationGate; - } - - private void validateQualityGate(DbSession dbSession, OrganizationDto organizationDto, String name) { - checkQualityGateDoesNotAlreadyExist(dbSession, organizationDto, name); - } - - public void setDefault(DbSession dbSession, OrganizationDto organizationDto, QualityGateDto qualityGateDto) { - organizationDto.setDefaultQualityGateUuid(qualityGateDto.getUuid()); - dbClient.qualityGateDao().update(qualityGateDto, dbSession); - } - - private void checkQualityGateDoesNotAlreadyExist(DbSession dbSession, OrganizationDto organizationDto, String name) { - QualityGateDto existingQgate = dbClient.qualityGateDao().selectByOrganizationAndName(dbSession, organizationDto, name); - checkArgument(existingQgate == null, IS_ALREADY_USED_MESSAGE, "Name"); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java deleted file mode 100644 index 35e0af5fff2..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import javax.annotation.CheckForNull; -import org.picocontainer.Startable; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.core.util.UuidFactory; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.qualitygate.QualityGateConditionDao; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.db.qualitygate.QualityGateDao; -import org.sonar.db.qualitygate.QualityGateDto; -import org.sonar.server.measure.Rating; - -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toMap; -import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY; -import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN; -import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN; - -public class RegisterQualityGates implements Startable { - - private static final Logger LOGGER = Loggers.get(RegisterQualityGates.class); - - private static final String BUILTIN_QUALITY_GATE_NAME = "Sonar way"; - private static final String A_RATING = Integer.toString(Rating.A.getIndex()); - - private static final List<QualityGateCondition> QUALITY_GATE_CONDITIONS = asList( - new QualityGateCondition().setMetricKey(NEW_SECURITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING), - new QualityGateCondition().setMetricKey(NEW_RELIABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING), - new QualityGateCondition().setMetricKey(NEW_MAINTAINABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING), - new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("80"), - new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("3")); - - private final DbClient dbClient; - private final QualityGateConditionsUpdater qualityGateConditionsUpdater; - private final QualityGateDao qualityGateDao; - private final QualityGateConditionDao qualityGateConditionDao; - private final UuidFactory uuidFactory; - private final System2 system2; - - public RegisterQualityGates(DbClient dbClient, - QualityGateConditionsUpdater qualityGateConditionsUpdater, UuidFactory uuidFactory, System2 system2) { - this.dbClient = dbClient; - this.qualityGateConditionsUpdater = qualityGateConditionsUpdater; - this.qualityGateDao = dbClient.qualityGateDao(); - this.qualityGateConditionDao = dbClient.gateConditionDao(); - this.uuidFactory = uuidFactory; - this.system2 = system2; - } - - @Override - public void start() { - try (DbSession dbSession = dbClient.openSession(false)) { - QualityGateDto builtin = qualityGateDao.selectByName(dbSession, BUILTIN_QUALITY_GATE_NAME); - - // Create builtin if not present - if (builtin == null) { - LOGGER.info("Built-in quality gate [{}] has been created", BUILTIN_QUALITY_GATE_NAME); - builtin = createQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME); - } - - // Set builtin if missing - if (!builtin.isBuiltIn()) { - builtin.setBuiltIn(true); - dbClient.qualityGateDao().update(builtin, dbSession); - LOGGER.info("Quality gate [{}] has been set as built-in", BUILTIN_QUALITY_GATE_NAME); - } - - updateQualityConditionsIfRequired(dbSession, builtin); - - qualityGateDao.ensureOneBuiltInQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME); - - dbSession.commit(); - } - } - - private void updateQualityConditionsIfRequired(DbSession dbSession, QualityGateDto builtin) { - Map<Long, String> idToKeyMetric = dbClient.metricDao().selectAll(dbSession).stream() - .collect(toMap(metricDto -> metricDto.getId().longValue(), MetricDto::getKey)); - - List<QualityGateCondition> qualityGateConditions = qualityGateConditionDao.selectForQualityGate(dbSession, builtin.getId()) - .stream() - .map(dto -> QualityGateCondition.from(dto, idToKeyMetric)) - .collect(MoreCollectors.toList()); - - // Find all conditions that are not present in QUALITY_GATE_CONDITIONS - // Those conditions must be deleted - List<QualityGateCondition> qgConditionsToBeDeleted = new ArrayList<>(qualityGateConditions); - qgConditionsToBeDeleted.removeAll(QUALITY_GATE_CONDITIONS); - qgConditionsToBeDeleted - .forEach(qgc -> qualityGateConditionDao.delete(qgc.toQualityGateDto(builtin.getId()), dbSession)); - - // Find all conditions that are not present in qualityGateConditions - // Those conditions must be created - List<QualityGateCondition> qgConditionsToBeCreated = new ArrayList<>(QUALITY_GATE_CONDITIONS); - qgConditionsToBeCreated.removeAll(qualityGateConditions); - qgConditionsToBeCreated - .forEach(qgc -> qualityGateConditionsUpdater.createCondition(dbSession, builtin, qgc.getMetricKey(), qgc.getOperator(), - qgc.getErrorThreshold())); - - if (!qgConditionsToBeCreated.isEmpty() || !qgConditionsToBeDeleted.isEmpty()) { - LOGGER.info("Built-in quality gate's conditions of [{}] has been updated", BUILTIN_QUALITY_GATE_NAME); - } - } - - @Override - public void stop() { - // do nothing - } - - private QualityGateDto createQualityGate(DbSession dbSession, String name) { - QualityGateDto qualityGate = new QualityGateDto() - .setName(name) - .setBuiltIn(true) - .setUuid(uuidFactory.create()) - .setCreatedAt(new Date(system2.now())); - return dbClient.qualityGateDao().insert(dbSession, qualityGate); - } - - private static class QualityGateCondition { - private Long id; - private String metricKey; - private String operator; - private String errorThreshold; - - public static QualityGateCondition from(QualityGateConditionDto qualityGateConditionDto, Map<Long, String> mapping) { - return new QualityGateCondition() - .setId(qualityGateConditionDto.getId()) - .setMetricKey(mapping.get(qualityGateConditionDto.getMetricId())) - .setOperator(qualityGateConditionDto.getOperator()) - .setErrorThreshold(qualityGateConditionDto.getErrorThreshold()); - } - - @CheckForNull - public Long getId() { - return id; - } - - public QualityGateCondition setId(Long id) { - this.id = id; - return this; - } - - public String getMetricKey() { - return metricKey; - } - - public QualityGateCondition setMetricKey(String metricKey) { - this.metricKey = metricKey; - return this; - } - - public String getOperator() { - return operator; - } - - public QualityGateCondition setOperator(String operator) { - this.operator = operator; - return this; - } - - public String getErrorThreshold() { - return errorThreshold; - } - - public QualityGateCondition setErrorThreshold(String errorThreshold) { - this.errorThreshold = errorThreshold; - return this; - } - - public QualityGateConditionDto toQualityGateDto(long qualityGateId) { - return new QualityGateConditionDto() - .setId(id) - .setMetricKey(metricKey) - .setOperator(operator) - .setErrorThreshold(errorThreshold) - .setQualityGateId(qualityGateId); - } - - // id does not belongs to equals to be able to be compared with builtin - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - QualityGateCondition that = (QualityGateCondition) o; - return Objects.equals(metricKey, that.metricKey) && - Objects.equals(operator, that.operator) && - Objects.equals(errorThreshold, that.errorThreshold); - } - - // id does not belongs to hashcode to be able to be compared with builtin - @Override - public int hashCode() { - return Objects.hash(metricKey, operator, errorThreshold); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ValidRatingMetrics.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ValidRatingMetrics.java deleted file mode 100644 index e408251eb19..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ValidRatingMetrics.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import java.util.Set; -import org.sonar.api.measures.CoreMetrics; - -import static org.sonar.api.measures.Metric.ValueType.RATING; -import static org.sonar.core.util.stream.MoreCollectors.toSet; - -public class ValidRatingMetrics { - - private static final Set<String> CORE_RATING_METRICS = CoreMetrics.getMetrics().stream() - .filter(metric -> metric.getType().equals(RATING)) - .map(org.sonar.api.measures.Metric::getKey) - .collect(toSet()); - - private ValidRatingMetrics() { - // only static methods - } - - public static boolean isCoreRatingMetric(String metricKey) { - return CORE_RATING_METRICS.contains(metricKey); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEvent.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEvent.java deleted file mode 100644 index 6953a77575e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEvent.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import java.util.Optional; -import java.util.function.Supplier; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import org.sonar.api.config.Configuration; -import org.sonar.api.measures.Metric; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.server.qualitygate.EvaluatedQualityGate; - -import static java.util.Objects.requireNonNull; - -@Immutable -public class QGChangeEvent { - private final ComponentDto project; - private final BranchDto branch; - private final SnapshotDto analysis; - private final Configuration projectConfiguration; - private final Metric.Level previousStatus; - private final Supplier<Optional<EvaluatedQualityGate>> qualityGateSupplier; - - public QGChangeEvent(ComponentDto project, BranchDto branch, SnapshotDto analysis, Configuration projectConfiguration, - @Nullable Metric.Level previousStatus, Supplier<Optional<EvaluatedQualityGate>> qualityGateSupplier) { - this.project = requireNonNull(project, "project can't be null"); - this.branch = requireNonNull(branch, "branch can't be null"); - this.analysis = requireNonNull(analysis, "analysis can't be null"); - this.projectConfiguration = requireNonNull(projectConfiguration, "projectConfiguration can't be null"); - this.previousStatus = previousStatus; - this.qualityGateSupplier = requireNonNull(qualityGateSupplier, "qualityGateSupplier can't be null"); - } - - public BranchDto getBranch() { - return branch; - } - - public ComponentDto getProject() { - return project; - } - - public SnapshotDto getAnalysis() { - return analysis; - } - - public Configuration getProjectConfiguration() { - return projectConfiguration; - } - - public Optional<Metric.Level> getPreviousStatus() { - return Optional.ofNullable(previousStatus); - } - - public Supplier<Optional<EvaluatedQualityGate>> getQualityGateSupplier() { - return qualityGateSupplier; - } - - @Override - public String toString() { - return "QGChangeEvent{" + - "project=" + toString(project) + - ", branch=" + toString(branch) + - ", analysis=" + toString(analysis) + - ", projectConfiguration=" + projectConfiguration + - ", previousStatus=" + previousStatus + - ", qualityGateSupplier=" + qualityGateSupplier + - '}'; - } - - private static String toString(ComponentDto project) { - return project.uuid() + ":" + project.getKey(); - } - - private static String toString(BranchDto branch) { - return branch.getBranchType() + ":" + branch.getUuid() + ":" + branch.getProjectUuid() + ":" + branch.getMergeBranchUuid(); - } - - private static String toString(SnapshotDto analysis) { - return analysis.getUuid() + ":" + analysis.getCreatedAt(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java deleted file mode 100644 index c3baf201471..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import java.util.EnumSet; -import java.util.Set; -import org.sonar.api.rules.RuleType; -import org.sonar.api.server.ServerSide; - -@ServerSide -public interface QGChangeEventListener { - /** - * Called consequently to a change done on one or more issue of a given project. - * - * @param qualityGateEvent can not be {@code null} - * @param changedIssues can not be {@code null} nor empty - */ - void onIssueChanges(QGChangeEvent qualityGateEvent, Set<ChangedIssue> changedIssues); - - interface ChangedIssue { - - String getKey(); - - Status getStatus(); - - RuleType getType(); - - String getSeverity(); - - default boolean isNotClosed() { - return !Status.CLOSED_STATUSES.contains(getStatus()); - } - } - - enum Status { - OPEN, - CONFIRMED, - REOPENED, - RESOLVED_FP, - RESOLVED_WF, - RESOLVED_FIXED, - TO_REVIEW, - IN_REVIEW, - REVIEWED; - - protected static final Set<Status> CLOSED_STATUSES = EnumSet.of(CONFIRMED, RESOLVED_FIXED, RESOLVED_FP, RESOLVED_WF); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListeners.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListeners.java deleted file mode 100644 index e2e66b555de..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListeners.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import java.util.Collection; -import java.util.List; -import org.sonar.core.issue.DefaultIssue; - -public interface QGChangeEventListeners { - - void broadcastOnIssueChange(List<DefaultIssue> changedIssues, Collection<QGChangeEvent> qgChangeEvents); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImpl.java deleted file mode 100644 index 76a4c2bebf1..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImpl.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import com.google.common.collect.Multimap; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.RuleType; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.server.qualitygate.changeevent.QGChangeEventListener.ChangedIssue; - -import static java.lang.String.format; -import static org.sonar.core.util.stream.MoreCollectors.toSet; - -/** - * Broadcast a given collection of {@link QGChangeEvent} for a specific trigger to all the registered - * {@link QGChangeEventListener} in Pico. - * - * This class ensures that an {@link Exception} occurring calling one of the {@link QGChangeEventListener} doesn't - * prevent from calling the others. - */ -public class QGChangeEventListenersImpl implements QGChangeEventListeners { - private static final Logger LOG = Loggers.get(QGChangeEventListenersImpl.class); - - private final QGChangeEventListener[] listeners; - - /** - * Used by Pico when there is no QGChangeEventListener instance in container. - */ - public QGChangeEventListenersImpl() { - this.listeners = new QGChangeEventListener[0]; - } - - public QGChangeEventListenersImpl(QGChangeEventListener[] listeners) { - this.listeners = listeners; - } - - @Override - public void broadcastOnIssueChange(List<DefaultIssue> issues, Collection<QGChangeEvent> changeEvents) { - if (listeners.length == 0 || issues.isEmpty() || changeEvents.isEmpty()) { - return; - } - - try { - Multimap<String, QGChangeEvent> eventsByComponentUuid = changeEvents.stream() - .collect(MoreCollectors.index(t -> t.getProject().uuid())); - Multimap<String, DefaultIssue> issueByComponentUuid = issues.stream() - .collect(MoreCollectors.index(DefaultIssue::projectUuid)); - - issueByComponentUuid.asMap() - .forEach((componentUuid, value) -> { - Collection<QGChangeEvent> qgChangeEvents = eventsByComponentUuid.get(componentUuid); - if (!qgChangeEvents.isEmpty()) { - Set<ChangedIssue> changedIssues = value.stream() - .map(ChangedIssueImpl::new) - .collect(toSet()); - qgChangeEvents - .forEach(changeEvent -> Arrays.stream(listeners) - .forEach(listener -> broadcastTo(changedIssues, changeEvent, listener))); - } - }); - } catch (Error e) { - LOG.warn(format("Broadcasting to listeners failed for %s events", changeEvents.size()), e); - } - } - - private static void broadcastTo(Set<ChangedIssue> changedIssues, QGChangeEvent changeEvent, QGChangeEventListener listener) { - try { - LOG.trace("calling onChange() on listener {} for events {}...", listener.getClass().getName(), changeEvent); - listener.onIssueChanges(changeEvent, changedIssues); - } catch (Exception e) { - LOG.warn(format("onChange() call failed on listener %s for events %s", listener.getClass().getName(), changeEvent), e); - } - } - - static class ChangedIssueImpl implements ChangedIssue { - private final String key; - private final QGChangeEventListener.Status status; - private final RuleType type; - private final String severity; - - ChangedIssueImpl(DefaultIssue issue) { - this.key = issue.key(); - this.status = statusOf(issue); - this.type = issue.type(); - this.severity = issue.severity(); - } - - static QGChangeEventListener.Status statusOf(DefaultIssue issue) { - switch (issue.status()) { - case Issue.STATUS_OPEN: - return QGChangeEventListener.Status.OPEN; - case Issue.STATUS_CONFIRMED: - return QGChangeEventListener.Status.CONFIRMED; - case Issue.STATUS_REOPENED: - return QGChangeEventListener.Status.REOPENED; - case Issue.STATUS_TO_REVIEW: - return QGChangeEventListener.Status.TO_REVIEW; - case Issue.STATUS_IN_REVIEW: - return QGChangeEventListener.Status.IN_REVIEW; - case Issue.STATUS_REVIEWED: - return QGChangeEventListener.Status.REVIEWED; - case Issue.STATUS_RESOLVED: - return statusOfResolved(issue); - default: - throw new IllegalStateException("Unexpected status: " + issue.status()); - } - } - - private static QGChangeEventListener.Status statusOfResolved(DefaultIssue issue) { - String resolution = issue.resolution(); - Objects.requireNonNull(resolution, "A resolved issue should have a resolution"); - switch (resolution) { - case Issue.RESOLUTION_FALSE_POSITIVE: - return QGChangeEventListener.Status.RESOLVED_FP; - case Issue.RESOLUTION_WONT_FIX: - return QGChangeEventListener.Status.RESOLVED_WF; - case Issue.RESOLUTION_FIXED: - return QGChangeEventListener.Status.RESOLVED_FIXED; - default: - throw new IllegalStateException("Unexpected resolution for a resolved issue: " + resolution); - } - } - - @Override - public String getKey() { - return key; - } - - @Override - public QGChangeEventListener.Status getStatus() { - return status; - } - - @Override - public RuleType getType() { - return type; - } - - @Override - public String getSeverity() { - return severity; - } - - @Override - public String toString() { - return "ChangedIssueImpl{" + - "key='" + key + '\'' + - ", status=" + status + - ", type=" + type + - ", severity=" + severity + - '}'; - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/Trigger.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/Trigger.java deleted file mode 100644 index 6ef8397046a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/Trigger.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -public enum Trigger { - ISSUE_CHANGE -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/package-info.java deleted file mode 100644 index ed52cd87a47..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/changeevent/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/package-info.java deleted file mode 100644 index 4d247e4707e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BulkChangeResult.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BulkChangeResult.java deleted file mode 100644 index 91a31ca76d9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BulkChangeResult.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class BulkChangeResult { - - private final List<String> errors = new ArrayList<>(); - private int succeeded = 0; - private int failed = 0; - private final List<ActiveRuleChange> changes = new ArrayList<>(); - - public List<String> getErrors() { - return errors; - } - - public int countSucceeded() { - return succeeded; - } - - public int countFailed() { - return failed; - } - - void incrementSucceeded() { - succeeded++; - } - - void incrementFailed() { - failed++; - } - - void addChanges(Collection<ActiveRuleChange> c) { - this.changes.addAll(c); - } - - public List<ActiveRuleChange> getChanges() { - return changes; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java deleted file mode 100644 index dd418601955..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.io.Reader; -import java.io.Writer; -import javax.annotation.Nullable; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileDto; - -/** - * Backup and restore a Quality profile. - */ -public interface QProfileBackuper { - - void backup(DbSession dbSession, QProfileDto profile, Writer backupWriter); - - /** - * Restore backup on a profile in the specified organization. The parameter {@code overriddenProfileName} - * is the name of the profile to be used. If the parameter is null, then the name is loaded from the backup. - * The profile is created if it does not exist. - */ - QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName); - - /** - * Restore backup on an existing profile. - */ - QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QProfileDto profile); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java deleted file mode 100644 index 48658b6afd0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import java.io.Reader; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.CompareToBuilder; -import org.codehaus.staxmate.SMInputFactory; -import org.codehaus.staxmate.in.SMHierarchicCursor; -import org.codehaus.staxmate.in.SMInputCursor; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.text.XmlWriter; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; - -import static com.google.common.base.Preconditions.checkArgument; - -@ServerSide -public class QProfileBackuperImpl implements QProfileBackuper { - - private static final Joiner RULE_KEY_JOINER = Joiner.on(", ").skipNulls(); - - private static final String ATTRIBUTE_PROFILE = "profile"; - private static final String ATTRIBUTE_NAME = "name"; - private static final String ATTRIBUTE_LANGUAGE = "language"; - - private static final String ATTRIBUTE_RULES = "rules"; - private static final String ATTRIBUTE_RULE = "rule"; - private static final String ATTRIBUTE_REPOSITORY_KEY = "repositoryKey"; - private static final String ATTRIBUTE_KEY = "key"; - private static final String ATTRIBUTE_PRIORITY = "priority"; - - private static final String ATTRIBUTE_PARAMETERS = "parameters"; - private static final String ATTRIBUTE_PARAMETER = "parameter"; - private static final String ATTRIBUTE_PARAMETER_KEY = "key"; - private static final String ATTRIBUTE_PARAMETER_VALUE = "value"; - - private final DbClient db; - private final QProfileReset profileReset; - private final QProfileFactory profileFactory; - - public QProfileBackuperImpl(DbClient db, QProfileReset profileReset, QProfileFactory profileFactory) { - this.db = db; - this.profileReset = profileReset; - this.profileFactory = profileFactory; - } - - @Override - public void backup(DbSession dbSession, QProfileDto profile, Writer writer) { - List<OrgActiveRuleDto> activeRules = db.activeRuleDao().selectByProfile(dbSession, profile); - activeRules.sort(BackupActiveRuleComparator.INSTANCE); - writeXml(dbSession, writer, profile, activeRules.iterator()); - } - - private void writeXml(DbSession dbSession, Writer writer, QProfileDto profile, Iterator<OrgActiveRuleDto> activeRules) { - XmlWriter xml = XmlWriter.of(writer).declaration(); - xml.begin(ATTRIBUTE_PROFILE); - xml.prop(ATTRIBUTE_NAME, profile.getName()); - xml.prop(ATTRIBUTE_LANGUAGE, profile.getLanguage()); - xml.begin(ATTRIBUTE_RULES); - while (activeRules.hasNext()) { - ActiveRuleDto activeRule = activeRules.next(); - xml.begin(ATTRIBUTE_RULE); - xml.prop(ATTRIBUTE_REPOSITORY_KEY, activeRule.getRuleKey().repository()); - xml.prop(ATTRIBUTE_KEY, activeRule.getRuleKey().rule()); - xml.prop(ATTRIBUTE_PRIORITY, activeRule.getSeverityString()); - xml.begin(ATTRIBUTE_PARAMETERS); - for (ActiveRuleParamDto param : db.activeRuleDao().selectParamsByActiveRuleId(dbSession, activeRule.getId())) { - xml - .begin(ATTRIBUTE_PARAMETER) - .prop(ATTRIBUTE_PARAMETER_KEY, param.getKey()) - .prop(ATTRIBUTE_PARAMETER_VALUE, param.getValue()) - .end(); - } - xml.end(ATTRIBUTE_PARAMETERS); - xml.end(ATTRIBUTE_RULE); - } - xml.end(ATTRIBUTE_RULES).end(ATTRIBUTE_PROFILE).close(); - } - - @Override - public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) { - return restore(dbSession, backup, nameInBackup -> { - QProfileName targetName = nameInBackup; - if (overriddenProfileName != null) { - targetName = new QProfileName(nameInBackup.getLanguage(), overriddenProfileName); - } - return profileFactory.getOrCreateCustom(dbSession, organization, targetName); - }); - } - - @Override - public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QProfileDto profile) { - return restore(dbSession, backup, nameInBackup -> { - checkArgument(profile.getLanguage().equals(nameInBackup.getLanguage()), - "Can't restore %s backup on %s profile with key [%s]. Languages are different.", nameInBackup.getLanguage(), profile.getLanguage(), profile.getKee()); - return profile; - }); - } - - private QProfileRestoreSummary restore(DbSession dbSession, Reader backup, Function<QProfileName, QProfileDto> profileLoader) { - try { - String profileLang = null; - String profileName = null; - List<Rule> rules = Lists.newArrayList(); - SMInputFactory inputFactory = initStax(); - SMHierarchicCursor rootC = inputFactory.rootElementCursor(backup); - rootC.advance(); // <profile> - if (!ATTRIBUTE_PROFILE.equals(rootC.getLocalName())) { - throw new IllegalArgumentException("Backup XML is not valid. Root element must be <profile>."); - } - SMInputCursor cursor = rootC.childElementCursor(); - while (cursor.getNext() != null) { - String nodeName = cursor.getLocalName(); - if (StringUtils.equals(ATTRIBUTE_NAME, nodeName)) { - profileName = StringUtils.trim(cursor.collectDescendantText(false)); - - } else if (StringUtils.equals(ATTRIBUTE_LANGUAGE, nodeName)) { - profileLang = StringUtils.trim(cursor.collectDescendantText(false)); - - } else if (StringUtils.equals(ATTRIBUTE_RULES, nodeName)) { - SMInputCursor rulesCursor = cursor.childElementCursor("rule"); - rules = parseRuleActivations(rulesCursor); - } - } - - QProfileName targetName = new QProfileName(profileLang, profileName); - QProfileDto targetProfile = profileLoader.apply(targetName); - List<RuleActivation> ruleActivations = toRuleActivations(dbSession, rules); - BulkChangeResult changes = profileReset.reset(dbSession, targetProfile, ruleActivations); - return new QProfileRestoreSummary(targetProfile, changes); - } catch (XMLStreamException e) { - throw new IllegalArgumentException("Fail to restore Quality profile backup, XML document is not well formed", e); - } - } - - private List<RuleActivation> toRuleActivations(DbSession dbSession, List<Rule> rules) { - List<RuleKey> ruleKeys = rules.stream() - .map(r -> r.ruleKey) - .collect(MoreCollectors.toList()); - Map<RuleKey, RuleDefinitionDto> ruleDefinitionsByKey = db.ruleDao().selectDefinitionByKeys(dbSession, ruleKeys) - .stream() - .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey)); - - List<RuleDefinitionDto> externalRules = ruleDefinitionsByKey.values().stream() - .filter(RuleDefinitionDto::isExternal) - .collect(Collectors.toList()); - - if (!externalRules.isEmpty()) { - throw new IllegalArgumentException("The quality profile cannot be restored as it contains rules from external rule engines: " - + externalRules.stream().map(r -> r.getKey().toString()).collect(Collectors.joining(", "))); - } - - return rules.stream() - .map(r -> { - RuleDefinitionDto ruleDefinition = ruleDefinitionsByKey.get(r.ruleKey); - if (ruleDefinition == null) { - return null; - } - return RuleActivation.create(ruleDefinition.getId(), r.severity, r.parameters); - }) - .filter(Objects::nonNull) - .collect(MoreCollectors.toList(rules.size())); - } - - private static final class Rule { - private final RuleKey ruleKey; - private final String severity; - private final Map<String, String> parameters; - - private Rule(RuleKey ruleKey, String severity, Map<String, String> parameters) { - this.ruleKey = ruleKey; - this.severity = severity; - this.parameters = parameters; - } - } - - private static List<Rule> parseRuleActivations(SMInputCursor rulesCursor) throws XMLStreamException { - List<Rule> activations = new ArrayList<>(); - Set<RuleKey> activatedKeys = new HashSet<>(); - List<RuleKey> duplicatedKeys = new ArrayList<>(); - while (rulesCursor.getNext() != null) { - SMInputCursor ruleCursor = rulesCursor.childElementCursor(); - String repositoryKey = null; - String key = null; - String severity = null; - Map<String, String> parameters = new HashMap<>(); - while (ruleCursor.getNext() != null) { - String nodeName = ruleCursor.getLocalName(); - if (StringUtils.equals(ATTRIBUTE_REPOSITORY_KEY, nodeName)) { - repositoryKey = StringUtils.trim(ruleCursor.collectDescendantText(false)); - - } else if (StringUtils.equals(ATTRIBUTE_KEY, nodeName)) { - key = StringUtils.trim(ruleCursor.collectDescendantText(false)); - - } else if (StringUtils.equals(ATTRIBUTE_PRIORITY, nodeName)) { - severity = StringUtils.trim(ruleCursor.collectDescendantText(false)); - - } else if (StringUtils.equals(ATTRIBUTE_PARAMETERS, nodeName)) { - SMInputCursor propsCursor = ruleCursor.childElementCursor(ATTRIBUTE_PARAMETER); - readParameters(propsCursor, parameters); - } - } - RuleKey ruleKey = RuleKey.of(repositoryKey, key); - if (activatedKeys.contains(ruleKey)) { - duplicatedKeys.add(ruleKey); - } - activatedKeys.add(ruleKey); - activations.add(new Rule(ruleKey, severity, parameters)); - } - if (!duplicatedKeys.isEmpty()) { - throw new IllegalArgumentException("The quality profile cannot be restored as it contains duplicates for the following rules: " + - RULE_KEY_JOINER.join(duplicatedKeys)); - } - return activations; - } - - private static void readParameters(SMInputCursor propsCursor, Map<String, String> parameters) throws XMLStreamException { - while (propsCursor.getNext() != null) { - SMInputCursor propCursor = propsCursor.childElementCursor(); - String key = null; - String value = null; - while (propCursor.getNext() != null) { - String nodeName = propCursor.getLocalName(); - if (StringUtils.equals(ATTRIBUTE_PARAMETER_KEY, nodeName)) { - key = StringUtils.trim(propCursor.collectDescendantText(false)); - } else if (StringUtils.equals(ATTRIBUTE_PARAMETER_VALUE, nodeName)) { - value = StringUtils.trim(propCursor.collectDescendantText(false)); - } - } - if (key != null) { - parameters.put(key, value); - } - } - } - - private static SMInputFactory initStax() { - XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); - xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE); - xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE); - // just so it won't try to load DTD in if there's DOCTYPE - xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); - xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE); - return new SMInputFactory(xmlFactory); - } - - private enum BackupActiveRuleComparator implements Comparator<ActiveRuleDto> { - INSTANCE; - - @Override - public int compare(ActiveRuleDto o1, ActiveRuleDto o2) { - return new CompareToBuilder() - .append(o1.getRuleKey().repository(), o2.getRuleKey().repository()) - .append(o1.getRuleKey().rule(), o2.getRuleKey().rule()) - .toComparison(); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileComparison.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileComparison.java deleted file mode 100644 index 03bd79fcd43..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileComparison.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.base.Function; -import com.google.common.collect.MapDifference; -import com.google.common.collect.Maps; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nonnull; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; - -@ServerSide -public class QProfileComparison { - - private final DbClient dbClient; - - public QProfileComparison(DbClient dbClient) { - this.dbClient = dbClient; - } - - public QProfileComparisonResult compare(DbSession dbSession, QProfileDto left, QProfileDto right) { - Map<RuleKey, OrgActiveRuleDto> leftActiveRulesByRuleKey = loadActiveRules(dbSession, left); - Map<RuleKey, OrgActiveRuleDto> rightActiveRulesByRuleKey = loadActiveRules(dbSession, right); - - Set<RuleKey> allRules = new HashSet<>(); - allRules.addAll(leftActiveRulesByRuleKey.keySet()); - allRules.addAll(rightActiveRulesByRuleKey.keySet()); - - QProfileComparisonResult result = new QProfileComparisonResult(left, right); - for (RuleKey ruleKey : allRules) { - if (!leftActiveRulesByRuleKey.containsKey(ruleKey)) { - result.inRight.put(ruleKey, rightActiveRulesByRuleKey.get(ruleKey)); - } else if (!rightActiveRulesByRuleKey.containsKey(ruleKey)) { - result.inLeft.put(ruleKey, leftActiveRulesByRuleKey.get(ruleKey)); - } else { - compareActivationParams(dbSession, leftActiveRulesByRuleKey.get(ruleKey), rightActiveRulesByRuleKey.get(ruleKey), result); - } - } - return result; - } - - private void compareActivationParams(DbSession session, ActiveRuleDto leftRule, ActiveRuleDto rightRule, QProfileComparisonResult result) { - RuleKey key = leftRule.getRuleKey(); - Map<String, String> leftParams = paramDtoToMap(dbClient.activeRuleDao().selectParamsByActiveRuleId(session, leftRule.getId())); - Map<String, String> rightParams = paramDtoToMap(dbClient.activeRuleDao().selectParamsByActiveRuleId(session, rightRule.getId())); - if (leftParams.equals(rightParams) && leftRule.getSeverityString().equals(rightRule.getSeverityString())) { - result.same.put(key, leftRule); - } else { - ActiveRuleDiff diff = new ActiveRuleDiff(); - - diff.leftSeverity = leftRule.getSeverityString(); - diff.rightSeverity = rightRule.getSeverityString(); - - diff.paramDifference = Maps.difference(leftParams, rightParams); - result.modified.put(key, diff); - } - } - - private Map<RuleKey, OrgActiveRuleDto> loadActiveRules(DbSession dbSession, QProfileDto profile) { - return Maps.uniqueIndex(dbClient.activeRuleDao().selectByProfile(dbSession, profile), ActiveRuleToRuleKey.INSTANCE); - } - - public static class QProfileComparisonResult { - - private final QProfileDto left; - private final QProfileDto right; - private final Map<RuleKey, ActiveRuleDto> inLeft = Maps.newHashMap(); - private final Map<RuleKey, ActiveRuleDto> inRight = Maps.newHashMap(); - private final Map<RuleKey, ActiveRuleDiff> modified = Maps.newHashMap(); - private final Map<RuleKey, ActiveRuleDto> same = Maps.newHashMap(); - - public QProfileComparisonResult(QProfileDto left, QProfileDto right) { - this.left = left; - this.right = right; - } - - public QProfileDto left() { - return left; - } - - public QProfileDto right() { - return right; - } - - public Map<RuleKey, ActiveRuleDto> inLeft() { - return inLeft; - } - - public Map<RuleKey, ActiveRuleDto> inRight() { - return inRight; - } - - public Map<RuleKey, ActiveRuleDiff> modified() { - return modified; - } - - public Map<RuleKey, ActiveRuleDto> same() { - return same; - } - - public Collection<RuleKey> collectRuleKeys() { - Set<RuleKey> keys = new HashSet<>(); - keys.addAll(inLeft.keySet()); - keys.addAll(inRight.keySet()); - keys.addAll(modified.keySet()); - keys.addAll(same.keySet()); - return keys; - } - } - - public static class ActiveRuleDiff { - private String leftSeverity; - private String rightSeverity; - private MapDifference<String, String> paramDifference; - - public String leftSeverity() { - return leftSeverity; - } - - public String rightSeverity() { - return rightSeverity; - } - - public MapDifference<String, String> paramDifference() { - return paramDifference; - } - } - - private enum ActiveRuleToRuleKey implements Function<ActiveRuleDto, RuleKey> { - INSTANCE; - - @Override - public RuleKey apply(@Nonnull ActiveRuleDto input) { - return input.getRuleKey(); - } - } - - private static Map<String, String> paramDtoToMap(List<ActiveRuleParamDto> params) { - Map<String, String> map = new HashMap<>(); - for (ActiveRuleParamDto dto : params) { - map.put(dto.getKey(), dto.getValue()); - } - return map; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java deleted file mode 100644 index 4b65da3c12c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import org.apache.commons.io.FileUtils; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.TempFolder; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileDto; - -import static java.nio.charset.StandardCharsets.UTF_8; - -@ServerSide -public class QProfileCopier { - - private final DbClient db; - private final QProfileFactory factory; - private final QProfileBackuper backuper; - private final TempFolder temp; - - public QProfileCopier(DbClient db, QProfileFactory factory, QProfileBackuper backuper, TempFolder temp) { - this.db = db; - this.factory = factory; - this.backuper = backuper; - this.temp = temp; - } - - public QProfileDto copyToName(DbSession dbSession, QProfileDto sourceProfile, String toName) { - OrganizationDto organization = db.organizationDao().selectByUuid(dbSession, sourceProfile.getOrganizationUuid()) - .orElseThrow(() -> new IllegalStateException("Organization with UUID [" + sourceProfile.getOrganizationUuid() + "] does not exist")); - QProfileDto to = prepareTarget(dbSession, organization, sourceProfile, toName); - File backupFile = temp.newFile(); - try { - backup(dbSession, sourceProfile, backupFile); - restore(dbSession, backupFile, to); - return to; - } finally { - org.sonar.core.util.FileUtils.deleteQuietly(backupFile); - } - } - - private QProfileDto prepareTarget(DbSession dbSession, OrganizationDto organization, QProfileDto sourceProfile, String toName) { - QProfileName toProfileName = new QProfileName(sourceProfile.getLanguage(), toName); - verify(sourceProfile, toProfileName); - QProfileDto toProfile = db.qualityProfileDao().selectByNameAndLanguage(dbSession, organization, toProfileName.getName(), toProfileName.getLanguage()); - if (toProfile == null) { - toProfile = factory.checkAndCreateCustom(dbSession, organization, toProfileName); - toProfile.setParentKee(sourceProfile.getParentKee()); - db.qualityProfileDao().update(dbSession, toProfile); - dbSession.commit(); - } - return toProfile; - } - - private void verify(QProfileDto fromProfile, QProfileName toProfileName) { - if (fromProfile.getName().equals(toProfileName.getName())) { - throw new IllegalArgumentException(String.format("Source and target profiles are equal: %s", - fromProfile.getName())); - } - } - - private void backup(DbSession dbSession, QProfileDto profile, File backupFile) { - try (Writer writer = new OutputStreamWriter(FileUtils.openOutputStream(backupFile), UTF_8)) { - backuper.backup(dbSession, profile, writer); - } catch (IOException e) { - throw new IllegalStateException("Fail to open temporary backup file: " + backupFile, e); - } - } - - private void restore(DbSession dbSession, File backupFile, QProfileDto profile) { - try (Reader reader = new InputStreamReader(FileUtils.openInputStream(backupFile), UTF_8)) { - backuper.restore(dbSession, reader, profile); - } catch (IOException e) { - throw new IllegalStateException("Fail to create temporary backup file: " + backupFile, e); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java deleted file mode 100644 index 43e795587ae..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Lists; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import javax.annotation.CheckForNull; -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.profiles.ProfileExporter; -import org.sonar.api.profiles.ProfileImporter; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.ActiveRuleParam; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; - -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -@ServerSide -public class QProfileExporters { - - private final DbClient dbClient; - private final RuleFinder ruleFinder; - private final QProfileRules qProfileRules; - private final ProfileExporter[] exporters; - private final ProfileImporter[] importers; - - public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules, ProfileExporter[] exporters, ProfileImporter[] importers) { - this.dbClient = dbClient; - this.ruleFinder = ruleFinder; - this.qProfileRules = qProfileRules; - this.exporters = exporters; - this.importers = importers; - } - - /** - * Used by Pico if no {@link ProfileImporter} is found - */ - public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules, ProfileExporter[] exporters) { - this(dbClient, ruleFinder, qProfileRules, exporters, new ProfileImporter[0]); - } - - /** - * Used by Pico if no {@link ProfileExporter} is found - */ - public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules, ProfileImporter[] importers) { - this(dbClient, ruleFinder, qProfileRules, new ProfileExporter[0], importers); - } - - /** - * Used by Pico if no {@link ProfileImporter} nor {@link ProfileExporter} is found - */ - public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules) { - this(dbClient, ruleFinder, qProfileRules, new ProfileExporter[0], new ProfileImporter[0]); - } - - public List<ProfileExporter> exportersForLanguage(String language) { - List<ProfileExporter> result = new ArrayList<>(); - for (ProfileExporter exporter : exporters) { - if (exporter.getSupportedLanguages() == null || exporter.getSupportedLanguages().length == 0 || ArrayUtils.contains(exporter.getSupportedLanguages(), language)) { - result.add(exporter); - } - } - return result; - } - - public String mimeType(String exporterKey) { - ProfileExporter exporter = findExporter(exporterKey); - return exporter.getMimeType(); - } - - public void export(DbSession dbSession, QProfileDto profile, String exporterKey, Writer writer) { - ProfileExporter exporter = findExporter(exporterKey); - exporter.exportProfile(wrap(dbSession, profile), writer); - } - - private RulesProfile wrap(DbSession dbSession, QProfileDto profile) { - RulesProfile target = new RulesProfile(profile.getName(), profile.getLanguage()); - List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByProfile(dbSession, profile); - List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, Lists.transform(activeRuleDtos, ActiveRuleDto::getId)); - ListMultimap<Integer, ActiveRuleParamDto> activeRuleParamsByActiveRuleId = FluentIterable.from(activeRuleParamDtos).index(ActiveRuleParamDto::getActiveRuleId); - - for (ActiveRuleDto activeRule : activeRuleDtos) { - // TODO all rules should be loaded by using one query with all active rule keys as parameter - Rule rule = ruleFinder.findByKey(activeRule.getRuleKey()); - org.sonar.api.rules.ActiveRule wrappedActiveRule = target.activateRule(rule, RulePriority.valueOf(activeRule.getSeverityString())); - List<ActiveRuleParamDto> paramDtos = activeRuleParamsByActiveRuleId.get(activeRule.getId()); - for (ActiveRuleParamDto activeRuleParamDto : paramDtos) { - wrappedActiveRule.setParameter(activeRuleParamDto.getKey(), activeRuleParamDto.getValue()); - } - } - return target; - } - - private ProfileExporter findExporter(String exporterKey) { - for (ProfileExporter e : exporters) { - if (exporterKey.equals(e.getKey())) { - return e; - } - } - throw new NotFoundException("Unknown quality profile exporter: " + exporterKey); - } - - public QProfileResult importXml(QProfileDto profile, String importerKey, InputStream xml, DbSession dbSession) { - return importXml(profile, importerKey, new InputStreamReader(xml, StandardCharsets.UTF_8), dbSession); - } - - private QProfileResult importXml(QProfileDto profile, String importerKey, Reader xml, DbSession dbSession) { - QProfileResult result = new QProfileResult(); - ValidationMessages messages = ValidationMessages.create(); - ProfileImporter importer = getProfileImporter(importerKey); - RulesProfile definition = importer.importProfile(xml, messages); - List<ActiveRuleChange> changes = importProfile(profile, definition, dbSession); - result.addChanges(changes); - processValidationMessages(messages, result); - return result; - } - - private List<ActiveRuleChange> importProfile(QProfileDto profile, RulesProfile definition, DbSession dbSession) { - Map<RuleKey, RuleDefinitionDto> rulesByRuleKey = dbClient.ruleDao().selectAllDefinitions(dbSession) - .stream() - .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey)); - List<ActiveRule> activeRules = definition.getActiveRules(); - List<RuleActivation> activations = activeRules.stream() - .map(activeRule -> toRuleActivation(activeRule, rulesByRuleKey)) - .filter(Objects::nonNull) - .collect(MoreCollectors.toArrayList(activeRules.size())); - return qProfileRules.activateAndCommit(dbSession, profile, activations); - } - - private ProfileImporter getProfileImporter(String importerKey) { - for (ProfileImporter importer : importers) { - if (StringUtils.equals(importerKey, importer.getKey())) { - return importer; - } - } - throw BadRequestException.create("No such importer : " + importerKey); - } - - private static void processValidationMessages(ValidationMessages messages, QProfileResult result) { - checkRequest(messages.getErrors().isEmpty(), messages.getErrors()); - result.addWarnings(messages.getWarnings()); - result.addInfos(messages.getInfos()); - } - - @CheckForNull - private static RuleActivation toRuleActivation(ActiveRule activeRule, Map<RuleKey, RuleDefinitionDto> rulesByRuleKey) { - RuleKey ruleKey = activeRule.getRule().ruleKey(); - RuleDefinitionDto ruleDefinition = rulesByRuleKey.get(ruleKey); - if (ruleDefinition == null) { - return null; - } - String severity = activeRule.getSeverity().name(); - Map<String, String> params = activeRule.getActiveRuleParams().stream() - .collect(MoreCollectors.uniqueIndex(ActiveRuleParam::getKey, ActiveRuleParam::getValue)); - return RuleActivation.create(ruleDefinition.getId(), severity, params); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java deleted file mode 100644 index cfecdfdfa28..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.Collection; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.server.exceptions.BadRequestException; - -/** - * Create, delete and set as default profile. - */ -public interface QProfileFactory { - - QProfileDto getOrCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name); - - /** - * Create the quality profile in DB with the specified name. - * - * @throws BadRequestException if a quality profile with the specified name already exists - */ - QProfileDto checkAndCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name); - - /** - * Deletes the specified profiles from database and Elasticsearch. - * All information related to custom profiles are deleted. Only association - * with built-in profiles are deleted. - * The profiles marked as "default" are deleted too. Deleting a parent profile - * does not delete descendants if the latter are not listed. - */ - void delete(DbSession dbSession, Collection<QProfileDto> profiles); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactoryImpl.java deleted file mode 100644 index 580f13aa45e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactoryImpl.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import javax.annotation.Nullable; -import org.apache.commons.lang.StringUtils; -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.organization.OrganizationDto; -import org.sonar.db.qualityprofile.DefaultQProfileDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public class QProfileFactoryImpl implements QProfileFactory { - - private final DbClient db; - private final UuidFactory uuidFactory; - private final System2 system2; - private final ActiveRuleIndexer activeRuleIndexer; - - public QProfileFactoryImpl(DbClient db, UuidFactory uuidFactory, System2 system2, ActiveRuleIndexer activeRuleIndexer) { - this.db = db; - this.uuidFactory = uuidFactory; - this.system2 = system2; - this.activeRuleIndexer = activeRuleIndexer; - } - - private static OrganizationDto requireNonNull(@Nullable OrganizationDto organization) { - Objects.requireNonNull(organization, "Organization is required, when creating a quality profile."); - return organization; - } - - @Override - public QProfileDto getOrCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name) { - requireNonNull(organization); - QProfileDto profile = db.qualityProfileDao().selectByNameAndLanguage(dbSession, organization, name.getName(), name.getLanguage()); - if (profile == null) { - profile = doCreate(dbSession, organization, name, false, false); - } else { - checkArgument(!profile.isBuiltIn(), "Operation forbidden for built-in Quality Profile '%s' with language '%s'", profile.getName(), profile.getLanguage()); - } - - return profile; - } - - @Override - public QProfileDto checkAndCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name) { - requireNonNull(organization); - QProfileDto dto = db.qualityProfileDao().selectByNameAndLanguage(dbSession, organization, name.getName(), name.getLanguage()); - checkRequest(dto == null, "Quality profile already exists: %s", name); - return doCreate(dbSession, organization, name, false, false); - } - - private QProfileDto doCreate(DbSession dbSession, OrganizationDto organization, QProfileName name, boolean isDefault, boolean isBuiltIn) { - if (StringUtils.isEmpty(name.getName())) { - throw BadRequestException.create("quality_profiles.profile_name_cant_be_blank"); - } - Date now = new Date(system2.now()); - QProfileDto dto = new QProfileDto() - .setKee(uuidFactory.create()) - .setRulesProfileUuid(uuidFactory.create()) - .setName(name.getName()) - .setOrganizationUuid(organization.getUuid()) - .setLanguage(name.getLanguage()) - .setIsBuiltIn(isBuiltIn) - .setRulesUpdatedAtAsDate(now); - db.qualityProfileDao().insert(dbSession, dto); - if (isDefault) { - db.defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from(dto)); - } - return dto; - } - - // ------------- DELETION - @Override - public void delete(DbSession dbSession, Collection<QProfileDto> profiles) { - if (profiles.isEmpty()) { - return; - } - - Set<String> uuids = new HashSet<>(); - List<QProfileDto> customProfiles = new ArrayList<>(); - Set<String> rulesProfileUuidsOfCustomProfiles = new HashSet<>(); - profiles.forEach(p -> { - uuids.add(p.getKee()); - if (!p.isBuiltIn()) { - customProfiles.add(p); - rulesProfileUuidsOfCustomProfiles.add(p.getRulesProfileUuid()); - } - }); - - // tables org_qprofiles, default_qprofiles and project_qprofiles - // are deleted whatever custom or built-in - db.qualityProfileDao().deleteProjectAssociationsByProfileUuids(dbSession, uuids); - db.defaultQProfileDao().deleteByQProfileUuids(dbSession, uuids); - db.qualityProfileDao().deleteOrgQProfilesByUuids(dbSession, uuids); - - // Permissions are only available on custom profiles - db.qProfileEditUsersDao().deleteByQProfiles(dbSession, customProfiles); - db.qProfileEditGroupsDao().deleteByQProfiles(dbSession, customProfiles); - - // tables related to rules_profiles and active_rules are deleted - // only for custom profiles. Built-in profiles are never - // deleted from table rules_profiles. - if (!rulesProfileUuidsOfCustomProfiles.isEmpty()) { - db.activeRuleDao().deleteParametersByRuleProfileUuids(dbSession, rulesProfileUuidsOfCustomProfiles); - db.activeRuleDao().deleteByRuleProfileUuids(dbSession, rulesProfileUuidsOfCustomProfiles); - db.qProfileChangeDao().deleteByRulesProfileUuids(dbSession, rulesProfileUuidsOfCustomProfiles); - db.qualityProfileDao().deleteRulesProfilesByUuids(dbSession, rulesProfileUuidsOfCustomProfiles); - activeRuleIndexer.commitDeletionOfProfiles(dbSession, customProfiles); - } else { - dbSession.commit(); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java deleted file mode 100644 index 8c514ef4f96..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.Collection; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.QProfileDto; - -public interface QProfileReset { - - /** - * Reset the rules of the specified profile. - */ - BulkChangeResult reset(DbSession dbSession, QProfileDto profile, Collection<RuleActivation> activations); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java deleted file mode 100644 index 79ec59531e8..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; - -@ServerSide -public class QProfileResetImpl implements QProfileReset { - - private final DbClient db; - private final RuleActivator activator; - private final ActiveRuleIndexer activeRuleIndexer; - - public QProfileResetImpl(DbClient db, RuleActivator activator, ActiveRuleIndexer activeRuleIndexer) { - this.db = db; - this.activator = activator; - this.activeRuleIndexer = activeRuleIndexer; - } - - @Override - public BulkChangeResult reset(DbSession dbSession, QProfileDto profile, Collection<RuleActivation> activations) { - requireNonNull(profile.getId(), "Quality profile must be persisted"); - checkArgument(!profile.isBuiltIn(), "Operation forbidden for built-in Quality Profile '%s'", profile.getKee()); - - BulkChangeResult result = new BulkChangeResult(); - Set<Integer> rulesToBeDeactivated = new HashSet<>(); - // Keep reference to all the activated rules before backup restore - for (ActiveRuleDto activeRuleDto : db.activeRuleDao().selectByProfile(dbSession, profile)) { - if (activeRuleDto.getInheritance() == null) { - // inherited rules can't be deactivated - rulesToBeDeactivated.add(activeRuleDto.getRuleId()); - } - } - Set<Integer> ruleIds = new HashSet<>(rulesToBeDeactivated.size() + activations.size()); - ruleIds.addAll(rulesToBeDeactivated); - activations.forEach(a -> ruleIds.add(a.getRuleId())); - RuleActivationContext context = activator.createContextForUserProfile(dbSession, profile, ruleIds); - - for (RuleActivation activation : activations) { - try { - List<ActiveRuleChange> changes = activator.activate(dbSession, activation, context); - rulesToBeDeactivated.remove(activation.getRuleId()); - result.incrementSucceeded(); - result.addChanges(changes); - } catch (BadRequestException e) { - result.incrementFailed(); - result.getErrors().addAll(e.errors()); - } - } - - List<ActiveRuleChange> changes = new ArrayList<>(result.getChanges()); - for (Integer ruleId : rulesToBeDeactivated) { - try { - changes.addAll(activator.deactivate(dbSession, context, ruleId, false)); - } catch (BadRequestException e) { - // ignore, probably a rule inherited from parent that can't be deactivated - } - } - activeRuleIndexer.commitAndIndex(dbSession, changes); - return result; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRestoreSummary.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRestoreSummary.java deleted file mode 100644 index cccdd92bbfc..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRestoreSummary.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import org.sonar.db.qualityprofile.QProfileDto; - -import static java.util.Objects.requireNonNull; - -public final class QProfileRestoreSummary { - private final QProfileDto profile; - private final BulkChangeResult ruleChanges; - - public QProfileRestoreSummary(QProfileDto profile, BulkChangeResult ruleChanges) { - this.profile = requireNonNull(profile); - this.ruleChanges = requireNonNull(ruleChanges); - } - - public QProfileDto getProfile() { - return profile; - } - - public BulkChangeResult getRuleChanges() { - return ruleChanges; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java deleted file mode 100644 index f36232b966b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.List; -import org.sonar.db.qualityprofile.QProfileDto; - -public class QProfileResult { - - private List<String> warnings; - private List<String> infos; - - private QProfileDto profile; - - private List<ActiveRuleChange> changes; - - public QProfileResult() { - warnings = new ArrayList<>(); - infos = new ArrayList<>(); - changes = new ArrayList<>(); - } - - public List<String> warnings() { - return warnings; - } - - public QProfileResult addWarnings(List<String> warnings) { - this.warnings.addAll(warnings); - return this; - } - - public List<String> infos() { - return infos; - } - - public QProfileResult addInfos(List<String> infos) { - this.infos.addAll(infos); - return this; - } - - public QProfileDto profile() { - return profile; - } - - public QProfileResult setProfile(QProfileDto profile) { - this.profile = profile; - return this; - } - - public List<ActiveRuleChange> getChanges() { - return changes; - } - - public QProfileResult addChanges(List<ActiveRuleChange> changes) { - this.changes.addAll(changes); - return this; - } - - public QProfileResult add(QProfileResult result) { - warnings.addAll(result.warnings()); - infos.addAll(result.infos()); - changes.addAll(result.getChanges()); - return this; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRules.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRules.java deleted file mode 100644 index b0f028ea31b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRules.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.Collection; -import java.util.List; -import javax.annotation.Nullable; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.rule.index.RuleQuery; - -/** - * Operations related to activation and deactivation of rules on user profiles. - * Use {@link BuiltInQProfileUpdate} for built-in profiles. - */ -@ServerSide -public interface QProfileRules { - - /** - * Activate multiple rules at once on a Quality profile. - * Db session is committed and Elasticsearch indices are updated. - * If an activation fails to be executed, then all others are - * canceled, db session is not committed and an exception is - * thrown. - */ - List<ActiveRuleChange> activateAndCommit(DbSession dbSession, QProfileDto profile, Collection<RuleActivation> activations); - - /** - * Same as {@link #activateAndCommit(DbSession, QProfileDto, Collection)} except - * that: - * - rules are loaded from search engine - * - rules are activated with default parameters - * - an activation failure does not break others. No exception is thrown. - */ - BulkChangeResult bulkActivateAndCommit(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery, @Nullable String severity); - - List<ActiveRuleChange> deactivateAndCommit(DbSession dbSession, QProfileDto profile, Collection<Integer> ruleIds); - - BulkChangeResult bulkDeactivateAndCommit(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery); - - /** - * Delete a rule from all Quality profiles. Db session is not committed. As a - * consequence Elasticsearch indices are NOT updated. - */ - List<ActiveRuleChange> deleteRule(DbSession dbSession, RuleDefinitionDto rule); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRulesImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRulesImpl.java deleted file mode 100644 index 2f6affebcfa..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRulesImpl.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.function.BiFunction; -import javax.annotation.Nullable; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleQuery; - -import static com.google.common.base.Preconditions.checkArgument; - -public class QProfileRulesImpl implements QProfileRules { - - private final DbClient db; - private final RuleActivator ruleActivator; - private final RuleIndex ruleIndex; - private final ActiveRuleIndexer activeRuleIndexer; - - public QProfileRulesImpl(DbClient db, RuleActivator ruleActivator, RuleIndex ruleIndex, ActiveRuleIndexer activeRuleIndexer) { - this.db = db; - this.ruleActivator = ruleActivator; - this.ruleIndex = ruleIndex; - this.activeRuleIndexer = activeRuleIndexer; - } - - @Override - public List<ActiveRuleChange> activateAndCommit(DbSession dbSession, QProfileDto profile, Collection<RuleActivation> activations) { - verifyNotBuiltIn(profile); - - Set<Integer> ruleIds = activations.stream().map(RuleActivation::getRuleId).collect(MoreCollectors.toHashSet(activations.size())); - RuleActivationContext context = ruleActivator.createContextForUserProfile(dbSession, profile, ruleIds); - - List<ActiveRuleChange> changes = new ArrayList<>(); - for (RuleActivation activation : activations) { - changes.addAll(ruleActivator.activate(dbSession, activation, context)); - } - activeRuleIndexer.commitAndIndex(dbSession, changes); - return changes; - } - - @Override - public BulkChangeResult bulkActivateAndCommit(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery, @Nullable String severity) { - verifyNotBuiltIn(profile); - return doBulk(dbSession, profile, ruleQuery, (context, ruleDefinition) -> { - RuleActivation activation = RuleActivation.create(ruleDefinition.getId(), severity, null); - return ruleActivator.activate(dbSession, activation, context); - }); - } - - @Override - public List<ActiveRuleChange> deactivateAndCommit(DbSession dbSession, QProfileDto profile, Collection<Integer> ruleIds) { - verifyNotBuiltIn(profile); - RuleActivationContext context = ruleActivator.createContextForUserProfile(dbSession, profile, ruleIds); - - List<ActiveRuleChange> changes = new ArrayList<>(); - for (Integer ruleId : ruleIds) { - changes.addAll(ruleActivator.deactivate(dbSession, context, ruleId, false)); - } - activeRuleIndexer.commitAndIndex(dbSession, changes); - return changes; - } - - @Override - public BulkChangeResult bulkDeactivateAndCommit(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery) { - verifyNotBuiltIn(profile); - return doBulk(dbSession, profile, ruleQuery, (context, ruleDefinition) -> ruleActivator.deactivate(dbSession, context, ruleDefinition.getId(), false)); - } - - @Override - public List<ActiveRuleChange> deleteRule(DbSession dbSession, RuleDefinitionDto rule) { - List<ActiveRuleChange> changes = new ArrayList<>(); - List<Integer> activeRuleIds = new ArrayList<>(); - db.activeRuleDao().selectByRuleIdOfAllOrganizations(dbSession, rule.getId()).forEach(ar -> { - activeRuleIds.add(ar.getId()); - changes.add(new ActiveRuleChange(ActiveRuleChange.Type.DEACTIVATED, ar, rule)); - }); - - db.activeRuleDao().deleteByIds(dbSession, activeRuleIds); - db.activeRuleDao().deleteParamsByActiveRuleIds(dbSession, activeRuleIds); - - return changes; - } - - private static void verifyNotBuiltIn(QProfileDto profile) { - checkArgument(!profile.isBuiltIn(), "The built-in profile %s is read-only and can't be updated", profile.getName()); - } - - private BulkChangeResult doBulk(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery, BiFunction<RuleActivationContext, RuleDefinitionDto, List<ActiveRuleChange>> fn) { - BulkChangeResult result = new BulkChangeResult(); - Collection<Integer> ruleIds = Sets.newHashSet(ruleIndex.searchAll(ruleQuery)); - RuleActivationContext context = ruleActivator.createContextForUserProfile(dbSession, profile, ruleIds); - - for (Integer ruleId : ruleIds) { - try { - context.reset(ruleId); - RuleDefinitionDto ruleDefinition = context.getRule().get(); - List<ActiveRuleChange> changes = fn.apply(context, ruleDefinition); - result.addChanges(changes); - if (!changes.isEmpty()) { - result.incrementSucceeded(); - } - } catch (BadRequestException e) { - // other exceptions stop the bulk activation - result.incrementFailed(); - result.getErrors().addAll(e.errors()); - } - } - activeRuleIndexer.commitAndIndex(dbSession, result.getChanges()); - return result; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileTree.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileTree.java deleted file mode 100644 index b8c6b148374..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileTree.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.List; -import org.sonar.api.server.ServerSide; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.QProfileDto; - -/** - * Operations related to hierarchy of profiles - */ -@ServerSide -public interface QProfileTree { - - List<ActiveRuleChange> removeParentAndCommit(DbSession dbSession, QProfileDto profile); - - List<ActiveRuleChange> setParentAndCommit(DbSession dbSession, QProfileDto profile, QProfileDto parentProfile); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileTreeImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileTreeImpl.java deleted file mode 100644 index af5f778d0ed..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileTreeImpl.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import javax.annotation.Nullable; -import org.sonar.api.utils.System2; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; - -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -public class QProfileTreeImpl implements QProfileTree { - - private final DbClient db; - private final RuleActivator ruleActivator; - private final System2 system2; - private final ActiveRuleIndexer activeRuleIndexer; - - public QProfileTreeImpl(DbClient db, RuleActivator ruleActivator, System2 system2, ActiveRuleIndexer activeRuleIndexer) { - this.db = db; - this.ruleActivator = ruleActivator; - this.system2 = system2; - this.activeRuleIndexer = activeRuleIndexer; - } - - @Override - public List<ActiveRuleChange> removeParentAndCommit(DbSession dbSession, QProfileDto profile) { - List<ActiveRuleChange> changes = removeParent(dbSession, profile); - activeRuleIndexer.commitAndIndex(dbSession, changes); - return changes; - } - - @Override - public List<ActiveRuleChange> setParentAndCommit(DbSession dbSession, QProfileDto profile, QProfileDto parentProfile) { - List<ActiveRuleChange> changes = setParent(dbSession, profile, parentProfile); - activeRuleIndexer.commitAndIndex(dbSession, changes); - return changes; - } - - private List<ActiveRuleChange> setParent(DbSession dbSession, QProfileDto profile, QProfileDto parent) { - checkRequest(parent.getLanguage().equals(profile.getLanguage()), "Cannot set the profile '%s' as the parent of profile '%s' since their languages differ ('%s' != '%s')", - parent.getKee(), profile.getKee(), parent.getLanguage(), profile.getLanguage()); - - List<ActiveRuleChange> changes = new ArrayList<>(); - if (parent.getKee().equals(profile.getParentKee())) { - return changes; - } - - checkRequest(!isDescendant(dbSession, profile, parent), "Descendant profile '%s' can not be selected as parent of '%s'", parent.getKee(), profile.getKee()); - changes.addAll(removeParent(dbSession, profile)); - - // set new parent - profile.setParentKee(parent.getKee()); - db.qualityProfileDao().update(dbSession, profile); - - List<OrgActiveRuleDto> parentActiveRules = db.activeRuleDao().selectByProfile(dbSession, parent); - Collection<Integer> ruleIds = parentActiveRules.stream().map(ActiveRuleDto::getRuleId).collect(MoreCollectors.toArrayList()); - RuleActivationContext context = ruleActivator.createContextForUserProfile(dbSession, profile, ruleIds); - - for (ActiveRuleDto parentActiveRule : parentActiveRules) { - try { - RuleActivation activation = RuleActivation.create(parentActiveRule.getRuleId(), null, null); - changes.addAll(ruleActivator.activate(dbSession, activation, context)); - } catch (BadRequestException e) { - // for example because rule status is REMOVED - // TODO return errors - } - } - return changes; - } - - private List<ActiveRuleChange> removeParent(DbSession dbSession, QProfileDto profile) { - List<ActiveRuleChange> changes = new ArrayList<>(); - if (profile.getParentKee() == null) { - return changes; - } - - profile.setParentKee(null); - db.qualityProfileDao().update(dbSession, profile); - - List<OrgActiveRuleDto> activeRules = db.activeRuleDao().selectByProfile(dbSession, profile); - Collection<Integer> ruleIds = activeRules.stream().map(ActiveRuleDto::getRuleId).collect(MoreCollectors.toArrayList()); - RuleActivationContext context = ruleActivator.createContextForUserProfile(dbSession, profile, ruleIds); - - for (OrgActiveRuleDto activeRule : activeRules) { - if (ActiveRuleDto.INHERITED.equals(activeRule.getInheritance())) { - changes.addAll(ruleActivator.deactivate(dbSession, context, activeRule.getRuleId(), true)); - - } else if (ActiveRuleDto.OVERRIDES.equals(activeRule.getInheritance())) { - context.reset(activeRule.getRuleId()); - activeRule.setInheritance(null); - activeRule.setUpdatedAt(system2.now()); - db.activeRuleDao().update(dbSession, activeRule); - changes.add(new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRule, context.getRule().get()).setInheritance(null)); - } - } - return changes; - } - - private boolean isDescendant(DbSession dbSession, QProfileDto childProfile, @Nullable QProfileDto parentProfile) { - QProfileDto currentParent = parentProfile; - while (currentParent != null) { - if (childProfile.getName().equals(currentParent.getName())) { - return true; - } - String parentKey = currentParent.getParentKee(); - if (parentKey != null) { - currentParent = db.qualityProfileDao().selectByUuid(dbSession, parentKey); - } else { - currentParent = null; - } - } - return false; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java deleted file mode 100644 index 4b9df426660..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import org.picocontainer.Startable; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.DefaultQProfileDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.RulesProfileDto; - -import static java.lang.String.format; -import static java.util.stream.Collectors.toMap; -import static org.sonar.server.qualityprofile.ActiveRuleInheritance.NONE; - -/** - * Synchronize Quality profiles during server startup - */ -@ServerSide -public class RegisterQualityProfiles implements Startable { - - private static final Logger LOGGER = Loggers.get(RegisterQualityProfiles.class); - - private final BuiltInQProfileRepository builtInQProfileRepository; - private final DbClient dbClient; - private final BuiltInQProfileInsert builtInQProfileInsert; - private final BuiltInQProfileUpdate builtInQProfileUpdate; - private final BuiltInQualityProfilesUpdateListener builtInQualityProfilesNotification; - private final System2 system2; - - public RegisterQualityProfiles(BuiltInQProfileRepository builtInQProfileRepository, - DbClient dbClient, BuiltInQProfileInsert builtInQProfileInsert, BuiltInQProfileUpdate builtInQProfileUpdate, - BuiltInQualityProfilesUpdateListener builtInQualityProfilesNotification, System2 system2) { - this.builtInQProfileRepository = builtInQProfileRepository; - this.dbClient = dbClient; - this.builtInQProfileInsert = builtInQProfileInsert; - this.builtInQProfileUpdate = builtInQProfileUpdate; - this.builtInQualityProfilesNotification = builtInQualityProfilesNotification; - this.system2 = system2; - } - - @Override - public void start() { - List<BuiltInQProfile> builtInQProfiles = builtInQProfileRepository.get(); - if (builtInQProfiles.isEmpty()) { - return; - } - - Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Register quality profiles"); - try (DbSession dbSession = dbClient.openSession(false); - DbSession batchDbSession = dbClient.openSession(true)) { - long startDate = system2.now(); - - Map<QProfileName, RulesProfileDto> persistedRuleProfiles = loadPersistedProfiles(dbSession); - - Multimap<QProfileName, ActiveRuleChange> changedProfiles = ArrayListMultimap.create(); - builtInQProfiles.forEach(builtIn -> { - RulesProfileDto ruleProfile = persistedRuleProfiles.get(builtIn.getQProfileName()); - if (ruleProfile == null) { - create(dbSession, batchDbSession, builtIn); - } else { - List<ActiveRuleChange> changes = update(dbSession, builtIn, ruleProfile); - changedProfiles.putAll(builtIn.getQProfileName(), changes.stream() - .filter(change -> { - String inheritance = change.getActiveRule().getInheritance(); - return inheritance == null || NONE.name().equals(inheritance); - }) - .collect(MoreCollectors.toList())); - } - }); - if (!changedProfiles.isEmpty()) { - long endDate = system2.now(); - builtInQualityProfilesNotification.onChange(changedProfiles, startDate, endDate); - } - ensureBuiltInDefaultQPContainsRules(dbSession); - } - profiler.stopDebug(); - } - - @Override - public void stop() { - // nothing to do - } - - private Map<QProfileName, RulesProfileDto> loadPersistedProfiles(DbSession dbSession) { - return dbClient.qualityProfileDao().selectBuiltInRuleProfiles(dbSession).stream() - .collect(MoreCollectors.uniqueIndex(rp -> new QProfileName(rp.getLanguage(), rp.getName()))); - } - - private void create(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtIn) { - LOGGER.info("Register profile {}", builtIn.getQProfileName()); - - renameOutdatedProfiles(dbSession, builtIn); - - builtInQProfileInsert.create(dbSession, batchDbSession, builtIn); - } - - private List<ActiveRuleChange> update(DbSession dbSession, BuiltInQProfile definition, RulesProfileDto dbProfile) { - LOGGER.info("Update profile {}", definition.getQProfileName()); - - return builtInQProfileUpdate.update(dbSession, definition, dbProfile); - } - - /** - * The Quality profiles created by users should be renamed when they have the same name - * as the built-in profile to be persisted. - * <p> - * When upgrading from < 6.5 , all existing profiles are considered as "custom" (created - * by users) because the concept of built-in profile is not persisted. The "Sonar way" profiles - * are renamed to "Sonar way (outdated copy) in order to avoid conflicts with the new - * built-in profile "Sonar way", which has probably different configuration. - */ - private void renameOutdatedProfiles(DbSession dbSession, BuiltInQProfile profile) { - Collection<String> uuids = dbClient.qualityProfileDao().selectUuidsOfCustomRulesProfiles(dbSession, profile.getLanguage(), profile.getName()); - if (uuids.isEmpty()) { - return; - } - Profiler profiler = Profiler.createIfDebug(Loggers.get(getClass())).start(); - String newName = profile.getName() + " (outdated copy)"; - LOGGER.info("Rename Quality profiles [{}/{}] to [{}] in {}Â organizations", profile.getLanguage(), profile.getName(), newName, uuids.size()); - dbClient.qualityProfileDao().renameRulesProfilesAndCommit(dbSession, uuids, newName); - profiler.stopDebug(format("%d Quality profiles renamed to [%s]", uuids.size(), newName)); - } - - /** - * This method ensure that if a default built-in quality profile does not have any active rules but another built-in one for the same language - * does have active rules, the last one will be the default one. - * - * @see <a href="https://jira.sonarsource.com/browse/SONAR-10363">SONAR-10363</a> - */ - private void ensureBuiltInDefaultQPContainsRules(DbSession dbSession) { - Map<String, RulesProfileDto> rulesProfilesByLanguage = dbClient.qualityProfileDao().selectBuiltInRuleProfilesWithActiveRules(dbSession).stream() - .collect(toMap(RulesProfileDto::getLanguage, Function.identity(), (oldValue, newValue) -> oldValue)); - - dbClient.qualityProfileDao().selectDefaultBuiltInProfilesWithoutActiveRules(dbSession, rulesProfilesByLanguage.keySet()) - .forEach(qp -> { - RulesProfileDto rulesProfile = rulesProfilesByLanguage.get(qp.getLanguage()); - if (rulesProfile == null) { - return; - } - - QProfileDto qualityProfile = dbClient.qualityProfileDao().selectByRuleProfileUuid(dbSession, qp.getOrganizationUuid(), rulesProfile.getKee()); - if (qualityProfile == null) { - return; - } - - Set<String> uuids = dbClient.defaultQProfileDao().selectExistingQProfileUuids(dbSession, qp.getOrganizationUuid(), Collections.singleton(qp.getKee())); - dbClient.defaultQProfileDao().deleteByQProfileUuids(dbSession, uuids); - dbClient.defaultQProfileDao().insertOrUpdate(dbSession, new DefaultQProfileDto() - .setQProfileUuid(qualityProfile.getKee()) - .setLanguage(qp.getLanguage()) - .setOrganizationUuid(qp.getOrganizationUuid()) - ); - - LOGGER.info("Default built-in quality profile for language [{}] has been updated from [{}] to [{}] since previous default does not have active rules.", - qp.getLanguage(), - qp.getName(), - rulesProfile.getName()); - }); - - dbSession.commit(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/package-info.java deleted file mode 100644 index 5a3c798af36..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/NewCustomRule.java b/server/sonar-server/src/main/java/org/sonar/server/rule/NewCustomRule.java deleted file mode 100644 index e64880ceb07..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/NewCustomRule.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.Maps; -import java.util.Map; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rules.RuleType; - -public class NewCustomRule { - - private String ruleKey; - private RuleKey templateKey; - private String name; - private String htmlDescription; - private String markdownDescription; - private String severity; - private RuleStatus status; - private RuleType type; - private final Map<String, String> parameters = Maps.newHashMap(); - - private boolean preventReactivation = false; - - private NewCustomRule() { - // No direct call to constructor - } - - public String ruleKey() { - return ruleKey; - } - - @CheckForNull - public RuleKey templateKey() { - return templateKey; - } - - @CheckForNull - public String name() { - return name; - } - - public NewCustomRule setName(@Nullable String name) { - this.name = name; - return this; - } - - @CheckForNull - public String htmlDescription() { - return htmlDescription; - } - - public NewCustomRule setHtmlDescription(@Nullable String htmlDescription) { - this.htmlDescription = htmlDescription; - return this; - } - - @CheckForNull - public String markdownDescription() { - return markdownDescription; - } - - public NewCustomRule setMarkdownDescription(@Nullable String markdownDescription) { - this.markdownDescription = markdownDescription; - return this; - } - - @CheckForNull - public String severity() { - return severity; - } - - public NewCustomRule setSeverity(@Nullable String severity) { - this.severity = severity; - return this; - } - - @CheckForNull - public RuleStatus status() { - return status; - } - - public NewCustomRule setStatus(@Nullable RuleStatus status) { - this.status = status; - return this; - } - - @CheckForNull - public RuleType type() { - return type; - } - - public NewCustomRule setType(@Nullable RuleType type) { - this.type = type; - return this; - } - - @CheckForNull - public String parameter(final String paramKey) { - return parameters.get(paramKey); - } - - public NewCustomRule setParameters(Map<String, String> params) { - this.parameters.clear(); - this.parameters.putAll(params); - return this; - } - - public boolean isPreventReactivation() { - return preventReactivation; - } - - /** - * When true, if the rule already exists in status REMOVED, an {@link ReactivationException} will be thrown - */ - public NewCustomRule setPreventReactivation(boolean preventReactivation) { - this.preventReactivation = preventReactivation; - return this; - } - - public static NewCustomRule createForCustomRule(String customKey, RuleKey templateKey) { - Preconditions.checkArgument(!Strings.isNullOrEmpty(customKey), "Custom key should be set"); - Preconditions.checkArgument(templateKey != null, "Template key should be set"); - NewCustomRule newRule = new NewCustomRule(); - newRule.ruleKey = customKey; - newRule.templateKey = templateKey; - return newRule; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ReactivationException.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ReactivationException.java deleted file mode 100644 index fcd5db096f2..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ReactivationException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import org.sonar.api.rule.RuleKey; - -public class ReactivationException extends RuntimeException { - - private RuleKey ruleKey; - - public ReactivationException(String s, RuleKey ruleKey) { - super(s); - this.ruleKey = ruleKey; - } - - public RuleKey ruleKey() { - return ruleKey; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java deleted file mode 100644 index 1b99932ed9b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java +++ /dev/null @@ -1,855 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang.StringUtils; -import org.picocontainer.Startable; -import org.sonar.api.resources.Languages; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleScope; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rules.RuleType; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; -import org.sonar.core.util.UuidFactory; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.rule.DeprecatedRuleKeyDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto.Format; -import org.sonar.db.rule.RuleDto.Scope; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.db.rule.RuleRepositoryDto; -import org.sonar.server.organization.OrganizationFlags; -import org.sonar.server.qualityprofile.ActiveRuleChange; -import org.sonar.server.qualityprofile.QProfileRules; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndexer; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Sets.difference; -import static com.google.common.collect.Sets.intersection; -import static java.lang.String.format; -import static java.util.Collections.emptySet; -import static org.sonar.core.util.stream.MoreCollectors.toList; -import static org.sonar.core.util.stream.MoreCollectors.toSet; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; - -/** - * Register rules at server startup - */ -public class RegisterRules implements Startable { - - private static final Logger LOG = Loggers.get(RegisterRules.class); - - private final RuleDefinitionsLoader defLoader; - private final QProfileRules qProfileRules; - private final DbClient dbClient; - private final RuleIndexer ruleIndexer; - private final ActiveRuleIndexer activeRuleIndexer; - private final Languages languages; - private final System2 system2; - private final OrganizationFlags organizationFlags; - private final WebServerRuleFinder webServerRuleFinder; - private final UuidFactory uuidFactory; - - public RegisterRules(RuleDefinitionsLoader defLoader, QProfileRules qProfileRules, DbClient dbClient, RuleIndexer ruleIndexer, - ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2, OrganizationFlags organizationFlags, - WebServerRuleFinder webServerRuleFinder, UuidFactory uuidFactory) { - this.defLoader = defLoader; - this.qProfileRules = qProfileRules; - this.dbClient = dbClient; - this.ruleIndexer = ruleIndexer; - this.activeRuleIndexer = activeRuleIndexer; - this.languages = languages; - this.system2 = system2; - this.organizationFlags = organizationFlags; - this.webServerRuleFinder = webServerRuleFinder; - this.uuidFactory = uuidFactory; - } - - @Override - public void start() { - Profiler profiler = Profiler.create(LOG).startInfo("Register rules"); - try (DbSession dbSession = dbClient.openSession(false)) { - RulesDefinition.Context ruleDefinitionContext = defLoader.load(); - List<RulesDefinition.ExtendedRepository> repositories = getRepositories(ruleDefinitionContext); - RegisterRulesContext registerRulesContext = createRegisterRulesContext(dbSession); - - verifyRuleKeyConsistency(repositories, registerRulesContext); - - boolean orgsEnabled = organizationFlags.isEnabled(dbSession); - for (RulesDefinition.ExtendedRepository repoDef : repositories) { - if (languages.get(repoDef.language()) != null) { - for (RulesDefinition.Rule ruleDef : repoDef.rules()) { - if (noTemplateRuleWithOrganizationsEnabled(registerRulesContext, orgsEnabled, ruleDef)) { - continue; - } - registerRule(registerRulesContext, ruleDef, dbSession); - } - dbSession.commit(); - } - } - processRemainingDbRules(registerRulesContext, dbSession); - List<ActiveRuleChange> changes = removeActiveRulesOnStillExistingRepositories(dbSession, registerRulesContext, repositories); - dbSession.commit(); - - persistRepositories(dbSession, ruleDefinitionContext.repositories()); - // FIXME lack of resiliency, active rules index is corrupted if rule index fails - // to be updated. Only a single DB commit should be executed. - ruleIndexer.commitAndIndex(dbSession, registerRulesContext.getAllModified().map(RuleDefinitionDto::getId).collect(toSet())); - activeRuleIndexer.commitAndIndex(dbSession, changes); - registerRulesContext.getRenamed().forEach(e -> LOG.info("Rule {} re-keyed to {}", e.getValue(), e.getKey().getKey())); - profiler.stopDebug(); - - webServerRuleFinder.startCaching(); - } - } - - private static List<RulesDefinition.ExtendedRepository> getRepositories(RulesDefinition.Context context) { - List<RulesDefinition.ExtendedRepository> repositories = new ArrayList<>(context.repositories()); - for (RulesDefinition.ExtendedRepository extendedRepoDef : context.extendedRepositories()) { - if (context.repository(extendedRepoDef.key()) == null) { - LOG.warn(format("Extension is ignored, repository %s does not exist", extendedRepoDef.key())); - } else { - repositories.add(extendedRepoDef); - } - } - return repositories; - } - - private RegisterRulesContext createRegisterRulesContext(DbSession dbSession) { - Map<RuleKey, RuleDefinitionDto> allRules = dbClient.ruleDao().selectAllDefinitions(dbSession) - .stream() - .collect(uniqueIndex(RuleDefinitionDto::getKey)); - Map<Integer, Set<SingleDeprecatedRuleKey>> existingDeprecatedKeysById = loadDeprecatedRuleKeys(dbSession); - return new RegisterRulesContext(allRules, existingDeprecatedKeysById); - } - - private Map<Integer, Set<SingleDeprecatedRuleKey>> loadDeprecatedRuleKeys(DbSession dbSession) { - return dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession) - .stream() - .map(SingleDeprecatedRuleKey::from) - .collect(Collectors.groupingBy(SingleDeprecatedRuleKey::getRuleId, Collectors.toSet())); - } - - private static boolean noTemplateRuleWithOrganizationsEnabled(RegisterRulesContext registerRulesContext, boolean orgsEnabled, RulesDefinition.Rule ruleDef) { - if (!ruleDef.template() || !orgsEnabled) { - return false; - } - - Optional<RuleDefinitionDto> dbRule = registerRulesContext.getDbRuleFor(ruleDef); - if (dbRule.isPresent() && dbRule.get().getStatus() == RuleStatus.REMOVED) { - RuleDefinitionDto dto = dbRule.get(); - LOG.debug("Template rule {} kept removed, because organizations are enabled.", dto.getKey()); - registerRulesContext.removed(dto); - } else { - LOG.info("Template rule {} will not be imported, because organizations are enabled.", RuleKey.of(ruleDef.repository().key(), ruleDef.key())); - } - return true; - } - - private static class RegisterRulesContext { - // initial immutable data - private final Map<RuleKey, RuleDefinitionDto> dbRules; - private final Set<RuleDefinitionDto> known; - private final Map<Integer, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysById; - private final Map<RuleKey, RuleDefinitionDto> dbRulesByDbDeprecatedKey; - // mutable data - private final Set<RuleDefinitionDto> created = new HashSet<>(); - private final Map<RuleDefinitionDto, RuleKey> renamed = new HashMap<>(); - private final Set<RuleDefinitionDto> updated = new HashSet<>(); - private final Set<RuleDefinitionDto> unchanged = new HashSet<>(); - private final Set<RuleDefinitionDto> removed = new HashSet<>(); - - private RegisterRulesContext(Map<RuleKey, RuleDefinitionDto> dbRules, Map<Integer, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysById) { - this.dbRules = ImmutableMap.copyOf(dbRules); - this.known = ImmutableSet.copyOf(dbRules.values()); - this.dbDeprecatedKeysById = dbDeprecatedKeysById; - this.dbRulesByDbDeprecatedKey = buildDbRulesByDbDeprecatedKey(dbDeprecatedKeysById, dbRules); - } - - private static Map<RuleKey, RuleDefinitionDto> buildDbRulesByDbDeprecatedKey(Map<Integer, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysById, - Map<RuleKey, RuleDefinitionDto> dbRules) { - Map<Integer, RuleDefinitionDto> dbRulesByRuleId = dbRules.values().stream() - .collect(uniqueIndex(RuleDefinitionDto::getId)); - - ImmutableMap.Builder<RuleKey, RuleDefinitionDto> builder = ImmutableMap.builder(); - for (Map.Entry<Integer, Set<SingleDeprecatedRuleKey>> entry : dbDeprecatedKeysById.entrySet()) { - Integer ruleId = entry.getKey(); - RuleDefinitionDto rule = dbRulesByRuleId.get(ruleId); - if (rule == null) { - LOG.warn("Could not retrieve rule with id %s referenced by a deprecated rule key. " + - "The following deprecated rule keys seem to be referencing a non-existing rule", - ruleId, entry.getValue()); - } else { - entry.getValue().forEach(d -> builder.put(d.getOldRuleKeyAsRuleKey(), rule)); - } - } - return builder.build(); - } - - private Optional<RuleDefinitionDto> getDbRuleFor(RulesDefinition.Rule ruleDef) { - RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key()); - Optional<RuleDefinitionDto> res = Stream.concat(Stream.of(ruleKey), ruleDef.deprecatedRuleKeys().stream()) - .map(dbRules::get) - .filter(Objects::nonNull) - .findFirst(); - // may occur in case of plugin downgrade - if (!res.isPresent()) { - return Optional.ofNullable(dbRulesByDbDeprecatedKey.get(ruleKey)); - } - return res; - } - - private ImmutableMap<RuleKey, SingleDeprecatedRuleKey> getDbDeprecatedKeysByOldRuleKey() { - return dbDeprecatedKeysById.values().stream() - .flatMap(Collection::stream) - .collect(uniqueIndex(SingleDeprecatedRuleKey::getOldRuleKeyAsRuleKey)); - } - - private Set<SingleDeprecatedRuleKey> getDBDeprecatedKeysFor(RuleDefinitionDto rule) { - return dbDeprecatedKeysById.getOrDefault(rule.getId(), emptySet()); - } - - private Stream<RuleDefinitionDto> getRemaining() { - Set<RuleDefinitionDto> res = new HashSet<>(dbRules.values()); - res.removeAll(unchanged); - res.removeAll(renamed.keySet()); - res.removeAll(updated); - res.removeAll(removed); - return res.stream(); - } - - private Stream<RuleDefinitionDto> getRemoved() { - return removed.stream(); - } - - public Stream<Map.Entry<RuleDefinitionDto, RuleKey>> getRenamed() { - return renamed.entrySet().stream(); - } - - private Stream<RuleDefinitionDto> getAllModified() { - return Stream.of( - created.stream(), - updated.stream(), - removed.stream(), - renamed.keySet().stream()) - .flatMap(s -> s); - } - - private boolean isCreated(RuleDefinitionDto ruleDefinition) { - return created.contains(ruleDefinition); - } - - private boolean isRenamed(RuleDefinitionDto ruleDefinition) { - return renamed.containsKey(ruleDefinition); - } - - private boolean isUpdated(RuleDefinitionDto ruleDefinition) { - return updated.contains(ruleDefinition); - } - - private void created(RuleDefinitionDto ruleDefinition) { - checkState(!known.contains(ruleDefinition), "known RuleDefinitionDto can't be created"); - created.add(ruleDefinition); - } - - private void renamed(RuleDefinitionDto ruleDefinition) { - ensureKnown(ruleDefinition); - renamed.put(ruleDefinition, ruleDefinition.getKey()); - } - - private void updated(RuleDefinitionDto ruleDefinition) { - ensureKnown(ruleDefinition); - updated.add(ruleDefinition); - } - - private void removed(RuleDefinitionDto ruleDefinition) { - ensureKnown(ruleDefinition); - removed.add(ruleDefinition); - } - - private void unchanged(RuleDefinitionDto ruleDefinition) { - ensureKnown(ruleDefinition); - unchanged.add(ruleDefinition); - } - - private void ensureKnown(RuleDefinitionDto ruleDefinition) { - checkState(known.contains(ruleDefinition), "unknown RuleDefinitionDto"); - } - } - - private void persistRepositories(DbSession dbSession, List<RulesDefinition.Repository> repositories) { - List<RuleRepositoryDto> dtos = repositories - .stream() - .map(r -> new RuleRepositoryDto(r.key(), r.language(), r.name())) - .collect(toList(repositories.size())); - List<String> keys = dtos.stream().map(RuleRepositoryDto::getKey).collect(toList(repositories.size())); - dbClient.ruleRepositoryDao().insertOrUpdate(dbSession, dtos); - dbClient.ruleRepositoryDao().deleteIfKeyNotIn(dbSession, keys); - dbSession.commit(); - } - - @Override - public void stop() { - // nothing - } - - private void registerRule(RegisterRulesContext context, RulesDefinition.Rule ruleDef, DbSession session) { - RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key()); - - RuleDefinitionDto ruleDefinitionDto = context.getDbRuleFor(ruleDef) - .orElseGet(() -> { - RuleDefinitionDto newRule = createRuleDto(ruleDef, session); - context.created(newRule); - return newRule; - }); - - // we must detect renaming __before__ we modify the DTO - if (!ruleDefinitionDto.getKey().equals(ruleKey)) { - context.renamed(ruleDefinitionDto); - ruleDefinitionDto.setRuleKey(ruleKey); - } - - if (mergeRule(ruleDef, ruleDefinitionDto)) { - context.updated(ruleDefinitionDto); - } - - if (mergeDebtDefinitions(ruleDef, ruleDefinitionDto)) { - context.updated(ruleDefinitionDto); - } - - if (mergeTags(ruleDef, ruleDefinitionDto)) { - context.updated(ruleDefinitionDto); - } - - if (mergeSecurityStandards(ruleDef, ruleDefinitionDto)) { - context.updated(ruleDefinitionDto); - } - - if (context.isUpdated(ruleDefinitionDto) || context.isRenamed(ruleDefinitionDto)) { - update(session, ruleDefinitionDto); - } else if (!context.isCreated(ruleDefinitionDto)) { - context.unchanged(ruleDefinitionDto); - } - - mergeParams(ruleDef, ruleDefinitionDto, session); - updateDeprecatedKeys(context, ruleDef, ruleDefinitionDto, session); - } - - private RuleDefinitionDto createRuleDto(RulesDefinition.Rule ruleDef, DbSession session) { - RuleDefinitionDto ruleDto = new RuleDefinitionDto() - .setRuleKey(RuleKey.of(ruleDef.repository().key(), ruleDef.key())) - .setPluginKey(ruleDef.pluginKey()) - .setIsTemplate(ruleDef.template()) - .setConfigKey(ruleDef.internalKey()) - .setLanguage(ruleDef.repository().language()) - .setName(ruleDef.name()) - .setSeverity(ruleDef.severity()) - .setStatus(ruleDef.status()) - .setGapDescription(ruleDef.gapDescription()) - .setSystemTags(ruleDef.tags()) - .setSecurityStandards(ruleDef.securityStandards()) - .setType(RuleType.valueOf(ruleDef.type().name())) - .setScope(toDtoScope(ruleDef.scope())) - .setIsExternal(ruleDef.repository().isExternal()) - .setIsAdHoc(false) - .setCreatedAt(system2.now()) - .setUpdatedAt(system2.now()); - if (ruleDef.htmlDescription() != null) { - ruleDto.setDescription(ruleDef.htmlDescription()); - ruleDto.setDescriptionFormat(Format.HTML); - } else { - ruleDto.setDescription(ruleDef.markdownDescription()); - ruleDto.setDescriptionFormat(Format.MARKDOWN); - } - DebtRemediationFunction debtRemediationFunction = ruleDef.debtRemediationFunction(); - if (debtRemediationFunction != null) { - ruleDto.setDefRemediationFunction(debtRemediationFunction.type().name()); - ruleDto.setDefRemediationGapMultiplier(debtRemediationFunction.gapMultiplier()); - ruleDto.setDefRemediationBaseEffort(debtRemediationFunction.baseEffort()); - ruleDto.setGapDescription(ruleDef.gapDescription()); - } - - dbClient.ruleDao().insert(session, ruleDto); - return ruleDto; - } - - private static Scope toDtoScope(RuleScope scope) { - switch (scope) { - case ALL: - return Scope.ALL; - case MAIN: - return Scope.MAIN; - case TEST: - return Scope.TEST; - default: - throw new IllegalArgumentException("Unknown rule scope: " + scope); - } - } - - private static boolean mergeRule(RulesDefinition.Rule def, RuleDefinitionDto dto) { - boolean changed = false; - if (!StringUtils.equals(dto.getName(), def.name())) { - dto.setName(def.name()); - changed = true; - } - if (mergeDescription(def, dto)) { - changed = true; - } - if (!StringUtils.equals(dto.getPluginKey(), def.pluginKey())) { - dto.setPluginKey(def.pluginKey()); - changed = true; - } - if (!StringUtils.equals(dto.getConfigKey(), def.internalKey())) { - dto.setConfigKey(def.internalKey()); - changed = true; - } - String severity = def.severity(); - if (!ObjectUtils.equals(dto.getSeverityString(), severity)) { - dto.setSeverity(severity); - changed = true; - } - boolean isTemplate = def.template(); - if (isTemplate != dto.isTemplate()) { - dto.setIsTemplate(isTemplate); - changed = true; - } - if (def.status() != dto.getStatus()) { - dto.setStatus(def.status()); - changed = true; - } - if (!StringUtils.equals(dto.getScope().name(), def.scope().name())) { - dto.setScope(toDtoScope(def.scope())); - changed = true; - } - if (!StringUtils.equals(dto.getLanguage(), def.repository().language())) { - dto.setLanguage(def.repository().language()); - changed = true; - } - RuleType type = RuleType.valueOf(def.type().name()); - if (!ObjectUtils.equals(dto.getType(), type.getDbConstant())) { - dto.setType(type); - changed = true; - } - if (dto.isAdHoc()) { - dto.setIsAdHoc(false); - changed = true; - } - return changed; - } - - private static boolean mergeDescription(RulesDefinition.Rule def, RuleDefinitionDto dto) { - boolean changed = false; - if (def.htmlDescription() != null && !StringUtils.equals(dto.getDescription(), def.htmlDescription())) { - dto.setDescription(def.htmlDescription()); - dto.setDescriptionFormat(Format.HTML); - changed = true; - } else if (def.markdownDescription() != null && !StringUtils.equals(dto.getDescription(), def.markdownDescription())) { - dto.setDescription(def.markdownDescription()); - dto.setDescriptionFormat(Format.MARKDOWN); - changed = true; - } - return changed; - } - - private static boolean mergeDebtDefinitions(RulesDefinition.Rule def, RuleDefinitionDto dto) { - // Debt definitions are set to null if the sub-characteristic and the remediation function are null - DebtRemediationFunction debtRemediationFunction = def.debtRemediationFunction(); - boolean hasDebt = debtRemediationFunction != null; - if (hasDebt) { - return mergeDebtDefinitions(dto, - debtRemediationFunction.type().name(), - debtRemediationFunction.gapMultiplier(), - debtRemediationFunction.baseEffort(), - def.gapDescription()); - } - return mergeDebtDefinitions(dto, null, null, null, null); - } - - private static boolean mergeDebtDefinitions(RuleDefinitionDto dto, @Nullable String remediationFunction, - @Nullable String remediationCoefficient, @Nullable String remediationOffset, @Nullable String effortToFixDescription) { - boolean changed = false; - - if (!StringUtils.equals(dto.getDefRemediationFunction(), remediationFunction)) { - dto.setDefRemediationFunction(remediationFunction); - changed = true; - } - if (!StringUtils.equals(dto.getDefRemediationGapMultiplier(), remediationCoefficient)) { - dto.setDefRemediationGapMultiplier(remediationCoefficient); - changed = true; - } - if (!StringUtils.equals(dto.getDefRemediationBaseEffort(), remediationOffset)) { - dto.setDefRemediationBaseEffort(remediationOffset); - changed = true; - } - if (!StringUtils.equals(dto.getGapDescription(), effortToFixDescription)) { - dto.setGapDescription(effortToFixDescription); - changed = true; - } - return changed; - } - - private void mergeParams(RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession session) { - List<RuleParamDto> paramDtos = dbClient.ruleDao().selectRuleParamsByRuleKey(session, rule.getKey()); - Map<String, RuleParamDto> existingParamsByName = Maps.newHashMap(); - - Profiler profiler = Profiler.create(Loggers.get(getClass())); - for (RuleParamDto paramDto : paramDtos) { - RulesDefinition.Param paramDef = ruleDef.param(paramDto.getName()); - if (paramDef == null) { - profiler.start(); - dbClient.activeRuleDao().deleteParamsByRuleParamOfAllOrganizations(session, paramDto); - profiler.stopDebug(format("Propagate deleted param with name %s to active rules of rule %s", paramDto.getName(), rule.getKey())); - dbClient.ruleDao().deleteRuleParam(session, paramDto.getId()); - } else { - if (mergeParam(paramDto, paramDef)) { - dbClient.ruleDao().updateRuleParam(session, rule, paramDto); - } - existingParamsByName.put(paramDto.getName(), paramDto); - } - } - - // Create newly parameters - for (RulesDefinition.Param param : ruleDef.params()) { - RuleParamDto paramDto = existingParamsByName.get(param.key()); - if (paramDto != null) { - continue; - } - paramDto = RuleParamDto.createFor(rule) - .setName(param.key()) - .setDescription(param.description()) - .setDefaultValue(param.defaultValue()) - .setType(param.type().toString()); - dbClient.ruleDao().insertRuleParam(session, rule, paramDto); - if (StringUtils.isEmpty(param.defaultValue())) { - continue; - } - // Propagate the default value to existing active rule parameters - profiler.start(); - for (ActiveRuleDto activeRule : dbClient.activeRuleDao().selectByRuleIdOfAllOrganizations(session, rule.getId())) { - ActiveRuleParamDto activeParam = ActiveRuleParamDto.createFor(paramDto).setValue(param.defaultValue()); - dbClient.activeRuleDao().insertParam(session, activeRule, activeParam); - } - profiler.stopDebug(format("Propagate new param with name %s to active rules of rule %s", paramDto.getName(), rule.getKey())); - } - } - - private static boolean mergeParam(RuleParamDto paramDto, RulesDefinition.Param paramDef) { - boolean changed = false; - if (!StringUtils.equals(paramDto.getType(), paramDef.type().toString())) { - paramDto.setType(paramDef.type().toString()); - changed = true; - } - if (!StringUtils.equals(paramDto.getDefaultValue(), paramDef.defaultValue())) { - paramDto.setDefaultValue(paramDef.defaultValue()); - changed = true; - } - if (!StringUtils.equals(paramDto.getDescription(), paramDef.description())) { - paramDto.setDescription(paramDef.description()); - changed = true; - } - return changed; - } - - private void updateDeprecatedKeys(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, - DbSession dbSession) { - - Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDefinition = SingleDeprecatedRuleKey.from(ruleDef); - Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDB = context.getDBDeprecatedKeysFor(rule); - - // DeprecatedKeys that must be deleted - List<String> uuidsToBeDeleted = difference(deprecatedRuleKeysFromDB, deprecatedRuleKeysFromDefinition).stream() - .map(SingleDeprecatedRuleKey::getUuid) - .collect(toList()); - - dbClient.ruleDao().deleteDeprecatedRuleKeys(dbSession, uuidsToBeDeleted); - - // DeprecatedKeys that must be created - Sets.SetView<SingleDeprecatedRuleKey> deprecatedRuleKeysToBeCreated = difference(deprecatedRuleKeysFromDefinition, deprecatedRuleKeysFromDB); - - deprecatedRuleKeysToBeCreated - .forEach(r -> dbClient.ruleDao().insert(dbSession, new DeprecatedRuleKeyDto() - .setUuid(uuidFactory.create()) - .setRuleId(rule.getId()) - .setOldRepositoryKey(r.getOldRepositoryKey()) - .setOldRuleKey(r.getOldRuleKey()) - .setCreatedAt(system2.now()))); - } - - private static boolean mergeTags(RulesDefinition.Rule ruleDef, RuleDefinitionDto dto) { - boolean changed = false; - - if (RuleStatus.REMOVED == ruleDef.status()) { - dto.setSystemTags(emptySet()); - changed = true; - } else if (dto.getSystemTags().size() != ruleDef.tags().size() || - !dto.getSystemTags().containsAll(ruleDef.tags())) { - dto.setSystemTags(ruleDef.tags()); - // FIXME this can't be implemented easily with organization support: remove end-user tags that are now declared as system - // RuleTagHelper.applyTags(dto, ImmutableSet.copyOf(dto.getTags())); - changed = true; - } - return changed; - } - - private static boolean mergeSecurityStandards(RulesDefinition.Rule ruleDef, RuleDefinitionDto dto) { - boolean changed = false; - - if (RuleStatus.REMOVED == ruleDef.status()) { - dto.setSecurityStandards(emptySet()); - changed = true; - } else if (dto.getSecurityStandards().size() != ruleDef.securityStandards().size() || - !dto.getSecurityStandards().containsAll(ruleDef.securityStandards())) { - dto.setSecurityStandards(ruleDef.securityStandards()); - changed = true; - } - return changed; - } - - private void processRemainingDbRules(RegisterRulesContext recorder, DbSession dbSession) { - // custom rules check status of template, so they must be processed at the end - List<RuleDefinitionDto> customRules = newArrayList(); - - recorder.getRemaining().forEach(rule -> { - if (rule.isCustomRule()) { - customRules.add(rule); - } else if (!rule.isAdHoc() && rule.getStatus() != RuleStatus.REMOVED) { - removeRule(dbSession, recorder, rule); - } - }); - - for (RuleDefinitionDto customRule : customRules) { - Integer templateId = customRule.getTemplateId(); - checkNotNull(templateId, "Template id of the custom rule '%s' is null", customRule); - Optional<RuleDefinitionDto> template = dbClient.ruleDao().selectDefinitionById(templateId, dbSession); - if (template.isPresent() && template.get().getStatus() != RuleStatus.REMOVED) { - if (updateCustomRuleFromTemplateRule(customRule, template.get())) { - update(dbSession, customRule); - } - } else { - removeRule(dbSession, recorder, customRule); - } - } - - dbSession.commit(); - } - - private void removeRule(DbSession session, RegisterRulesContext recorder, RuleDefinitionDto rule) { - LOG.info(format("Disable rule %s", rule.getKey())); - rule.setStatus(RuleStatus.REMOVED); - rule.setSystemTags(emptySet()); - update(session, rule); - // FIXME resetting the tags for all organizations must be handled a different way - // rule.setTags(Collections.emptySet()); - // update(session, rule.getMetadata()); - recorder.removed(rule); - if (recorder.getRemoved().count() % 100 == 0) { - session.commit(); - } - } - - private static boolean updateCustomRuleFromTemplateRule(RuleDefinitionDto customRule, RuleDefinitionDto templateRule) { - boolean changed = false; - if (!StringUtils.equals(customRule.getLanguage(), templateRule.getLanguage())) { - customRule.setLanguage(templateRule.getLanguage()); - changed = true; - } - if (!StringUtils.equals(customRule.getConfigKey(), templateRule.getConfigKey())) { - customRule.setConfigKey(templateRule.getConfigKey()); - changed = true; - } - if (!StringUtils.equals(customRule.getPluginKey(), templateRule.getPluginKey())) { - customRule.setPluginKey(templateRule.getPluginKey()); - changed = true; - } - if (!StringUtils.equals(customRule.getDefRemediationFunction(), templateRule.getDefRemediationFunction())) { - customRule.setDefRemediationFunction(templateRule.getDefRemediationFunction()); - changed = true; - } - if (!StringUtils.equals(customRule.getDefRemediationGapMultiplier(), templateRule.getDefRemediationGapMultiplier())) { - customRule.setDefRemediationGapMultiplier(templateRule.getDefRemediationGapMultiplier()); - changed = true; - } - if (!StringUtils.equals(customRule.getDefRemediationBaseEffort(), templateRule.getDefRemediationBaseEffort())) { - customRule.setDefRemediationBaseEffort(templateRule.getDefRemediationBaseEffort()); - changed = true; - } - if (!StringUtils.equals(customRule.getGapDescription(), templateRule.getGapDescription())) { - customRule.setGapDescription(templateRule.getGapDescription()); - changed = true; - } - if (customRule.getStatus() != templateRule.getStatus()) { - customRule.setStatus(templateRule.getStatus()); - changed = true; - } - if (!StringUtils.equals(customRule.getSeverityString(), templateRule.getSeverityString())) { - customRule.setSeverity(templateRule.getSeverityString()); - changed = true; - } - return changed; - } - - /** - * SONAR-4642 - * <p/> - * Remove active rules on repositories that still exists. - * <p/> - * For instance, if the javascript repository do not provide anymore some rules, active rules related to this rules will be removed. - * But if the javascript repository do not exists anymore, then related active rules will not be removed. - * <p/> - * The side effect of this approach is that extended repositories will not be managed the same way. - * If an extended repository do not exists anymore, then related active rules will be removed. - */ - private List<ActiveRuleChange> removeActiveRulesOnStillExistingRepositories(DbSession dbSession, RegisterRulesContext recorder, - List<RulesDefinition.ExtendedRepository> context) { - List<String> repositoryKeys = context.stream() - .map(RulesDefinition.ExtendedRepository::key) - .collect(MoreCollectors.toList(context.size())); - - List<ActiveRuleChange> changes = new ArrayList<>(); - Profiler profiler = Profiler.create(Loggers.get(getClass())); - recorder.getRemoved().forEach(rule -> { - // SONAR-4642 Remove active rules only when repository still exists - if (repositoryKeys.contains(rule.getRepositoryKey())) { - profiler.start(); - changes.addAll(qProfileRules.deleteRule(dbSession, rule)); - profiler.stopDebug(format("Remove active rule for rule %s", rule.getKey())); - } - }); - return changes; - } - - private void update(DbSession session, RuleDefinitionDto rule) { - rule.setUpdatedAt(system2.now()); - dbClient.ruleDao().update(session, rule); - } - - private static void verifyRuleKeyConsistency(List<RulesDefinition.ExtendedRepository> repositories, RegisterRulesContext registerRulesContext) { - List<RulesDefinition.Rule> definedRules = repositories.stream() - .flatMap(r -> r.rules().stream()) - .collect(toList()); - - Set<RuleKey> definedRuleKeys = definedRules.stream() - .map(r -> RuleKey.of(r.repository().key(), r.key())) - .collect(toSet()); - - List<RuleKey> definedDeprecatedRuleKeys = definedRules.stream() - .flatMap(r -> r.deprecatedRuleKeys().stream()) - .collect(toList()); - - // Find duplicates in declared deprecated rule keys - Set<RuleKey> duplicates = findDuplicates(definedDeprecatedRuleKeys); - checkState(duplicates.isEmpty(), "The following deprecated rule keys are declared at least twice [%s]", - lazyToString(() -> duplicates.stream().map(RuleKey::toString).collect(Collectors.joining(",")))); - - // Find rule keys that are both deprecated and used - Set<RuleKey> intersection = intersection(new HashSet<>(definedRuleKeys), new HashSet<>(definedDeprecatedRuleKeys)).immutableCopy(); - checkState(intersection.isEmpty(), "The following rule keys are declared both as deprecated and used key [%s]", - lazyToString(() -> intersection.stream().map(RuleKey::toString).collect(Collectors.joining(",")))); - - // Find incorrect usage of deprecated keys - ImmutableMap<RuleKey, SingleDeprecatedRuleKey> dbDeprecatedRuleKeysByOldRuleKey = registerRulesContext.getDbDeprecatedKeysByOldRuleKey(); - - Set<String> incorrectRuleKeyMessage = definedRules.stream() - .flatMap(r -> filterInvalidDeprecatedRuleKeys(dbDeprecatedRuleKeysByOldRuleKey, r)) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - - checkState(incorrectRuleKeyMessage.isEmpty(), "An incorrect state of deprecated rule keys has been detected.\n %s", - lazyToString(() -> incorrectRuleKeyMessage.stream().collect(Collectors.joining("\n")))); - } - - private static Stream<String> filterInvalidDeprecatedRuleKeys(ImmutableMap<RuleKey, SingleDeprecatedRuleKey> dbDeprecatedRuleKeysByOldRuleKey, - RulesDefinition.Rule rule) { - return rule.deprecatedRuleKeys().stream() - .map(rk -> { - SingleDeprecatedRuleKey singleDeprecatedRuleKey = dbDeprecatedRuleKeysByOldRuleKey.get(rk); - if (singleDeprecatedRuleKey == null) { - // new deprecated rule key : OK - return null; - } - RuleKey parentRuleKey = RuleKey.of(rule.repository().key(), rule.key()); - if (parentRuleKey.equals(singleDeprecatedRuleKey.getNewRuleKeyAsRuleKey())) { - // same parent : OK - return null; - } - if (rule.deprecatedRuleKeys().contains(parentRuleKey)) { - // the new rule is deprecating the old parentRuleKey : OK - return null; - } - return format("The deprecated rule key [%s] was previously deprecated by [%s]. [%s] should be a deprecated key of [%s],", - rk.toString(), - singleDeprecatedRuleKey.getNewRuleKeyAsRuleKey().toString(), - singleDeprecatedRuleKey.getNewRuleKeyAsRuleKey().toString(), - RuleKey.of(rule.repository().key(), rule.key()).toString()); - }); - } - - private static Object lazyToString(Supplier<String> toString) { - return new Object() { - @Override - public String toString() { - return toString.get(); - } - }; - } - - private static <T> Set<T> findDuplicates(Collection<T> list) { - Set<T> duplicates = new HashSet<>(); - Set<T> uniques = new HashSet<>(); - - list.stream().forEach(t -> { - if (!uniques.add(t)) { - duplicates.add(t); - } - }); - - return duplicates; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java deleted file mode 100644 index 5a4074a20bd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.base.Splitter; -import com.google.common.base.Strings; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; -import org.sonar.api.server.ServerSide; -import org.sonar.api.server.rule.RuleParamType; -import org.sonar.api.utils.System2; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.rule.RuleDto.Format; -import org.sonar.db.rule.RuleMetadataDto; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.organization.DefaultOrganizationProvider; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.util.TypeValidations; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.collect.Lists.newArrayList; -import static java.lang.String.format; -import static org.sonar.server.exceptions.BadRequestException.checkRequest; - -@ServerSide -public class RuleCreator { - - private final System2 system2; - private final RuleIndexer ruleIndexer; - private final DbClient dbClient; - private final TypeValidations typeValidations; - private final DefaultOrganizationProvider defaultOrganizationProvider; - - public RuleCreator(System2 system2, RuleIndexer ruleIndexer, DbClient dbClient, TypeValidations typeValidations, DefaultOrganizationProvider defaultOrganizationProvider) { - this.system2 = system2; - this.ruleIndexer = ruleIndexer; - this.dbClient = dbClient; - this.typeValidations = typeValidations; - this.defaultOrganizationProvider = defaultOrganizationProvider; - } - - public RuleKey create(DbSession dbSession, NewCustomRule newRule) { - RuleKey templateKey = newRule.templateKey(); - checkArgument(templateKey != null, "Rule template key should not be null"); - String defaultOrganizationUuid = defaultOrganizationProvider.get().getUuid(); - OrganizationDto defaultOrganization = dbClient.organizationDao().selectByUuid(dbSession, defaultOrganizationUuid) - .orElseThrow(() -> new IllegalStateException(format("Could not find default organization for uuid '%s'", defaultOrganizationUuid))); - RuleDto templateRule = dbClient.ruleDao().selectByKey(dbSession, defaultOrganization.getUuid(), templateKey) - .orElseThrow(() -> new IllegalArgumentException(format("The template key doesn't exist: %s", templateKey))); - checkArgument(templateRule.isTemplate(), "This rule is not a template rule: %s", templateKey.toString()); - checkArgument(templateRule.getStatus() != RuleStatus.REMOVED, "The template key doesn't exist: %s", templateKey.toString()); - validateCustomRule(newRule, dbSession, templateKey); - - RuleKey customRuleKey = RuleKey.of(templateRule.getRepositoryKey(), newRule.ruleKey()); - Optional<RuleDefinitionDto> definition = loadRule(dbSession, customRuleKey); - int customRuleId = definition.map(d -> updateExistingRule(d, newRule, dbSession)) - .orElseGet(() -> createCustomRule(customRuleKey, newRule, templateRule, dbSession)); - - ruleIndexer.commitAndIndex(dbSession, customRuleId); - return customRuleKey; - } - - private void validateCustomRule(NewCustomRule newRule, DbSession dbSession, RuleKey templateKey) { - List<String> errors = new ArrayList<>(); - - validateRuleKey(errors, newRule.ruleKey()); - validateName(errors, newRule); - validateDescription(errors, newRule); - - String severity = newRule.severity(); - if (Strings.isNullOrEmpty(severity)) { - errors.add("The severity is missing"); - } else if (!Severity.ALL.contains(severity)) { - errors.add(format("Severity \"%s\" is invalid", severity)); - } - if (newRule.status() == null) { - errors.add("The status is missing"); - } - - for (RuleParamDto ruleParam : dbClient.ruleDao().selectRuleParamsByRuleKey(dbSession, templateKey)) { - try { - validateParam(ruleParam, newRule.parameter(ruleParam.getName())); - } catch (BadRequestException validationError) { - errors.addAll(validationError.errors()); - } - } - checkRequest(errors.isEmpty(), errors); - } - - @CheckForNull - private void validateParam(RuleParamDto ruleParam, @Nullable String value) { - if (value != null) { - RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType()); - if (ruleParamType.multiple()) { - List<String> values = newArrayList(Splitter.on(",").split(value)); - typeValidations.validate(values, ruleParamType.type(), ruleParamType.values()); - } else { - typeValidations.validate(value, ruleParamType.type(), ruleParamType.values()); - } - } - } - - private static void validateName(List<String> errors, NewCustomRule newRule) { - if (Strings.isNullOrEmpty(newRule.name())) { - errors.add("The name is missing"); - } - } - - private static void validateDescription(List<String> errors, NewCustomRule newRule) { - if (Strings.isNullOrEmpty(newRule.htmlDescription()) && Strings.isNullOrEmpty(newRule.markdownDescription())) { - errors.add("The description is missing"); - } - } - - private static void validateRuleKey(List<String> errors, String ruleKey) { - if (!ruleKey.matches("^[\\w]+$")) { - errors.add(format("The rule key \"%s\" is invalid, it should only contain: a-z, 0-9, \"_\"", ruleKey)); - } - } - - private Optional<RuleDefinitionDto> loadRule(DbSession dbSession, RuleKey ruleKey) { - return dbClient.ruleDao().selectDefinitionByKey(dbSession, ruleKey); - } - - private int createCustomRule(RuleKey ruleKey, NewCustomRule newRule, RuleDto templateRuleDto, DbSession dbSession) { - RuleDefinitionDto ruleDefinition = new RuleDefinitionDto() - .setRuleKey(ruleKey) - .setPluginKey(templateRuleDto.getPluginKey()) - .setTemplateId(templateRuleDto.getId()) - .setConfigKey(templateRuleDto.getConfigKey()) - .setName(newRule.name()) - .setDescription(newRule.markdownDescription()) - .setDescriptionFormat(Format.MARKDOWN) - .setSeverity(newRule.severity()) - .setStatus(newRule.status()) - .setType(newRule.type() == null ? templateRuleDto.getType() : newRule.type().getDbConstant()) - .setLanguage(templateRuleDto.getLanguage()) - .setDefRemediationFunction(templateRuleDto.getDefRemediationFunction()) - .setDefRemediationGapMultiplier(templateRuleDto.getDefRemediationGapMultiplier()) - .setDefRemediationBaseEffort(templateRuleDto.getDefRemediationBaseEffort()) - .setGapDescription(templateRuleDto.getGapDescription()) - .setScope(templateRuleDto.getScope()) - .setSystemTags(templateRuleDto.getSystemTags()) - .setSecurityStandards(templateRuleDto.getSecurityStandards()) - .setIsExternal(false) - .setIsAdHoc(false) - .setCreatedAt(system2.now()) - .setUpdatedAt(system2.now()); - dbClient.ruleDao().insert(dbSession, ruleDefinition); - - Set<String> tags = templateRuleDto.getTags(); - if (!tags.isEmpty()) { - RuleMetadataDto ruleMetadata = new RuleMetadataDto() - .setOrganizationUuid(defaultOrganizationProvider.get().getUuid()) - .setRuleId(ruleDefinition.getId()) - .setTags(tags) - .setCreatedAt(system2.now()) - .setUpdatedAt(system2.now()); - dbClient.ruleDao().insertOrUpdate(dbSession, ruleMetadata); - } - - for (RuleParamDto templateRuleParamDto : dbClient.ruleDao().selectRuleParamsByRuleKey(dbSession, templateRuleDto.getKey())) { - String customRuleParamValue = Strings.emptyToNull(newRule.parameter(templateRuleParamDto.getName())); - createCustomRuleParams(customRuleParamValue, ruleDefinition, templateRuleParamDto, dbSession); - } - return ruleDefinition.getId(); - } - - private void createCustomRuleParams(@Nullable String paramValue, RuleDefinitionDto ruleDto, RuleParamDto templateRuleParam, DbSession dbSession) { - RuleParamDto ruleParamDto = RuleParamDto.createFor(ruleDto) - .setName(templateRuleParam.getName()) - .setType(templateRuleParam.getType()) - .setDescription(templateRuleParam.getDescription()) - .setDefaultValue(paramValue); - dbClient.ruleDao().insertRuleParam(dbSession, ruleDto, ruleParamDto); - } - - private int updateExistingRule(RuleDefinitionDto ruleDto, NewCustomRule newRule, DbSession dbSession) { - if (ruleDto.getStatus().equals(RuleStatus.REMOVED)) { - if (newRule.isPreventReactivation()) { - throw new ReactivationException(format("A removed rule with the key '%s' already exists", ruleDto.getKey().rule()), ruleDto.getKey()); - } else { - ruleDto.setStatus(RuleStatus.READY) - .setUpdatedAt(system2.now()); - dbClient.ruleDao().update(dbSession, ruleDto); - } - } else { - throw new IllegalArgumentException(format("A rule with the key '%s' already exists", ruleDto.getKey().rule())); - } - return ruleDto.getId(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleTagHelper.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleTagHelper.java deleted file mode 100644 index d96ac1fe8d0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleTagHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.collect.Sets; -import java.util.Set; -import org.sonar.api.server.rule.RuleTagFormat; -import org.sonar.db.rule.RuleDto; - -class RuleTagHelper { - - private RuleTagHelper() { - // only static stuff - } - - /** - * Validates tags and resolves conflicts between user and system tags. - */ - static boolean applyTags(RuleDto rule, Set<String> tags) { - for (String tag : tags) { - RuleTagFormat.validate(tag); - } - - Set<String> initialTags = rule.getTags(); - final Set<String> systemTags = rule.getSystemTags(); - Set<String> withoutSystemTags = Sets.filter(tags, input -> input != null && !systemTags.contains(input)); - rule.setTags(withoutSystemTags); - return withoutSystemTags.size() != initialTags.size() || !withoutSystemTags.containsAll(initialTags); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java deleted file mode 100644 index 9df29ada1a9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdate.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.collect.Maps; -import java.util.Map; -import java.util.Set; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.db.organization.OrganizationDto; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.sonar.server.rule.RuleUpdate.RuleUpdateUseCase.CUSTOM_RULE; -import static org.sonar.server.rule.RuleUpdate.RuleUpdateUseCase.PLUGIN_RULE; - -public class RuleUpdate { - - private final RuleKey ruleKey; - - private boolean changeTags = false; - private boolean changeMarkdownNote = false; - private boolean changeDebtRemediationFunction = false; - private boolean changeName = false; - private boolean changeDescription = false; - private boolean changeSeverity = false; - private boolean changeStatus = false; - private boolean changeParameters = false; - private final RuleUpdateUseCase useCase; - private Set<String> tags; - private String markdownNote; - private DebtRemediationFunction debtRemediationFunction; - - private String name; - private String markdownDescription; - private String severity; - private RuleStatus status; - private final Map<String, String> parameters = Maps.newHashMap(); - private OrganizationDto organization; - - private RuleUpdate(RuleKey ruleKey, RuleUpdateUseCase useCase) { - this.ruleKey = ruleKey; - this.useCase = useCase; - } - - public RuleKey getRuleKey() { - return ruleKey; - } - - @CheckForNull - public Set<String> getTags() { - return tags; - } - - /** - * Set to <code>null</code> or empty set to remove existing tags. - */ - public RuleUpdate setTags(@Nullable Set<String> tags) { - this.tags = tags; - this.changeTags = true; - return this; - } - - @CheckForNull - public String getMarkdownNote() { - return markdownNote; - } - - /** - * Set to <code>null</code> or blank to remove existing note. - */ - public RuleUpdate setMarkdownNote(@Nullable String s) { - this.markdownNote = s == null ? null : StringUtils.defaultIfBlank(s, null); - this.changeMarkdownNote = true; - return this; - } - - @CheckForNull - public DebtRemediationFunction getDebtRemediationFunction() { - return debtRemediationFunction; - } - - public RuleUpdate setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) { - this.debtRemediationFunction = fn; - this.changeDebtRemediationFunction = true; - return this; - } - - @CheckForNull - public String getName() { - return name; - } - - public RuleUpdate setName(@Nullable String name) { - checkCustomRule(); - this.name = name; - this.changeName = true; - return this; - } - - @CheckForNull - public String getMarkdownDescription() { - return markdownDescription; - } - - public RuleUpdate setMarkdownDescription(@Nullable String markdownDescription) { - checkCustomRule(); - this.markdownDescription = markdownDescription; - this.changeDescription = true; - return this; - } - - @CheckForNull - public String getSeverity() { - return severity; - } - - public RuleUpdate setSeverity(@Nullable String severity) { - checkCustomRule(); - this.severity = severity; - this.changeSeverity = true; - return this; - } - - @CheckForNull - public RuleStatus getStatus() { - return status; - } - - public RuleUpdate setStatus(@Nullable RuleStatus status) { - checkCustomRule(); - this.status = status; - this.changeStatus = true; - return this; - } - - /** - * Parameters to be updated (only for custom rules) - */ - public RuleUpdate setParameters(Map<String, String> params) { - checkCustomRule(); - this.parameters.clear(); - this.parameters.putAll(params); - this.changeParameters = true; - return this; - } - - public RuleUpdate setOrganization(OrganizationDto organization) { - this.organization = organization; - return this; - } - - public Map<String, String> getParameters() { - return parameters; - } - - @CheckForNull - public String parameter(final String paramKey) { - return parameters.get(paramKey); - } - - boolean isCustomRule() { - return useCase.isCustomRule; - } - - public boolean isChangeTags() { - return changeTags; - } - - public boolean isChangeMarkdownNote() { - return changeMarkdownNote; - } - - public boolean isChangeDebtRemediationFunction() { - return changeDebtRemediationFunction; - } - - public boolean isChangeName() { - return changeName; - } - - public boolean isChangeDescription() { - return changeDescription; - } - - public boolean isChangeSeverity() { - return changeSeverity; - } - - public boolean isChangeStatus() { - return changeStatus; - } - - public boolean isChangeParameters() { - return changeParameters; - } - - public boolean isEmpty() { - return !changeMarkdownNote && !changeTags && !changeDebtRemediationFunction && isCustomRuleFieldsEmpty(); - } - - private boolean isCustomRuleFieldsEmpty() { - return !changeName && !changeDescription && !changeSeverity && !changeStatus && !changeParameters; - } - - private void checkCustomRule() { - checkArgument(useCase == CUSTOM_RULE, "Not a custom rule"); - } - - public OrganizationDto getOrganization() { - return organization; - } - - /** - * Use to update a rule provided by a plugin (name, description, severity, status and parameters cannot by changed) - */ - public static RuleUpdate createForPluginRule(RuleKey ruleKey) { - return new RuleUpdate(ruleKey, PLUGIN_RULE); - } - - /** - * Use to update a custom rule - */ - public static RuleUpdate createForCustomRule(RuleKey ruleKey) { - return new RuleUpdate(ruleKey, CUSTOM_RULE); - } - - public enum RuleUpdateUseCase { - PLUGIN_RULE(false), - CUSTOM_RULE(true); - - public final boolean isCustomRule; - - RuleUpdateUseCase(boolean isCustomRule) { - this.isCustomRule = isCustomRule; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java deleted file mode 100644 index 8cf466a23e9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.base.Function; -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Consumer; -import javax.annotation.Nonnull; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; -import org.sonar.api.server.ServerSide; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.utils.System2; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.user.UserSession; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Strings.isNullOrEmpty; -import static com.google.common.collect.FluentIterable.from; -import static com.google.common.collect.Lists.newArrayList; -import static org.apache.commons.lang.StringUtils.isBlank; - -@ServerSide -public class RuleUpdater { - - private final DbClient dbClient; - private final RuleIndexer ruleIndexer; - private final System2 system; - - public RuleUpdater(DbClient dbClient, RuleIndexer ruleIndexer, System2 system) { - this.dbClient = dbClient; - this.ruleIndexer = ruleIndexer; - this.system = system; - } - - /** - * Update manual rules and custom rules (rules instantiated from templates) - */ - public boolean update(DbSession dbSession, RuleUpdate update, OrganizationDto organization, UserSession userSession) { - if (update.isEmpty()) { - return false; - } - - RuleDto rule = getRuleDto(update); - // validate only the changes, not all the rule fields - apply(update, rule, userSession); - update(dbSession, rule); - updateParameters(dbSession, organization, update, rule); - ruleIndexer.commitAndIndex(dbSession, rule.getId(), organization); - - return true; - } - - /** - * Load all the DTOs required for validating changes and updating rule - */ - private RuleDto getRuleDto(RuleUpdate change) { - try (DbSession dbSession = dbClient.openSession(false)) { - RuleDto rule = dbClient.ruleDao().selectOrFailByKey(dbSession, change.getOrganization(), change.getRuleKey()); - if (RuleStatus.REMOVED == rule.getStatus()) { - throw new IllegalArgumentException("Rule with REMOVED status cannot be updated: " + change.getRuleKey()); - } - return rule; - } - } - - private void apply(RuleUpdate update, RuleDto rule, UserSession userSession) { - if (update.isChangeName()) { - updateName(update, rule); - } - if (update.isChangeDescription()) { - updateDescription(update, rule); - } - if (update.isChangeSeverity()) { - updateSeverity(update, rule); - } - if (update.isChangeStatus()) { - updateStatus(update, rule); - } - if (update.isChangeMarkdownNote()) { - updateMarkdownNote(update, rule, userSession); - } - if (update.isChangeTags()) { - updateTags(update, rule); - } - // order is important -> sub-characteristic must be set - if (update.isChangeDebtRemediationFunction()) { - updateDebtRemediationFunction(update, rule); - } - } - - private static void updateName(RuleUpdate update, RuleDto rule) { - String name = update.getName(); - if (isNullOrEmpty(name)) { - throw new IllegalArgumentException("The name is missing"); - } - rule.setName(name); - } - - private static void updateDescription(RuleUpdate update, RuleDto rule) { - String description = update.getMarkdownDescription(); - if (isNullOrEmpty(description)) { - throw new IllegalArgumentException("The description is missing"); - } - rule.setDescription(description); - rule.setDescriptionFormat(RuleDto.Format.MARKDOWN); - } - - private static void updateSeverity(RuleUpdate update, RuleDto rule) { - String severity = update.getSeverity(); - if (isNullOrEmpty(severity) || !Severity.ALL.contains(severity)) { - throw new IllegalArgumentException("The severity is invalid"); - } - rule.setSeverity(severity); - } - - private static void updateStatus(RuleUpdate update, RuleDto rule) { - RuleStatus status = update.getStatus(); - if (status == null) { - throw new IllegalArgumentException("The status is missing"); - } - rule.setStatus(status); - } - - private static void updateTags(RuleUpdate update, RuleDto rule) { - Set<String> tags = update.getTags(); - if (tags == null || tags.isEmpty()) { - rule.setTags(Collections.emptySet()); - } else { - RuleTagHelper.applyTags(rule, tags); - } - } - - private static void updateDebtRemediationFunction(RuleUpdate update, RuleDto rule) { - DebtRemediationFunction function = update.getDebtRemediationFunction(); - if (function == null) { - rule.setRemediationFunction(null); - rule.setRemediationGapMultiplier(null); - rule.setRemediationBaseEffort(null); - } else { - if (isSameAsDefaultFunction(function, rule)) { - // reset to default - rule.setRemediationFunction(null); - rule.setRemediationGapMultiplier(null); - rule.setRemediationBaseEffort(null); - } else { - rule.setRemediationFunction(function.type().name()); - rule.setRemediationGapMultiplier(function.gapMultiplier()); - rule.setRemediationBaseEffort(function.baseEffort()); - } - } - } - - private void updateMarkdownNote(RuleUpdate update, RuleDto rule, UserSession userSession) { - if (isBlank(update.getMarkdownNote())) { - rule.setNoteData(null); - rule.setNoteCreatedAt(null); - rule.setNoteUpdatedAt(null); - rule.setNoteUserUuid(null); - } else { - long now = system.now(); - rule.setNoteData(update.getMarkdownNote()); - rule.setNoteCreatedAt(rule.getNoteCreatedAt() != null ? rule.getNoteCreatedAt() : now); - rule.setNoteUpdatedAt(now); - rule.setNoteUserUuid(userSession.getUuid()); - } - } - - private static boolean isSameAsDefaultFunction(DebtRemediationFunction fn, RuleDto rule) { - return new EqualsBuilder() - .append(fn.type().name(), rule.getDefRemediationFunction()) - .append(fn.gapMultiplier(), rule.getDefRemediationGapMultiplier()) - .append(fn.baseEffort(), rule.getDefRemediationBaseEffort()) - .isEquals(); - } - - private void updateParameters(DbSession dbSession, OrganizationDto organization, RuleUpdate update, RuleDto rule) { - if (update.isChangeParameters() && update.isCustomRule()) { - RuleDto customRule = rule; - Integer templateId = customRule.getTemplateId(); - checkNotNull(templateId, "Rule '%s' has no persisted template!", customRule); - Optional<RuleDefinitionDto> templateRule = dbClient.ruleDao().selectDefinitionById(templateId, dbSession); - if (!templateRule.isPresent()) { - throw new IllegalStateException(String.format("Template %s of rule %s does not exist", - customRule.getTemplateId(), customRule.getKey())); - } - List<String> paramKeys = newArrayList(); - - // Load active rules and its parameters in cache - Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParamsByActiveRule = getActiveRuleParamsByActiveRule(dbSession, organization, customRule); - // Browse custom rule parameters to create, update or delete them - deleteOrUpdateParameters(dbSession, update, customRule, paramKeys, activeRuleParamsByActiveRule); - } - } - - private Multimap<ActiveRuleDto, ActiveRuleParamDto> getActiveRuleParamsByActiveRule(DbSession dbSession, OrganizationDto organization, RuleDto customRule) { - List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByRuleId(dbSession, organization, customRule.getId()); - Map<Integer, OrgActiveRuleDto> activeRuleById = from(activeRuleDtos).uniqueIndex(ActiveRuleDto::getId); - List<Integer> activeRuleIds = Lists.transform(activeRuleDtos, ActiveRuleDto::getId); - List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, activeRuleIds); - return from(activeRuleParamDtos) - .index(new ActiveRuleParamToActiveRule(activeRuleById)); - } - - private void deleteOrUpdateParameters(DbSession dbSession, RuleUpdate update, RuleDto customRule, List<String> paramKeys, - Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParamsByActiveRule) { - for (RuleParamDto ruleParamDto : dbClient.ruleDao().selectRuleParamsByRuleKey(dbSession, update.getRuleKey())) { - String key = ruleParamDto.getName(); - String value = Strings.emptyToNull(update.parameter(key)); - - // Update rule param - ruleParamDto.setDefaultValue(value); - dbClient.ruleDao().updateRuleParam(dbSession, customRule.getDefinition(), ruleParamDto); - - if (value != null) { - // Update linked active rule params or create new one - updateOrInsertActiveRuleParams(dbSession, ruleParamDto, activeRuleParamsByActiveRule); - } else { - // Delete linked active rule params - deleteActiveRuleParams(dbSession, key, activeRuleParamsByActiveRule.values()); - } - paramKeys.add(key); - } - } - - private void updateOrInsertActiveRuleParams(DbSession dbSession, RuleParamDto ruleParamDto, Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParamsByActiveRule) { - activeRuleParamsByActiveRule - .keySet() - .forEach(new UpdateOrInsertActiveRuleParams(dbSession, dbClient, ruleParamDto, activeRuleParamsByActiveRule)); - } - - private void deleteActiveRuleParams(DbSession dbSession, String key, Collection<ActiveRuleParamDto> activeRuleParamDtos) { - activeRuleParamDtos.forEach(new DeleteActiveRuleParams(dbSession, dbClient, key)); - } - - private static class ActiveRuleParamToActiveRule implements Function<ActiveRuleParamDto, ActiveRuleDto> { - private final Map<Integer, OrgActiveRuleDto> activeRuleById; - - private ActiveRuleParamToActiveRule(Map<Integer, OrgActiveRuleDto> activeRuleById) { - this.activeRuleById = activeRuleById; - } - - @Override - public OrgActiveRuleDto apply(@Nonnull ActiveRuleParamDto input) { - return activeRuleById.get(input.getActiveRuleId()); - } - } - - private static class UpdateOrInsertActiveRuleParams implements Consumer<ActiveRuleDto> { - private final DbSession dbSession; - private final DbClient dbClient; - private final RuleParamDto ruleParamDto; - private final Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParams; - - private UpdateOrInsertActiveRuleParams(DbSession dbSession, DbClient dbClient, RuleParamDto ruleParamDto, Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParams) { - this.dbSession = dbSession; - this.dbClient = dbClient; - this.ruleParamDto = ruleParamDto; - this.activeRuleParams = activeRuleParams; - } - - @Override - public void accept(@Nonnull ActiveRuleDto activeRuleDto) { - Map<String, ActiveRuleParamDto> activeRuleParamByKey = from(activeRuleParams.get(activeRuleDto)) - .uniqueIndex(ActiveRuleParamDto::getKey); - ActiveRuleParamDto activeRuleParamDto = activeRuleParamByKey.get(ruleParamDto.getName()); - if (activeRuleParamDto != null) { - dbClient.activeRuleDao().updateParam(dbSession, activeRuleParamDto.setValue(ruleParamDto.getDefaultValue())); - } else { - dbClient.activeRuleDao().insertParam(dbSession, activeRuleDto, ActiveRuleParamDto.createFor(ruleParamDto).setValue(ruleParamDto.getDefaultValue())); - } - } - } - - private static class DeleteActiveRuleParams implements Consumer<ActiveRuleParamDto> { - private final DbSession dbSession; - private final DbClient dbClient; - private final String key; - - public DeleteActiveRuleParams(DbSession dbSession, DbClient dbClient, String key) { - this.dbSession = dbSession; - this.dbClient = dbClient; - this.key = key; - } - - @Override - public void accept(@Nonnull ActiveRuleParamDto activeRuleParamDto) { - if (activeRuleParamDto.getKey().equals(key)) { - dbClient.activeRuleDao().deleteParamById(dbSession, activeRuleParamDto.getId()); - } - } - } - - private void update(DbSession session, RuleDto rule) { - rule.setUpdatedAt(system.now()); - dbClient.ruleDao().update(session, rule.getDefinition()); - dbClient.ruleDao().insertOrUpdate(session, rule.getMetadata()); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectConfigurationLoader.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectConfigurationLoader.java deleted file mode 100644 index eaada4f4db1..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectConfigurationLoader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.settings; - -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import org.sonar.api.config.Configuration; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; - -import static java.lang.String.format; -import static java.util.Objects.requireNonNull; - -public interface ProjectConfigurationLoader { - /** - * Loads configuration for the specified components. - * - * <p> - * Returns the applicable component configuration with most specific configuration overriding more global ones - * (eg. global > project > branch). - * - * <p> - * Any component is accepted but SQ only supports specific properties for projects and branches. - */ - Map<String, Configuration> loadProjectConfigurations(DbSession dbSession, Set<ComponentDto> projects); - - default Configuration loadProjectConfiguration(DbSession dbSession, ComponentDto project) { - Map<String, Configuration> configurations = loadProjectConfigurations(dbSession, Collections.singleton(project)); - return requireNonNull(configurations.get(project.uuid()), () -> format("Configuration for project '%s' is not found", project.getKey())); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectConfigurationLoaderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectConfigurationLoaderImpl.java deleted file mode 100644 index b487038ab68..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectConfigurationLoaderImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.settings; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.sonar.api.config.Configuration; -import org.sonar.api.config.Settings; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.property.PropertyDto; -import org.sonar.server.setting.ChildSettings; - -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; - -public class ProjectConfigurationLoaderImpl implements ProjectConfigurationLoader { - private final Settings globalSettings; - private final DbClient dbClient; - - public ProjectConfigurationLoaderImpl(Settings globalSettings, DbClient dbClient) { - this.globalSettings = globalSettings; - this.dbClient = dbClient; - } - - @Override - public Map<String, Configuration> loadProjectConfigurations(DbSession dbSession, Set<ComponentDto> projects) { - Set<String> mainBranchDbKeys = projects.stream().map(ComponentDto::getKey).collect(Collectors.toSet()); - Map<String, ChildSettings> mainBranchSettingsByDbKey = loadMainBranchConfigurations(dbSession, mainBranchDbKeys); - return projects.stream() - .collect(uniqueIndex(ComponentDto::uuid, component -> { - if (component.getDbKey().equals(component.getKey())) { - return mainBranchSettingsByDbKey.get(component.getKey()).asConfiguration(); - } - - ChildSettings settings = new ChildSettings(mainBranchSettingsByDbKey.get(component.getKey())); - dbClient.propertiesDao() - .selectProjectProperties(dbSession, component.getDbKey()) - .forEach(property -> settings.setProperty(property.getKey(), property.getValue())); - return settings.asConfiguration(); - })); - } - - private Map<String, ChildSettings> loadMainBranchConfigurations(DbSession dbSession, Set<String> dbKeys) { - return dbKeys.stream().collect(uniqueIndex(Function.identity(), dbKey -> { - ChildSettings settings = new ChildSettings(globalSettings); - List<PropertyDto> propertyDtos = dbClient.propertiesDao() - .selectProjectProperties(dbSession, dbKey); - propertyDtos - .forEach(property -> settings.setProperty(property.getKey(), property.getValue())); - return settings; - })); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java deleted file mode 100644 index 09bb2e5b403..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.settings; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java b/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java deleted file mode 100644 index 64291c4aefd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.ArrayDeque; -import java.util.Deque; - -class CharactersReader { - - static final int END_OF_STREAM = -1; - - private final BufferedReader stringBuffer; - private final Deque<String> openTags; - - private int currentValue; - private int previousValue; - private int currentIndex = -1; - - public CharactersReader(BufferedReader stringBuffer) { - this.stringBuffer = stringBuffer; - this.openTags = new ArrayDeque<>(); - } - - boolean readNextChar() throws IOException { - previousValue = currentValue; - currentValue = stringBuffer.read(); - currentIndex++; - return currentValue != END_OF_STREAM; - } - - int getCurrentValue() { - return currentValue; - } - - int getPreviousValue() { - return previousValue; - } - - int getCurrentIndex() { - return currentIndex; - } - - void registerOpenTag(String textType) { - openTags.push(textType); - } - - void removeLastOpenTag() { - openTags.remove(); - } - - Deque<String> getOpenTags() { - return openTags; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/DecorationDataHolder.java b/server/sonar-server/src/main/java/org/sonar/server/source/DecorationDataHolder.java deleted file mode 100644 index d667e1e7e11..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/DecorationDataHolder.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import com.google.common.collect.Lists; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -class DecorationDataHolder { - - private static final String ENTITY_SEPARATOR = ";"; - private static final String FIELD_SEPARATOR = ","; - private static final String SYMBOL_PREFIX = "sym-"; - private static final String HIGHLIGHTABLE = "sym"; - - private List<OpeningHtmlTag> openingTagsEntries; - private int openingTagsIndex; - private List<Integer> closingTagsOffsets; - private int closingTagsIndex; - - DecorationDataHolder() { - openingTagsEntries = Lists.newArrayList(); - closingTagsOffsets = Lists.newArrayList(); - } - - void loadSymbolReferences(String symbolsReferences) { - String[] symbols = symbolsReferences.split(ENTITY_SEPARATOR); - for (String symbol : symbols) { - String[] symbolFields = symbol.split(FIELD_SEPARATOR); - int declarationStartOffset = Integer.parseInt(symbolFields[0]); - int declarationEndOffset = Integer.parseInt(symbolFields[1]); - int symbolLength = declarationEndOffset - declarationStartOffset; - String[] symbolOccurrences = Arrays.copyOfRange(symbolFields, 2, symbolFields.length); - loadSymbolOccurrences(declarationStartOffset, symbolLength, symbolOccurrences); - } - } - - void loadLineSymbolReferences(String symbolsReferences) { - String[] symbols = symbolsReferences.split(ENTITY_SEPARATOR); - for (String symbol : symbols) { - String[] symbolFields = symbol.split(FIELD_SEPARATOR); - int startOffset = Integer.parseInt(symbolFields[0]); - int endOffset = Integer.parseInt(symbolFields[1]); - int symbolLength = endOffset - startOffset; - int symbolId = Integer.parseInt(symbolFields[2]); - loadSymbolOccurrences(symbolId, symbolLength, new String[] { Integer.toString(startOffset) }); - } - } - - - void loadSyntaxHighlightingData(String syntaxHighlightingRules) { - String[] rules = syntaxHighlightingRules.split(ENTITY_SEPARATOR); - for (String rule : rules) { - String[] ruleFields = rule.split(FIELD_SEPARATOR); - int startOffset = Integer.parseInt(ruleFields[0]); - int endOffset = Integer.parseInt(ruleFields[1]); - if (startOffset < endOffset) { - insertAndPreserveOrder(new OpeningHtmlTag(startOffset, ruleFields[2]), openingTagsEntries); - insertAndPreserveOrder(endOffset, closingTagsOffsets); - } - } - } - - List<OpeningHtmlTag> getOpeningTagsEntries() { - return openingTagsEntries; - } - - OpeningHtmlTag getCurrentOpeningTagEntry() { - return openingTagsIndex < openingTagsEntries.size() ? openingTagsEntries.get(openingTagsIndex) : null; - } - - void nextOpeningTagEntry() { - openingTagsIndex++; - } - - List<Integer> getClosingTagsOffsets() { - return closingTagsOffsets; - } - - int getCurrentClosingTagOffset() { - return closingTagsIndex < closingTagsOffsets.size() ? closingTagsOffsets.get(closingTagsIndex) : -1; - } - - void nextClosingTagOffset() { - closingTagsIndex++; - } - - private void loadSymbolOccurrences(int declarationStartOffset, int symbolLength, String[] symbolOccurrences) { - for (String symbolOccurrence : symbolOccurrences) { - int occurrenceStartOffset = Integer.parseInt(symbolOccurrence); - int occurrenceEndOffset = occurrenceStartOffset + symbolLength; - insertAndPreserveOrder(new OpeningHtmlTag(occurrenceStartOffset, SYMBOL_PREFIX + declarationStartOffset + " " + HIGHLIGHTABLE), openingTagsEntries); - insertAndPreserveOrder(occurrenceEndOffset, closingTagsOffsets); - } - } - - private void insertAndPreserveOrder(OpeningHtmlTag newEntry, List<OpeningHtmlTag> openingHtmlTags) { - int insertionIndex = 0; - Iterator<OpeningHtmlTag> tagIterator = openingHtmlTags.iterator(); - while (tagIterator.hasNext() && tagIterator.next().getStartOffset() <= newEntry.getStartOffset()) { - insertionIndex++; - } - openingHtmlTags.add(insertionIndex, newEntry); - } - - private void insertAndPreserveOrder(int newOffset, List<Integer> orderedOffsets) { - int insertionIndex = 0; - Iterator<Integer> entriesIterator = orderedOffsets.iterator(); - while (entriesIterator.hasNext() && entriesIterator.next() <= newOffset) { - insertionIndex++; - } - orderedOffsets.add(insertionIndex, newOffset); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java deleted file mode 100644 index 7ac5c343234..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import java.util.List; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.apache.commons.lang.StringUtils; - -public class HtmlSourceDecorator { - - @CheckForNull - public String getDecoratedSourceAsHtml(@Nullable String sourceLine, @Nullable String highlighting, @Nullable String symbols) { - if (sourceLine == null) { - return null; - } - DecorationDataHolder decorationDataHolder = new DecorationDataHolder(); - if (StringUtils.isNotBlank(highlighting)) { - decorationDataHolder.loadSyntaxHighlightingData(highlighting); - } - if (StringUtils.isNotBlank(symbols)) { - decorationDataHolder.loadLineSymbolReferences(symbols); - } - HtmlTextDecorator textDecorator = new HtmlTextDecorator(); - List<String> decoratedSource = textDecorator.decorateTextWithHtml(sourceLine, decorationDataHolder, 1, 1); - if (decoratedSource == null) { - return null; - } else { - if (decoratedSource.isEmpty()) { - return ""; - } else { - return decoratedSource.get(0); - } - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java deleted file mode 100644 index 2cb2fe91e35..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import com.google.common.io.Closeables; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.util.Collection; -import java.util.List; -import javax.annotation.Nullable; -import org.sonar.api.utils.log.Loggers; - -import static com.google.common.collect.Lists.newArrayList; - -class HtmlTextDecorator { - - static final char CR_END_OF_LINE = '\r'; - static final char LF_END_OF_LINE = '\n'; - static final char HTML_OPENING = '<'; - static final char HTML_CLOSING = '>'; - static final char AMPERSAND = '&'; - static final String ENCODED_HTML_OPENING = "<"; - static final String ENCODED_HTML_CLOSING = ">"; - static final String ENCODED_AMPERSAND = "&"; - - List<String> decorateTextWithHtml(String text, DecorationDataHolder decorationDataHolder) { - return decorateTextWithHtml(text, decorationDataHolder, null, null); - } - - List<String> decorateTextWithHtml(String text, DecorationDataHolder decorationDataHolder, @Nullable Integer from, @Nullable Integer to) { - - StringBuilder currentHtmlLine = new StringBuilder(); - List<String> decoratedHtmlLines = newArrayList(); - int currentLine = 1; - - BufferedReader stringBuffer = null; - try { - stringBuffer = new BufferedReader(new StringReader(text)); - - CharactersReader charsReader = new CharactersReader(stringBuffer); - - while (charsReader.readNextChar()) { - if (shouldStop(currentLine, to)) { - break; - } - if (shouldStartNewLine(charsReader)) { - if (canAddLine(currentLine, from)) { - decoratedHtmlLines.add(currentHtmlLine.toString()); - } - currentLine++; - currentHtmlLine = new StringBuilder(); - } - addCharToCurrentLine(charsReader, currentHtmlLine, decorationDataHolder); - } - - closeCurrentSyntaxTags(charsReader, currentHtmlLine); - - if (shouldStartNewLine(charsReader)) { - addLine(decoratedHtmlLines, currentHtmlLine.toString(), currentLine, from, to); - currentLine++; - addLine(decoratedHtmlLines, "", currentLine, from, to); - } else if (currentHtmlLine.length() > 0) { - addLine(decoratedHtmlLines, currentHtmlLine.toString(), currentLine, from, to); - } - - } catch (IOException exception) { - String errorMsg = "An exception occurred while highlighting the syntax of one of the project's files"; - Loggers.get(HtmlTextDecorator.class).error(errorMsg); - throw new IllegalStateException(errorMsg, exception); - } finally { - Closeables.closeQuietly(stringBuffer); - } - - return decoratedHtmlLines; - } - - private void addCharToCurrentLine(CharactersReader charsReader, StringBuilder currentHtmlLine, DecorationDataHolder decorationDataHolder) { - if (shouldStartNewLine(charsReader)) { - if (shouldReopenPendingTags(charsReader)) { - reopenCurrentSyntaxTags(charsReader, currentHtmlLine); - } - } - - int numberOfTagsToClose = getNumberOfTagsToClose(charsReader.getCurrentIndex(), decorationDataHolder); - closeCompletedTags(charsReader, numberOfTagsToClose, currentHtmlLine); - - if (shouldClosePendingTags(charsReader)) { - closeCurrentSyntaxTags(charsReader, currentHtmlLine); - } - - Collection<String> tagsToOpen = getTagsToOpen(charsReader.getCurrentIndex(), decorationDataHolder); - openNewTags(charsReader, tagsToOpen, currentHtmlLine); - - if (shouldAppendCharToHtmlOutput(charsReader)) { - char currentChar = (char) charsReader.getCurrentValue(); - currentHtmlLine.append(normalize(currentChar)); - } - } - - private static void addLine(List<String> decoratedHtmlLines, String line, int currentLine, @Nullable Integer from, @Nullable Integer to) { - if (canAddLine(currentLine, from) && !shouldStop(currentLine, to)) { - decoratedHtmlLines.add(line); - } - } - - private static boolean canAddLine(int currentLine, @Nullable Integer from) { - return from == null || currentLine >= from; - } - - private static boolean shouldStop(int currentLine, @Nullable Integer to) { - return to != null && to < currentLine; - } - - private char[] normalize(char currentChar) { - char[] normalizedChars; - if (currentChar == HTML_OPENING) { - normalizedChars = ENCODED_HTML_OPENING.toCharArray(); - } else if (currentChar == HTML_CLOSING) { - normalizedChars = ENCODED_HTML_CLOSING.toCharArray(); - } else if (currentChar == AMPERSAND) { - normalizedChars = ENCODED_AMPERSAND.toCharArray(); - } else { - normalizedChars = new char[] {currentChar}; - } - return normalizedChars; - } - - private boolean shouldAppendCharToHtmlOutput(CharactersReader charsReader) { - return charsReader.getCurrentValue() != CR_END_OF_LINE && charsReader.getCurrentValue() != LF_END_OF_LINE; - } - - private int getNumberOfTagsToClose(int currentIndex, DecorationDataHolder dataHolder) { - int numberOfTagsToClose = 0; - - while (currentIndex == dataHolder.getCurrentClosingTagOffset()) { - numberOfTagsToClose++; - dataHolder.nextClosingTagOffset(); - } - return numberOfTagsToClose; - } - - private Collection<String> getTagsToOpen(int currentIndex, DecorationDataHolder dataHolder) { - Collection<String> tagsToOpen = newArrayList(); - while (dataHolder.getCurrentOpeningTagEntry() != null && currentIndex == dataHolder.getCurrentOpeningTagEntry().getStartOffset()) { - tagsToOpen.add(dataHolder.getCurrentOpeningTagEntry().getCssClass()); - dataHolder.nextOpeningTagEntry(); - } - return tagsToOpen; - } - - private boolean shouldClosePendingTags(CharactersReader charactersReader) { - return charactersReader.getCurrentValue() == CR_END_OF_LINE - || (charactersReader.getCurrentValue() == LF_END_OF_LINE && charactersReader.getPreviousValue() != CR_END_OF_LINE) - || (charactersReader.getCurrentValue() == CharactersReader.END_OF_STREAM && charactersReader.getPreviousValue() != LF_END_OF_LINE); - } - - private boolean shouldReopenPendingTags(CharactersReader charactersReader) { - return (charactersReader.getPreviousValue() == LF_END_OF_LINE && charactersReader.getCurrentValue() != LF_END_OF_LINE) - || (charactersReader.getPreviousValue() == CR_END_OF_LINE && charactersReader.getCurrentValue() != CR_END_OF_LINE - && charactersReader.getCurrentValue() != LF_END_OF_LINE); - } - - private boolean shouldStartNewLine(CharactersReader charactersReader) { - return charactersReader.getPreviousValue() == LF_END_OF_LINE - || (charactersReader.getPreviousValue() == CR_END_OF_LINE && charactersReader.getCurrentValue() != LF_END_OF_LINE); - } - - private void closeCompletedTags(CharactersReader charactersReader, int numberOfTagsToClose, - StringBuilder decoratedText) { - for (int i = 0; i < numberOfTagsToClose; i++) { - injectClosingHtml(decoratedText); - charactersReader.removeLastOpenTag(); - } - } - - private void openNewTags(CharactersReader charactersReader, Collection<String> tagsToOpen, - StringBuilder decoratedText) { - for (String tagToOpen : tagsToOpen) { - injectOpeningHtmlForRule(tagToOpen, decoratedText); - charactersReader.registerOpenTag(tagToOpen); - } - } - - private void closeCurrentSyntaxTags(CharactersReader charactersReader, StringBuilder decoratedText) { - for (int i = 0; i < charactersReader.getOpenTags().size(); i++) { - injectClosingHtml(decoratedText); - } - } - - private void reopenCurrentSyntaxTags(CharactersReader charactersReader, StringBuilder decoratedText) { - for (String tags : charactersReader.getOpenTags()) { - injectOpeningHtmlForRule(tags, decoratedText); - } - } - - private void injectOpeningHtmlForRule(String textType, StringBuilder decoratedText) { - decoratedText.append("<span class=\"").append(textType).append("\">"); - } - - private void injectClosingHtml(StringBuilder decoratedText) { - decoratedText.append("</span>"); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/OpeningHtmlTag.java b/server/sonar-server/src/main/java/org/sonar/server/source/OpeningHtmlTag.java deleted file mode 100644 index 358f89ffa8f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/OpeningHtmlTag.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -class OpeningHtmlTag { - - private final int startOffset; - private final String cssClass; - - OpeningHtmlTag(int startOffset, String cssClass) { - this.startOffset = startOffset; - this.cssClass = cssClass; - } - - int getStartOffset() { - return startOffset; - } - - String getCssClass() { - return cssClass; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - return compareTo((OpeningHtmlTag) o); - } - - @Override - public int hashCode() { - int result = startOffset; - result = 31 * result + (cssClass != null ? cssClass.hashCode() : 0); - return result; - } - - private boolean compareTo(OpeningHtmlTag otherTag) { - if (startOffset != otherTag.startOffset) { - return false; - } - return (cssClass != null) ? cssClass.equals(otherTag.cssClass) : (otherTag.cssClass == null); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java b/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java deleted file mode 100644 index 44a3013179d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.protobuf.DbFileSources; -import org.sonar.db.source.FileSourceDto; - -import static com.google.common.base.Preconditions.checkArgument; - -public class SourceService { - - private final DbClient dbClient; - private final HtmlSourceDecorator htmlDecorator; - private final Function<DbFileSources.Line, String> lineToHtml; - - public SourceService(DbClient dbClient, HtmlSourceDecorator htmlDecorator) { - this.dbClient = dbClient; - this.htmlDecorator = htmlDecorator; - this.lineToHtml = lineToHtml(); - } - - /** - * Returns a range of lines as raw db data. User permission is not verified. - * - * @param from starts from 1 - * @param toInclusive starts from 1, must be greater than or equal param {@code from} - */ - public Optional<Iterable<DbFileSources.Line>> getLines(DbSession dbSession, String fileUuid, int from, int toInclusive) { - return getLines(dbSession, fileUuid, from, toInclusive, Function.identity()); - } - - public Optional<Iterable<DbFileSources.Line>> getLines(DbSession dbSession, String fileUuid, Set<Integer> lines) { - return getLines(dbSession, fileUuid, lines, Function.identity()); - } - - /** - * Returns a range of lines as raw text. - * - * @see #getLines(DbSession, String, int, int) - */ - public Optional<Iterable<String>> getLinesAsRawText(DbSession dbSession, String fileUuid, int from, int toInclusive) { - return getLines(dbSession, fileUuid, from, toInclusive, DbFileSources.Line::getSource); - } - - public Optional<Iterable<String>> getLinesAsHtml(DbSession dbSession, String fileUuid, int from, int toInclusive) { - return getLines(dbSession, fileUuid, from, toInclusive, lineToHtml); - } - - private <E> Optional<Iterable<E>> getLines(DbSession dbSession, String fileUuid, int from, int toInclusive, Function<DbFileSources.Line, E> function) { - verifyLine(from); - checkArgument(toInclusive >= from, String.format("Line number must greater than or equal to %d, got %d", from, toInclusive)); - FileSourceDto dto = dbClient.fileSourceDao().selectByFileUuid(dbSession, fileUuid); - if (dto == null) { - return Optional.empty(); - } - return Optional.of(dto.getSourceData().getLinesList().stream() - .filter(line -> line.hasLine() && line.getLine() >= from) - .limit((toInclusive - from) + 1L) - .map(function) - .collect(MoreCollectors.toList())); - } - - private <E> Optional<Iterable<E>> getLines(DbSession dbSession, String fileUuid, Set<Integer> lines, Function<DbFileSources.Line, E> function) { - FileSourceDto dto = dbClient.fileSourceDao().selectByFileUuid(dbSession, fileUuid); - if (dto == null) { - return Optional.empty(); - } - return Optional.of(dto.getSourceData().getLinesList().stream() - .filter(line -> line.hasLine() && lines.contains(line.getLine())) - .map(function) - .collect(MoreCollectors.toList())); - } - - private static void verifyLine(int line) { - checkArgument(line >= 1, String.format("Line number must start at 1, got %d", line)); - } - - private Function<DbFileSources.Line, String> lineToHtml() { - return line -> htmlDecorator.getDecoratedSourceAsHtml(line.getSource(), line.getHighlighting(), line.getSymbols()); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/source/package-info.java deleted file mode 100644 index 81f98ebc983..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryData.java b/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryData.java deleted file mode 100644 index 89f3df4b38f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryData.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.telemetry; - -import java.util.Map; -import java.util.Optional; -import javax.annotation.Nullable; -import org.sonar.core.platform.EditionProvider; -import org.sonar.server.measure.index.ProjectMeasuresStatistics; - -import static java.util.Objects.requireNonNull; - -public class TelemetryData { - private final String serverId; - private final String version; - private final Map<String, String> plugins; - private final long ncloc; - private final long userCount; - private final long projectCount; - private final boolean usingBranches; - private final Database database; - private final Map<String, Long> projectCountByLanguage; - private final Map<String, Long> nclocByLanguage; - private final Optional<EditionProvider.Edition> edition; - private final String licenseType; - private final Long installationDate; - private final String installationVersion; - - private TelemetryData(Builder builder) { - serverId = builder.serverId; - version = builder.version; - plugins = builder.plugins; - ncloc = builder.ncloc; - userCount = builder.userCount; - projectCount = builder.projectMeasuresStatistics.getProjectCount(); - usingBranches = builder.usingBranches; - database = builder.database; - projectCountByLanguage = builder.projectMeasuresStatistics.getProjectCountByLanguage(); - nclocByLanguage = builder.projectMeasuresStatistics.getNclocByLanguage(); - edition = builder.edition; - licenseType = builder.licenseType; - installationDate = builder.installationDate; - installationVersion = builder.installationVersion; - } - - public String getServerId() { - return serverId; - } - - public String getVersion() { - return version; - } - - public Map<String, String> getPlugins() { - return plugins; - } - - public long getNcloc() { - return ncloc; - } - - public long getUserCount() { - return userCount; - } - - public long getProjectCount() { - return projectCount; - } - - public boolean isUsingBranches() { - return usingBranches; - } - - public Database getDatabase() { - return database; - } - - public Map<String, Long> getProjectCountByLanguage() { - return projectCountByLanguage; - } - - public Map<String, Long> getNclocByLanguage() { - return nclocByLanguage; - } - - public Optional<EditionProvider.Edition> getEdition() { - return edition; - } - - public Optional<String> getLicenseType() { - return Optional.ofNullable(licenseType); - } - - public Long getInstallationDate(){ - return installationDate; - } - - public String getInstallationVersion(){ - return installationVersion; - } - - static Builder builder() { - return new Builder(); - } - - static class Builder { - private String serverId; - private String version; - private long userCount; - private Map<String, String> plugins; - private Database database; - private ProjectMeasuresStatistics projectMeasuresStatistics; - private Long ncloc; - private Boolean usingBranches; - private Optional<EditionProvider.Edition> edition; - private String licenseType; - private Long installationDate; - private String installationVersion; - - private Builder() { - // enforce static factory method - } - - Builder setServerId(String serverId) { - this.serverId = serverId; - return this; - } - - Builder setVersion(String version) { - this.version = version; - return this; - } - - Builder setUserCount(long userCount) { - this.userCount = userCount; - return this; - } - - Builder setPlugins(Map<String, String> plugins) { - this.plugins = plugins; - return this; - } - - Builder setProjectMeasuresStatistics(ProjectMeasuresStatistics projectMeasuresStatistics) { - this.projectMeasuresStatistics = projectMeasuresStatistics; - return this; - } - - Builder setNcloc(long ncloc) { - this.ncloc = ncloc; - return this; - } - - Builder setDatabase(Database database) { - this.database = database; - return this; - } - - Builder setUsingBranches(boolean usingBranches) { - this.usingBranches = usingBranches; - return this; - } - - public Builder setEdition(Optional<EditionProvider.Edition> edition) { - this.edition = edition; - return this; - } - - public Builder setLicenseType(@Nullable String licenseType) { - this.licenseType = licenseType; - return this; - } - - public Builder setInstallationDate(@Nullable Long installationDate){ - this.installationDate = installationDate; - return this; - } - - public Builder setInstallationVersion(@Nullable String installationVersion){ - this.installationVersion = installationVersion; - return this; - } - - TelemetryData build() { - requireNonNull(serverId); - requireNonNull(version); - requireNonNull(plugins); - requireNonNull(projectMeasuresStatistics); - requireNonNull(ncloc); - requireNonNull(database); - requireNonNull(usingBranches); - requireNonNull(edition); - - return new TelemetryData(this); - } - } - - static class Database { - private final String name; - private final String version; - - Database(String name, String version) { - this.name = name; - this.version = version; - } - - public String getName() { - return name; - } - - public String getVersion() { - return version; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java deleted file mode 100644 index 8f4d17696d5..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.telemetry; - -import java.util.Locale; -import org.sonar.api.utils.text.JsonWriter; - -import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; - -public class TelemetryDataJsonWriter { - private TelemetryDataJsonWriter() { - // static methods - } - - public static void writeTelemetryData(JsonWriter json, TelemetryData statistics) { - json.beginObject(); - json.prop("id", statistics.getServerId()); - json.prop("version", statistics.getVersion()); - statistics.getEdition().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH))); - statistics.getLicenseType().ifPresent(e -> json.prop("licenseType", e)); - json.name("database"); - json.beginObject(); - json.prop("name", statistics.getDatabase().getName()); - json.prop("version", statistics.getDatabase().getVersion()); - json.endObject(); - json.name("plugins"); - json.beginArray(); - statistics.getPlugins().forEach((plugin, version) -> { - json.beginObject(); - json.prop("name", plugin); - json.prop("version", version); - json.endObject(); - }); - json.endArray(); - json.prop("userCount", statistics.getUserCount()); - json.prop("projectCount", statistics.getProjectCount()); - json.prop("usingBranches", statistics.isUsingBranches()); - json.prop(NCLOC_KEY, statistics.getNcloc()); - json.name("projectCountByLanguage"); - json.beginArray(); - statistics.getProjectCountByLanguage().forEach((language, count) -> { - json.beginObject(); - json.prop("language", language); - json.prop("count", count); - json.endObject(); - }); - json.endArray(); - json.name("nclocByLanguage"); - json.beginArray(); - statistics.getNclocByLanguage().forEach((language, ncloc) -> { - json.beginObject(); - json.prop("language", language); - json.prop("ncloc", ncloc); - json.endObject(); - }); - json.endArray(); - if (statistics.getInstallationDate() != null) { - json.prop("installationDate", statistics.getInstallationDate()); - } - if (statistics.getInstallationVersion() != null) { - json.prop("installationVersion", statistics.getInstallationVersion()); - } - json.endObject(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataLoader.java b/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataLoader.java deleted file mode 100644 index 25762f5b25c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataLoader.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.telemetry; - -public interface TelemetryDataLoader { - TelemetryData load(); - - String loadServerId(); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/text/Macro.java b/server/sonar-server/src/main/java/org/sonar/server/text/Macro.java deleted file mode 100644 index ad847d7e043..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/text/Macro.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.text; - -public interface Macro { - - String getRegex(); - - String getReplacement(); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java b/server/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java deleted file mode 100644 index b473ac96a82..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.text; - -import com.google.common.collect.ImmutableList; -import org.sonar.api.server.ServerSide; -import org.sonar.api.platform.Server; - -import java.util.List; - -@ServerSide -public class MacroInterpreter { - - private final List<Macro> macros; - - public MacroInterpreter(Server server) { - this.macros = ImmutableList.of( - new RuleMacro(server.getContextPath()) - ); - } - - public String interpret(String text) { - String textReplaced = text; - for (Macro macro : macros) { - textReplaced = textReplaced.replaceAll(macro.getRegex(), macro.getReplacement()); - } - return textReplaced; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/text/RuleMacro.java b/server/sonar-server/src/main/java/org/sonar/server/text/RuleMacro.java deleted file mode 100644 index 215091d64ca..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/text/RuleMacro.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.text; - -class RuleMacro implements Macro { - - private static final String COLON = "%3A"; - private final String contextPath; - - RuleMacro(String contextPath) { - this.contextPath = contextPath; - } - - /** - * First parameter is the repository, second one is the rule key. Exemple : {rule:squid:ArchitecturalConstraint} - */ - @Override - public String getRegex() { - return "\\{rule:([a-zA-Z0-9._-]++):([a-zA-Z0-9._-]++)\\}"; - } - - @Override - public String getReplacement() { - return "<a href='" + contextPath + "/coding_rules#rule_key=$1" + COLON + "$2'>$2</a>"; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/DeprecatedViews.java b/server/sonar-server/src/main/java/org/sonar/server/ui/DeprecatedViews.java deleted file mode 100644 index b8fc0595fc4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/DeprecatedViews.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import org.sonar.api.Startable; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.web.View; -import org.sonar.api.web.Widget; -import org.sonar.api.web.page.PageDefinition; - -/** - * @deprecated since 6.3 see {@link org.sonar.api.web.page.PageDefinition}. This class logs warnings at startup if there are pages using the old page API. - */ -@ServerSide -@Deprecated -public class DeprecatedViews implements Startable { - - private static final Logger LOGGER = Loggers.get(DeprecatedViews.class); - - private final View[] views; - - public DeprecatedViews() { - this.views = new View[0]; - } - - public DeprecatedViews(View[] views) { - this.views = views; - } - - @Override - public void start() { - for (View view : views) { - String pageOrWidget = view instanceof Widget ? "Widget" : "Page"; - LOGGER.warn("{} '{}' ({}) is ignored. See {} to define pages.", pageOrWidget, view.getTitle(), view.getId(), PageDefinition.class.getCanonicalName()); - } - } - - @Override - public void stop() { - // do nothing - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/PageDecorations.java b/server/sonar-server/src/main/java/org/sonar/server/ui/PageDecorations.java deleted file mode 100644 index c35f7567728..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/PageDecorations.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import java.util.Collections; -import java.util.List; -import org.sonar.api.server.ServerSide; -import org.sonar.api.web.PageDecoration; - -/** - * @since 3.3 - * @deprecated since 6.3 see {@link org.sonar.api.web.page.PageDefinition}. This class has not effect. - */ -@ServerSide -@Deprecated -public final class PageDecorations { - - private final PageDecoration[] decorations; - - public PageDecorations(List<PageDecoration> decorations) { - this.decorations = decorations.toArray(new PageDecoration[decorations.size()]); - } - - public PageDecorations() { - this(Collections.emptyList()); - } - - public PageDecoration[] get() { - return decorations;// NOSONAR expose internal representation - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/PageRepository.java b/server/sonar-server/src/main/java/org/sonar/server/ui/PageRepository.java deleted file mode 100644 index b3693678182..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/PageRepository.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import com.google.common.annotations.VisibleForTesting; -import java.util.List; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.sonar.api.Startable; -import org.sonar.api.server.ServerSide; -import org.sonar.api.web.page.Context; -import org.sonar.api.web.page.Page; -import org.sonar.api.web.page.Page.Qualifier; -import org.sonar.api.web.page.Page.Scope; -import org.sonar.api.web.page.PageDefinition; -import org.sonar.core.platform.PluginRepository; -import org.sonar.core.extension.CoreExtensionRepository; -import org.sonar.server.ui.page.CorePageDefinition; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableList.copyOf; -import static java.util.Collections.emptyList; -import static java.util.Comparator.comparing; -import static java.util.Objects.requireNonNull; -import static org.sonar.api.web.page.Page.Scope.COMPONENT; -import static org.sonar.api.web.page.Page.Scope.GLOBAL; -import static org.sonar.api.web.page.Page.Scope.ORGANIZATION; -import static org.sonar.core.util.stream.MoreCollectors.toList; - -@ServerSide -public class PageRepository implements Startable { - private final PluginRepository pluginRepository; - private final CoreExtensionRepository coreExtensionRepository; - private final List<PageDefinition> definitions; - private final List<CorePageDefinition> corePageDefinitions; - private List<Page> pages; - - /** - * Used by Pico when there is no {@link PageDefinition}. - */ - public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository) { - this.pluginRepository = pluginRepository; - this.coreExtensionRepository = coreExtensionRepository; - // in case there's no page definition - this.definitions = emptyList(); - this.corePageDefinitions = emptyList(); - } - - /** - * Used by Pico when there is only {@link PageDefinition} provided both by Plugin(s). - */ - public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository, - PageDefinition[] pageDefinitions) { - this.pluginRepository = pluginRepository; - this.coreExtensionRepository = coreExtensionRepository; - this.definitions = copyOf(pageDefinitions); - this.corePageDefinitions = emptyList(); - } - - /** - * Used by Pico when there is only {@link PageDefinition} provided both by Core Extension(s). - */ - public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository, - CorePageDefinition[] corePageDefinitions) { - this.pluginRepository = pluginRepository; - this.coreExtensionRepository = coreExtensionRepository; - this.definitions = emptyList(); - this.corePageDefinitions = copyOf(corePageDefinitions); - } - - /** - * Used by Pico when there is {@link PageDefinition} provided both by Core Extension(s) and Plugin(s). - */ - public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository, - PageDefinition[] pageDefinitions, CorePageDefinition[] corePageDefinitions) { - this.pluginRepository = pluginRepository; - this.coreExtensionRepository = coreExtensionRepository; - this.definitions = copyOf(pageDefinitions); - this.corePageDefinitions = copyOf(corePageDefinitions); - } - - @Override - public void start() { - Context context = new Context(); - definitions.forEach(definition -> definition.define(context)); - Context coreContext = new Context(); - corePageDefinitions.stream() - .map(CorePageDefinition::getPageDefinition) - .forEach(definition -> definition.define(coreContext)); - pages = Stream.concat( - context.getPages().stream().peek(this::checkPluginExists), - coreContext.getPages().stream().peek(this::checkCoreExtensionExists)) - .sorted(comparing(Page::getKey)) - .collect(toList()); - } - - @Override - public void stop() { - // nothing to do - } - - public List<Page> getGlobalPages(boolean isAdmin) { - return getPages(GLOBAL, isAdmin, null); - } - - public List<Page> getOrganizationPages(boolean isAdmin) { - return getPages(ORGANIZATION, isAdmin, null); - } - - public List<Page> getComponentPages(boolean isAdmin, String qualifierKey) { - Qualifier qualifier = Qualifier.fromKey(qualifierKey); - return qualifier == null ? emptyList() : getPages(COMPONENT, isAdmin, qualifier); - } - - private List<Page> getPages(Scope scope, boolean isAdmin, @Nullable Qualifier qualifier) { - return getAllPages().stream() - .filter(p -> p.getScope().equals(scope)) - .filter(p -> p.isAdmin() == isAdmin) - .filter(p -> !COMPONENT.equals(p.getScope()) || p.getComponentQualifiers().contains(qualifier)) - .collect(toList()); - } - - @VisibleForTesting - List<Page> getAllPages() { - return requireNonNull(pages, "Pages haven't been initialized yet"); - } - - private void checkPluginExists(Page page) { - String pluginKey = page.getPluginKey(); - checkState(pluginRepository.hasPlugin(pluginKey), - "Page '%s' references plugin '%s' that does not exist", page.getName(), pluginKey); - } - - private void checkCoreExtensionExists(Page page) { - String coreExtensionName = page.getPluginKey(); - checkState(coreExtensionRepository.isInstalled(coreExtensionName), - "Page '%s' references Core Extension '%s' which is not installed", page.getName(), coreExtensionName); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/VersionFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/ui/VersionFormatter.java deleted file mode 100644 index a395c09ae5a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/VersionFormatter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import com.google.common.base.Splitter; -import java.util.List; - -public class VersionFormatter { - private static final String VERSION_SEQUENCE_SEPARATION = "."; - - private VersionFormatter() { - // prevent instantiation - } - - public static String format(String technicalVersion) { - List<String> elements = Splitter.on(VERSION_SEQUENCE_SEPARATION).splitToList(technicalVersion); - if (elements.size() != 4) { - return technicalVersion; - } - - // version has the form 6.3.1.4563 - StringBuilder builder = new StringBuilder(); - builder - .append(elements.get(0)) - .append(VERSION_SEQUENCE_SEPARATION) - .append(elements.get(1)); - if (!"0".equals(elements.get(2))) { - builder.append(VERSION_SEQUENCE_SEPARATION) - .append(elements.get(2)); - } - - builder.append(" (build ").append(elements.get(3)).append(")"); - - return builder.toString(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/WebAnalyticsLoader.java b/server/sonar-server/src/main/java/org/sonar/server/ui/WebAnalyticsLoader.java deleted file mode 100644 index ce2f54f3065..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/WebAnalyticsLoader.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import java.util.Optional; -import org.sonar.api.server.ServerSide; - -@ServerSide -public interface WebAnalyticsLoader { - - /** - * URL path to the JS file to be loaded by webapp, for instance "/static/foo/bar.js". - * It always starts with "/" and does not include the optional web context. - */ - Optional<String> getUrlPathToJs(); - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/WebAnalyticsLoaderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/ui/WebAnalyticsLoaderImpl.java deleted file mode 100644 index b82267262cc..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/WebAnalyticsLoaderImpl.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.sonar.api.utils.MessageException; -import org.sonar.api.web.WebAnalytics; - -public class WebAnalyticsLoaderImpl implements WebAnalyticsLoader { - - @Nullable - private final WebAnalytics analytics; - - public WebAnalyticsLoaderImpl(WebAnalytics[] analytics) { - if (analytics.length > 1) { - List<String> classes = Arrays.stream(analytics).map(a -> a.getClass().getName()).collect(Collectors.toList()); - throw MessageException.of("Limited to only one web analytics plugin. Found multiple implementations: " + classes); - } - this.analytics = analytics.length == 1 ? analytics[0] : null; - } - - public WebAnalyticsLoaderImpl() { - this.analytics = null; - } - - @Override - public Optional<String> getUrlPathToJs() { - return Optional.ofNullable(analytics) - .map(WebAnalytics::getUrlPathToJs) - .filter(path -> !path.startsWith("/") && !path.contains("..") && !path.contains("://")) - .map(path -> "/" + path); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ui/package-info.java deleted file mode 100644 index 0a8222dc7dd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/page/CorePageDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/ui/page/CorePageDefinition.java deleted file mode 100644 index 2e935f2fefb..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/page/CorePageDefinition.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui.page; - -import org.sonar.api.ExtensionPoint; -import org.sonar.api.server.ServerSide; -import org.sonar.api.web.page.PageDefinition; - -/** - * This class must be used by core extensions to declare {@link PageDefinition}(s). - * <p> - * This allows to distinguish {@link PageDefinition} provided by plugins from those provided by Core Extensions and - * apply the appropriate security and consistency checks. - */ -@ServerSide -@ExtensionPoint -public interface CorePageDefinition { - - PageDefinition getPageDefinition(); -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/page/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ui/page/package-info.java deleted file mode 100644 index a1b7be58e59..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/page/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui.page; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-server/src/main/java/org/sonar/server/util/EnumUtils.java b/server/sonar-server/src/main/java/org/sonar/server/util/EnumUtils.java deleted file mode 100644 index 1a414a85a2d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/util/EnumUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.util; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; - -public class EnumUtils { - private EnumUtils() { - // prevent instantiation - } - - public static <E extends Enum<E>> List<E> toEnums(@Nullable Iterable<String> values, Class<E> enumClass) { - if (values == null) { - return Collections.emptyList(); - } - - List<E> result = new ArrayList<>(); - for (String s : values) { - result.add(Enum.valueOf(enumClass, s)); - } - return result; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/util/LanguageParamUtils.java b/server/sonar-server/src/main/java/org/sonar/server/util/LanguageParamUtils.java deleted file mode 100644 index 3defde1bcc7..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/util/LanguageParamUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.util; - -import java.util.Arrays; -import java.util.List; -import org.sonar.api.resources.Language; -import org.sonar.api.resources.Languages; -import org.sonar.core.util.stream.MoreCollectors; - -public class LanguageParamUtils { - - private LanguageParamUtils() { - // Utility class - } - - public static String getExampleValue(Languages languages) { - Language[] languageArray = languages.all(); - if (languageArray.length > 0) { - return languageArray[0].getKey(); - } else { - return ""; - } - } - - public static List<String> getOrderedLanguageKeys(Languages languages) { - Language[] all = languages.all(); - return Arrays.stream(all) - .map(Language::getKey) - .sorted() - .collect(MoreCollectors.toList(all.length)); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/WebhookQGChangeEventListener.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/WebhookQGChangeEventListener.java deleted file mode 100644 index 098302e7816..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/webhook/WebhookQGChangeEventListener.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.webhook; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.measures.Metric; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.AnalysisPropertyDto; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.changeevent.QGChangeEvent; -import org.sonar.server.qualitygate.changeevent.QGChangeEventListener; -import org.sonar.server.webhook.Branch.Type; - -public class WebhookQGChangeEventListener implements QGChangeEventListener { - private final WebHooks webhooks; - private final WebhookPayloadFactory webhookPayloadFactory; - private final DbClient dbClient; - - public WebhookQGChangeEventListener(WebHooks webhooks, WebhookPayloadFactory webhookPayloadFactory, DbClient dbClient) { - this.webhooks = webhooks; - this.webhookPayloadFactory = webhookPayloadFactory; - this.dbClient = dbClient; - } - - @Override - public void onIssueChanges(QGChangeEvent qualityGateEvent, Set<ChangedIssue> changedIssues) { - - if (!webhooks.isEnabled(qualityGateEvent.getProject())) { - return; - } - Optional<EvaluatedQualityGate> evaluatedQualityGate = qualityGateEvent.getQualityGateSupplier().get(); - if (isQGStatusUnchanged(qualityGateEvent, evaluatedQualityGate)) { - return; - } - - try (DbSession dbSession = dbClient.openSession(false)) { - callWebhook(dbSession, qualityGateEvent, evaluatedQualityGate.orElse(null)); - } - } - - private static boolean isQGStatusUnchanged(QGChangeEvent qualityGateEvent, Optional<EvaluatedQualityGate> evaluatedQualityGate) { - Optional<Metric.Level> previousStatus = qualityGateEvent.getPreviousStatus(); - if (!previousStatus.isPresent() && !evaluatedQualityGate.isPresent()) { - return true; - } - - return previousStatus - .map(previousQGStatus -> evaluatedQualityGate - .filter(newQualityGate -> newQualityGate.getStatus() == previousQGStatus) - .isPresent()) - .orElse(false); - } - - private void callWebhook(DbSession dbSession, QGChangeEvent event, @Nullable EvaluatedQualityGate evaluatedQualityGate) { - webhooks.sendProjectAnalysisUpdate( - new WebHooks.Analysis(event.getBranch().getUuid(), event.getAnalysis().getUuid(), null), - () -> buildWebHookPayload(dbSession, event, evaluatedQualityGate)); - } - - private WebhookPayload buildWebHookPayload(DbSession dbSession, QGChangeEvent event, @Nullable EvaluatedQualityGate evaluatedQualityGate) { - ComponentDto project = event.getProject(); - BranchDto branch = event.getBranch(); - SnapshotDto analysis = event.getAnalysis(); - Map<String, String> analysisProperties = dbClient.analysisPropertiesDao().selectByAnalysisUuid(dbSession, analysis.getUuid()) - .stream() - .collect(Collectors.toMap(AnalysisPropertyDto::getKey, AnalysisPropertyDto::getValue)); - String projectUuid = StringUtils.defaultString(project.getMainBranchProjectUuid(), project.projectUuid()); - ProjectAnalysis projectAnalysis = new ProjectAnalysis( - new Project(projectUuid, project.getKey(), project.name()), - null, - new Analysis(analysis.getUuid(), analysis.getCreatedAt(), analysis.getRevision()), - new Branch(branch.isMain(), branch.getKey(), Type.valueOf(branch.getBranchType().name())), - evaluatedQualityGate, - null, - analysisProperties); - return webhookPayloadFactory.create(projectAnalysis); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/package-info.java deleted file mode 100644 index 157f43819ea..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/webhook/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.webhook; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java deleted file mode 100644 index de5f24347fc..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.app; - -import java.io.File; -import java.io.IOException; -import java.util.Random; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; -import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; - -public class ProcessCommandWrapperImplTest { - private static final int PROCESS_NUMBER = 2; - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private MapSettings settings = new MapSettings(); - - @Test - public void requestSQRestart_throws_IAE_if_process_index_property_not_set() { - ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings.asConfig()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Property process.index is not set"); - - processCommandWrapper.requestSQRestart(); - } - - @Test - public void requestSQRestart_throws_IAE_if_process_shared_path_property_not_set() { - settings.setProperty(PROPERTY_PROCESS_INDEX, 1); - ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings.asConfig()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Property process.sharedDir is not set"); - - processCommandWrapper.requestSQRestart(); - } - - @Test - public void requestSQRestart_updates_shareMemory_file() throws IOException { - File tmpDir = temp.newFolder().getAbsoluteFile(); - settings.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath()); - settings.setProperty(PROPERTY_PROCESS_INDEX, PROCESS_NUMBER); - - ProcessCommandWrapperImpl underTest = new ProcessCommandWrapperImpl(settings.asConfig()); - underTest.requestSQRestart(); - - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(tmpDir, PROCESS_NUMBER)) { - assertThat(processCommands.askedForRestart()).isTrue(); - } - } - - @Test - public void requestSQStop_throws_IAE_if_process_shared_path_property_not_set() { - settings.setProperty(PROPERTY_PROCESS_INDEX, 1); - ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings.asConfig()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Property process.sharedDir is not set"); - - processCommandWrapper.requestHardStop(); - } - - @Test - public void requestSQStop_updates_shareMemory_file() throws IOException { - File tmpDir = temp.newFolder().getAbsoluteFile(); - settings.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath()); - settings.setProperty(PROPERTY_PROCESS_INDEX, PROCESS_NUMBER); - - ProcessCommandWrapperImpl underTest = new ProcessCommandWrapperImpl(settings.asConfig()); - underTest.requestHardStop(); - - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(tmpDir, PROCESS_NUMBER)) { - assertThat(processCommands.askedForHardStop()).isTrue(); - } - } - - @Test - public void notifyOperational_throws_IAE_if_process_sharedDir_property_not_set() { - settings.setProperty(PROPERTY_PROCESS_INDEX, 1); - ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings.asConfig()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Property process.sharedDir is not set"); - - processCommandWrapper.notifyOperational(); - } - - @Test - public void notifyOperational_throws_IAE_if_process_index_property_not_set() { - ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings.asConfig()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Property process.index is not set"); - - processCommandWrapper.notifyOperational(); - } - - @Test - public void notifyOperational_updates_shareMemory_file() throws IOException { - File tmpDir = temp.newFolder().getAbsoluteFile(); - settings.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath()); - settings.setProperty(PROPERTY_PROCESS_INDEX, PROCESS_NUMBER); - - ProcessCommandWrapperImpl underTest = new ProcessCommandWrapperImpl(settings.asConfig()); - underTest.notifyOperational(); - - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(tmpDir, PROCESS_NUMBER)) { - assertThat(processCommands.isOperational()).isTrue(); - } - } - - @Test - public void isCeOperational_reads_shared_memory_operational_flag_in_location_3() throws IOException { - File tmpDir = temp.newFolder().getAbsoluteFile(); - settings.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath()); - - boolean expected = new Random().nextBoolean(); - if (expected) { - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(tmpDir, 3)) { - processCommands.setOperational(); - } - } - - ProcessCommandWrapperImpl underTest = new ProcessCommandWrapperImpl(settings.asConfig()); - - assertThat(underTest.isCeOperational()).isEqualTo(expected); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/BranchFeatureProxyImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/BranchFeatureProxyImplTest.java deleted file mode 100644 index 6fb3d9a6449..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/branch/BranchFeatureProxyImplTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class BranchFeatureProxyImplTest { - - private BranchFeatureExtension branchFeatureExtension = mock(BranchFeatureExtension.class); - - @Test - public void return_false_when_no_extension() { - assertThat(new BranchFeatureProxyImpl().isEnabled()).isFalse(); - } - - @Test - public void return_false_when_extension_returns_false() { - when(branchFeatureExtension.isEnabled()).thenReturn(false); - assertThat(new BranchFeatureProxyImpl(branchFeatureExtension).isEnabled()).isFalse(); - } - - @Test - public void return_true_when_extension_returns_ftrue() { - when(branchFeatureExtension.isEnabled()).thenReturn(true); - assertThat(new BranchFeatureProxyImpl(branchFeatureExtension).isEnabled()).isTrue(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/BranchFeatureRule.java b/server/sonar-server/src/test/java/org/sonar/server/branch/BranchFeatureRule.java deleted file mode 100644 index 2bf56463474..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/branch/BranchFeatureRule.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.branch; - -import org.junit.rules.ExternalResource; - -public class BranchFeatureRule extends ExternalResource implements BranchFeatureProxy { - - private boolean enabled; - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - @Override - protected void after() { - reset(); - } - - public void reset() { - this.enabled = false; - } - - @Override - public boolean isEnabled() { - return enabled; - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/http/CeHttpClientTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/http/CeHttpClientTest.java deleted file mode 100644 index c53cf871bf4..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/http/CeHttpClientTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.http; - -import java.io.File; -import java.io.IOException; -import java.util.Optional; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okio.Buffer; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; -import org.sonar.process.ProcessEntryPoint; -import org.sonar.process.ProcessId; -import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - -import static java.lang.String.format; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.test.ExceptionCauseMatcher.hasType; - -public class CeHttpClientTest { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public MockWebServer server = new MockWebServer(); - - private File ipcSharedDir; - private CeHttpClient underTest; - - @Before - public void setUp() throws Exception { - ipcSharedDir = temp.newFolder(); - MapSettings settings = new MapSettings(); - settings.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, ipcSharedDir.getAbsolutePath()); - underTest = new CeHttpClientImpl(settings.asConfig()); - } - - @Test - public void retrieveSystemInfo_returns_absent_if_process_is_down() { - Optional<ProtobufSystemInfo.SystemInfo> info = underTest.retrieveSystemInfo(); - - assertThat(info.isPresent()).isFalse(); - } - - @Test - public void retrieveSystemInfo_get_information_if_process_is_up() { - Buffer response = new Buffer(); - response.read(ProtobufSystemInfo.Section.newBuilder().build().toByteArray()); - server.enqueue(new MockResponse().setBody(response)); - - // initialize registration of process - setUpWithHttpUrl(ProcessId.COMPUTE_ENGINE); - - Optional<ProtobufSystemInfo.SystemInfo> info = underTest.retrieveSystemInfo(); - assertThat(info.get().getSectionsCount()).isEqualTo(0); - } - - @Test - public void retrieveSystemInfo_throws_ISE_if_http_error() { - server.enqueue(new MockResponse().setResponseCode(500)); - - // initialize registration of process - setUpWithHttpUrl(ProcessId.COMPUTE_ENGINE); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Failed to call HTTP server of process " + ProcessId.COMPUTE_ENGINE); - expectedException.expectCause(hasType(IOException.class) - .andMessage(format("Server returned HTTP response code: 500 for URL: http://%s:%d/systemInfo", server.getHostName(), server.getPort()))); - underTest.retrieveSystemInfo(); - } - - @Test - public void changeLogLevel_throws_NPE_if_level_argument_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("level can't be null"); - - underTest.changeLogLevel(null); - } - - @Test - public void changeLogLevel_throws_ISE_if_http_error() { - String message = "blah"; - server.enqueue(new MockResponse().setResponseCode(500).setBody(message)); - - // initialize registration of process - setUpWithHttpUrl(ProcessId.COMPUTE_ENGINE); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Failed to call HTTP server of process " + ProcessId.COMPUTE_ENGINE); - expectedException.expectCause(hasType(IOException.class) - .andMessage(format("Failed to change log level in Compute Engine. Code was '500' and response was 'blah' for url " + - "'http://%s:%s/changeLogLevel'", server.getHostName(), server.getPort()))); - - underTest.changeLogLevel(LoggerLevel.DEBUG); - } - - @Test - public void changeLogLevel_does_not_fail_when_http_code_is_200() { - server.enqueue(new MockResponse().setResponseCode(200)); - - setUpWithHttpUrl(ProcessId.COMPUTE_ENGINE); - - underTest.changeLogLevel(LoggerLevel.TRACE); - } - - @Test - public void changelogLevel_does_not_fail_if_process_is_down() { - underTest.changeLogLevel(LoggerLevel.INFO); - } - - private void setUpWithHttpUrl(ProcessId processId) { - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, processId.getIpcIndex())) { - processCommands.setUp(); - processCommands.setHttpUrl(format("http://%s:%d", server.getHostName(), server.getPort())); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/BranchReportSubmitterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/queue/BranchReportSubmitterTest.java deleted file mode 100644 index 9768b0cb0fe..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/BranchReportSubmitterTest.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import com.google.common.collect.ImmutableMap; -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.function.BiConsumer; -import java.util.stream.IntStream; -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.stubbing.Answer; -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.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.ce.CeTaskTypes; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.favorite.FavoriteUpdater; -import org.sonar.server.permission.PermissionTemplateService; -import org.sonar.server.tester.UserSessionRule; - -import static java.util.Collections.emptyMap; -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -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; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; -import static org.sonar.db.component.ComponentTesting.newBranchDto; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; -import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; -import static org.sonar.db.permission.OrganizationPermission.SCAN; - -/** - * Tests of {@link ReportSubmitter} when branch support is installed. - */ -@RunWith(DataProviderRunner.class) -public class BranchReportSubmitterTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - private CeQueue queue = mock(CeQueueImpl.class); - private ComponentUpdater componentUpdater = mock(ComponentUpdater.class); - private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); - private FavoriteUpdater favoriteUpdater = mock(FavoriteUpdater.class); - private BranchSupportDelegate branchSupportDelegate = mock(BranchSupportDelegate.class); - private BranchSupport branchSupport = spy(new BranchSupport(branchSupportDelegate)); - - private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), branchSupport); - - @Test - public void submit_does_not_use_delegate_if_characteristics_are_empty() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertMainBranch(organization); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); - mockSuccessfulPrepareSubmitCall(); - InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); - - underTest.submit(organization.getKey(), project.getDbKey(), project.name(), emptyMap(), reportInput); - - verifyZeroInteractions(branchSupportDelegate); - } - - @Test - public void submit_a_report_on_existing_branch() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertMainBranch(organization); - ComponentDto branch = db.components().insertProjectBranch(project); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); - Map<String, String> randomCharacteristics = randomNonEmptyMap(); - BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(branch); - when(branchSupportDelegate.createComponentKey(project.getDbKey(), randomCharacteristics)) - .thenReturn(componentKey); - InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); - String taskUuid = mockSuccessfulPrepareSubmitCall(); - - underTest.submit(organization.getKey(), project.getDbKey(), project.name(), randomCharacteristics, reportInput); - - verifyZeroInteractions(permissionTemplateService); - verifyZeroInteractions(favoriteUpdater); - verify(branchSupport, times(0)).createBranchComponent(any(), any(), any(), any(), any()); - verify(branchSupportDelegate).createComponentKey(project.getDbKey(), randomCharacteristics); - verify(branchSupportDelegate, times(0)).createBranchComponent(any(), any(), any(), any(), any()); - verifyNoMoreInteractions(branchSupportDelegate); - verifyQueueSubmit(project, branch, user, randomCharacteristics, taskUuid); - } - - @Test - public void submit_a_report_on_missing_branch_but_existing_project() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto existingProject = db.components().insertMainBranch(organization); - BranchDto exitingProjectMainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), existingProject.uuid()).get(); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, existingProject); - Map<String, String> randomCharacteristics = randomNonEmptyMap(); - ComponentDto createdBranch = createButDoNotInsertBranch(existingProject); - BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(createdBranch); - when(branchSupportDelegate.createComponentKey(existingProject.getDbKey(), randomCharacteristics)) - .thenReturn(componentKey); - when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(existingProject), eq(exitingProjectMainBranch))) - .thenReturn(createdBranch); - InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); - String taskUuid = mockSuccessfulPrepareSubmitCall(); - - underTest.submit(organization.getKey(), existingProject.getDbKey(), existingProject.name(), randomCharacteristics, reportInput); - - verifyZeroInteractions(permissionTemplateService); - verifyZeroInteractions(favoriteUpdater); - verify(branchSupport).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(existingProject), eq(exitingProjectMainBranch)); - verify(branchSupportDelegate).createComponentKey(existingProject.getDbKey(), randomCharacteristics); - verify(branchSupportDelegate).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(existingProject), eq(exitingProjectMainBranch)); - verifyNoMoreInteractions(branchSupportDelegate); - verify(componentUpdater, times(0)).commitAndIndex(any(), any()); - verifyQueueSubmit(existingProject, createdBranch, user, randomCharacteristics, taskUuid); - } - - @Test - public void submit_report_on_missing_branch_of_missing_project_provisions_project_when_org_PROVISION_PROJECT_perm() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto nonExistingProject = newPrivateProjectDto(organization); - UserDto user = db.users().insertUser(); - userSession.logIn(user) - .addPermission(PROVISION_PROJECTS, organization) - .addPermission(SCAN, organization); - - Map<String, String> randomCharacteristics = randomNonEmptyMap(); - ComponentDto createdBranch = createButDoNotInsertBranch(nonExistingProject); - BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(createdBranch); - when(branchSupportDelegate.createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics)) - .thenReturn(componentKey); - when(componentUpdater.createWithoutCommit(any(), any(), eq(user.getId()))) - .thenAnswer((Answer<ComponentDto>) invocation -> db.components().insertMainBranch(nonExistingProject)); - when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject), any())) - .thenReturn(createdBranch); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(nonExistingProject.getKey()))) - .thenReturn(true); - String taskUuid = mockSuccessfulPrepareSubmitCall(); - InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); - - underTest.submit(organization.getKey(), nonExistingProject.getDbKey(), nonExistingProject.name(), randomCharacteristics, reportInput); - - BranchDto exitingProjectMainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), nonExistingProject.uuid()).get(); - verify(branchSupport).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject), eq(exitingProjectMainBranch)); - verify(branchSupportDelegate).createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics); - verify(branchSupportDelegate).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject), eq(exitingProjectMainBranch)); - verifyNoMoreInteractions(branchSupportDelegate); - verifyQueueSubmit(nonExistingProject, createdBranch, user, randomCharacteristics, taskUuid); - verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(nonExistingProject)); - } - - @Test - public void submit_fails_if_branch_support_delegate_createComponentKey_throws_an_exception() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertMainBranch(organization); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); - Map<String, String> randomCharacteristics = randomNonEmptyMap(); - InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); - RuntimeException expected = new RuntimeException("Faking an exception thrown by branchSupportDelegate"); - when(branchSupportDelegate.createComponentKey(any(), any())).thenThrow(expected); - - try { - underTest.submit(organization.getKey(), project.getDbKey(), project.name(), randomCharacteristics, reportInput); - fail("exception should have been thrown"); - } catch (Exception e) { - assertThat(e).isSameAs(expected); - } - } - - @DataProvider - public static Object[][] permissionsAllowingProjectProvisioning() { - BiConsumer<ComponentDto, UserSessionRule> noProjectPerm = (cpt, userSession) -> { - }; - BiConsumer<OrganizationDto, UserSessionRule> noOrgPerm = (cpt, userSession) -> { - }; - BiConsumer<ComponentDto, UserSessionRule> provisionOnProject = (cpt, userSession) -> userSession.addProjectPermission(PROVISIONING, cpt); - BiConsumer<OrganizationDto, UserSessionRule> provisionOnOrganization = (cpt, userSession) -> userSession.addPermission(PROVISION_PROJECTS, cpt); - return new Object[][] { - {provisionOnProject, noOrgPerm}, - {noProjectPerm, provisionOnOrganization}, - {provisionOnProject, provisionOnOrganization} - }; - } - - @Test - public void submit_report_on_missing_branch_of_missing_project_fails_with_ForbiddenException_if_only_scan_permission() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto nonExistingProject = newPrivateProjectDto(organization); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, nonExistingProject); - Map<String, String> randomCharacteristics = randomNonEmptyMap(); - ComponentDto createdBranch = createButDoNotInsertBranch(nonExistingProject); - BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(createdBranch); - when(branchSupportDelegate.createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics)) - .thenReturn(componentKey); - when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject), any())) - .thenReturn(createdBranch); - InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); - - expectedException.expect(ForbiddenException.class); - expectedException.expectMessage("Insufficient privileges"); - - underTest.submit(organization.getKey(), nonExistingProject.getDbKey(), nonExistingProject.name(), randomCharacteristics, reportInput); - } - - private static ComponentDto createButDoNotInsertBranch(ComponentDto project) { - BranchType randomBranchType = BranchType.values()[new Random().nextInt(BranchType.values().length)]; - BranchDto branchDto = newBranchDto(project.projectUuid(), randomBranchType); - return ComponentTesting.newProjectBranch(project, branchDto); - } - - private String mockSuccessfulPrepareSubmitCall() { - String taskUuid = randomAlphabetic(12); - when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(taskUuid)); - return taskUuid; - } - - private void verifyQueueSubmit(ComponentDto project, ComponentDto branch, UserDto user, Map<String, String> characteristics, String taskUuid) { - verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) - && submit.getComponent().filter(cpt -> cpt.getUuid().equals(branch.uuid()) && cpt.getMainComponentUuid().equals(project.uuid())).isPresent() - && submit.getSubmitterUuid().equals(user.getUuid()) - && submit.getCharacteristics().equals(characteristics) - && submit.getUuid().equals(taskUuid))); - } - - private static BranchSupport.ComponentKey createComponentKeyOfBranch(ComponentDto branch) { - BranchSupport.ComponentKey mainComponentKey = mockComponentKey(branch.getKey(), branch.getKey()); - when(mainComponentKey.getMainBranchComponentKey()).thenReturn(mainComponentKey); - - BranchSupport.ComponentKey componentKey = mockComponentKey(branch.getKey(), branch.getDbKey()); - when(componentKey.getBranch()).thenReturn(Optional.ofNullable(branch).map(b -> new BranchSupport.Branch(b.name(), BranchType.LONG))); - when(componentKey.getMainBranchComponentKey()).thenReturn(mainComponentKey); - - return componentKey; - } - - private static BranchSupport.ComponentKey mockComponentKey(String key, String dbKey) { - BranchSupport.ComponentKey componentKey = mock(BranchSupport.ComponentKey.class); - when(componentKey.getKey()).thenReturn(key); - when(componentKey.getDbKey()).thenReturn(dbKey); - return componentKey; - } - - private static ImmutableMap<String, String> randomNonEmptyMap() { - return IntStream.range(0, 1 + new Random().nextInt(5)) - .boxed() - .collect(uniqueIndex(i -> "key_" + i, i -> "val_" + i)); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/BranchSupportTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/queue/BranchSupportTest.java deleted file mode 100644 index af798ce77aa..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/BranchSupportTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import java.util.Collections; -import java.util.Map; -import java.util.Random; -import java.util.stream.IntStream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.sonar.db.DbSession; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.ce.queue.BranchSupport.ComponentKey; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; - -@RunWith(DataProviderRunner.class) -public class BranchSupportTest { - private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private BranchSupportDelegate branchSupportDelegate = mock(BranchSupportDelegate.class); - private BranchSupport underTestNoBranch = new BranchSupport(); - private BranchSupport underTestWithBranch = new BranchSupport(branchSupportDelegate); - - @Test - public void createComponentKey_of_main_branch() { - String projectKey = randomAlphanumeric(12); - - ComponentKey componentKey = underTestNoBranch.createComponentKey(projectKey, NO_CHARACTERISTICS); - - assertThat(componentKey) - .isEqualTo(underTestWithBranch.createComponentKey(projectKey, NO_CHARACTERISTICS)); - assertThat(componentKey.getKey()).isEqualTo(projectKey); - assertThat(componentKey.getDbKey()).isEqualTo(projectKey); - assertThat(componentKey.getMainBranchComponentKey()).isSameAs(componentKey); - assertThat(componentKey.getBranch()).isEmpty(); - assertThat(componentKey.getPullRequestKey()).isEmpty(); - } - - @Test - public void createComponentKey_delegates_to_delegate_if_characteristics_is_not_empty() { - String projectKey = randomAlphanumeric(12); - Map<String, String> nonEmptyMap = newRandomNonEmptyMap(); - ComponentKey expected = mock(ComponentKey.class); - when(branchSupportDelegate.createComponentKey(projectKey, nonEmptyMap)).thenReturn(expected); - - ComponentKey componentKey = underTestWithBranch.createComponentKey(projectKey, nonEmptyMap); - - assertThat(componentKey).isSameAs(expected); - } - - @Test - public void createBranchComponent_fails_with_ISE_if_delegate_is_null() { - DbSession dbSession = mock(DbSession.class); - ComponentKey componentKey = mock(ComponentKey.class); - OrganizationDto organization = new OrganizationDto(); - ComponentDto mainComponentDto = new ComponentDto(); - BranchDto mainComponentBranchDto = new BranchDto(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Current edition does not support branch feature"); - - underTestNoBranch.createBranchComponent(dbSession, componentKey, organization, mainComponentDto, mainComponentBranchDto); - } - - @Test - public void createBranchComponent_delegates_to_delegate() { - DbSession dbSession = mock(DbSession.class); - ComponentKey componentKey = mock(ComponentKey.class); - OrganizationDto organization = new OrganizationDto(); - ComponentDto mainComponentDto = new ComponentDto(); - ComponentDto expected = new ComponentDto(); - BranchDto mainComponentBranchDto = new BranchDto(); - when(branchSupportDelegate.createBranchComponent(dbSession, componentKey, organization, mainComponentDto, mainComponentBranchDto)) - .thenReturn(expected); - - ComponentDto dto = underTestWithBranch.createBranchComponent(dbSession, componentKey, organization, mainComponentDto, mainComponentBranchDto); - - assertThat(dto).isSameAs(expected); - } - - @DataProvider - public static Object[][] nullOrNonEmpty() { - return new Object[][] { - {null}, - {randomAlphabetic(5)}, - }; - } - - private static Map<String, String> newRandomNonEmptyMap() { - return IntStream.range(0, 1 + new Random().nextInt(10)).boxed().collect(uniqueIndex(i -> "key_" + i, i -> "val_" + i)); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/CeQueueCleanerTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/queue/CeQueueCleanerTest.java deleted file mode 100644 index f8c78ae07dc..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/CeQueueCleanerTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import java.util.Optional; -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.platform.ServerUpgradeStatus; -import org.sonar.api.utils.System2; -import org.sonar.ce.queue.CeQueue; -import org.sonar.db.DbTester; -import org.sonar.db.ce.CeQueueDto; -import org.sonar.db.ce.CeTaskInputDao; -import org.sonar.db.ce.CeTaskTypes; -import org.sonar.process.ProcessProperties; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class CeQueueCleanerTest { - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - private ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class); - private CeQueue queue = mock(CeQueue.class); - private MapSettings settings = new MapSettings(); - - @Test - public void start_does_not_reset_in_progress_tasks_to_pending() { - insertInQueue("TASK_1", CeQueueDto.Status.PENDING); - insertInQueue("TASK_2", CeQueueDto.Status.IN_PROGRESS); - - runCleaner(); - - assertThat(dbTester.getDbClient().ceQueueDao().countByStatus(dbTester.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(1); - assertThat(dbTester.getDbClient().ceQueueDao().countByStatus(dbTester.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(1); - } - - @Test - public void start_clears_queue_if_version_upgrade() { - when(serverUpgradeStatus.isUpgraded()).thenReturn(true); - - runCleaner(); - - verify(queue).clear(); - } - - @Test - public void start_does_not_clear_queue_if_version_upgrade_but_blue_green_deployment() { - when(serverUpgradeStatus.isUpgraded()).thenReturn(true); - settings.setProperty(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey(), true); - - runCleaner(); - - verify(queue, never()).clear(); - } - - @Test - public void start_deletes_orphan_report_files() { - // 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"); - - runCleaner(); - - CeTaskInputDao dataDao = dbTester.getDbClient().ceTaskInputDao(); - Optional<CeTaskInputDao.DataStream> task1Data = dataDao.selectData(dbTester.getSession(), "TASK_1"); - assertThat(task1Data).isPresent(); - task1Data.get().close(); - - assertThat(dataDao.selectData(dbTester.getSession(), "TASK_2")).isNotPresent(); - } - - private CeQueueDto insertInQueue(String taskUuid, CeQueueDto.Status status) { - 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; - } - - private void insertTaskData(String taskUuid) { - dbTester.getDbClient().ceTaskInputDao().insert(dbTester.getSession(), taskUuid, IOUtils.toInputStream("{binary}")); - dbTester.getSession().commit(); - } - - private void runCleaner() { - CeQueueCleaner cleaner = new CeQueueCleaner(dbTester.getDbClient(), serverUpgradeStatus, queue, settings.asConfig()); - cleaner.start(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/ReportSubmitterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/queue/ReportSubmitterTest.java deleted file mode 100644 index a874f2b6071..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/queue/ReportSubmitterTest.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.queue; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.Random; -import java.util.stream.IntStream; -import org.apache.commons.io.IOUtils; -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.ce.queue.CeQueue; -import org.sonar.ce.queue.CeQueueImpl; -import org.sonar.ce.queue.CeTaskSubmit; -import org.sonar.core.i18n.I18n; -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.db.component.ComponentTesting; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.OrganizationPermission; -import org.sonar.db.user.UserDto; -import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.es.TestProjectIndexers; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.favorite.FavoriteUpdater; -import org.sonar.server.permission.PermissionTemplateService; -import org.sonar.server.tester.UserSessionRule; - -import static java.lang.String.format; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Collections.emptyMap; -import static java.util.stream.IntStream.rangeClosed; -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.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.SCAN_EXECUTION; -import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; -import static org.sonar.db.component.ComponentTesting.newModuleDto; -import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; -import static org.sonar.db.permission.OrganizationPermission.SCAN; - -public class ReportSubmitterTest { - - private static final String PROJECT_KEY = "MY_PROJECT"; - private static final String PROJECT_UUID = "P1"; - private static final String PROJECT_NAME = "My Project"; - private static final String TASK_UUID = "TASK_1"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public DbTester db = DbTester.create(); - - private String defaultOrganizationKey; - private String defaultOrganizationUuid; - - private CeQueue queue = mock(CeQueueImpl.class); - private TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); - private ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService, - new FavoriteUpdater(db.getDbClient()), projectIndexers); - private BranchSupport ossEditionBranchSupport = new BranchSupport(); - - private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport); - - @Before - public void setUp() throws Exception { - defaultOrganizationKey = db.getDefaultOrganization().getKey(); - defaultOrganizationUuid = db.getDefaultOrganization().getUuid(); - } - - @Test - public void submit_with_characteristics_fails_with_ISE_when_no_branch_support_delegate() { - userSession - .addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) - .addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); - mockSuccessfulPrepareSubmitCall(); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY))) - .thenReturn(true); - Map<String, String> nonEmptyCharacteristics = IntStream.range(0, 1 + new Random().nextInt(5)) - .boxed() - .collect(uniqueIndex(i -> randomAlphabetic(i + 10), i -> randomAlphabetic(i + 20))); - InputStream reportInput = IOUtils.toInputStream("{binary}", UTF_8); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Current edition does not support branch feature"); - - underTest.submit(defaultOrganizationKey, PROJECT_KEY, PROJECT_NAME, nonEmptyCharacteristics, reportInput); - } - - @Test - public void submit_stores_report() { - userSession - .addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) - .addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); - mockSuccessfulPrepareSubmitCall(); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY))) - .thenReturn(true); - - underTest.submit(defaultOrganizationKey, PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); - - verifyReportIsPersisted(TASK_UUID); - } - - @Test - public void submit_a_report_on_existing_project() { - ComponentDto project = db.components().insertPrivateProject(db.getDefaultOrganization()); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); - mockSuccessfulPrepareSubmitCall(); - - underTest.submit(defaultOrganizationKey, project.getDbKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8)); - - verifyReportIsPersisted(TASK_UUID); - verifyZeroInteractions(permissionTemplateService); - verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) - && submit.getComponent().filter(cpt -> cpt.getUuid().equals(project.uuid()) && cpt.getMainComponentUuid().equals(project.uuid())).isPresent() - && submit.getSubmitterUuid().equals(user.getUuid()) - && submit.getUuid().equals(TASK_UUID))); - } - - @Test - public void provision_project_if_does_not_exist() { - OrganizationDto organization = db.organizations().insert(); - userSession - .addPermission(OrganizationPermission.SCAN, organization.getUuid()) - .addPermission(PROVISION_PROJECTS, organization); - mockSuccessfulPrepareSubmitCall(); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY))).thenReturn(true); - when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - - underTest.submit(organization.getKey(), PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); - verifyReportIsPersisted(TASK_UUID); - verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) - && submit.getComponent().filter(cpt -> cpt.getUuid().equals(createdProject.uuid()) && cpt.getMainComponentUuid().equals(createdProject.uuid())).isPresent() - && submit.getUuid().equals(TASK_UUID))); - } - - @Test - public void add_project_as_favorite_when_project_creator_permission_on_permission_template() { - UserDto user = db.users().insertUser(); - OrganizationDto organization = db.organizations().insert(); - userSession - .logIn(user) - .addPermission(OrganizationPermission.SCAN, organization.getUuid()) - .addPermission(PROVISION_PROJECTS, organization); - mockSuccessfulPrepareSubmitCall(); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY))).thenReturn(true); - when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - - underTest.submit(organization.getKey(), PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); - assertThat(db.favorites().hasFavorite(createdProject, user.getId())).isTrue(); - } - - @Test - public void do_no_add_favorite_when_no_project_creator_permission_on_permission_template() { - userSession - .addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) - .addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY))) - .thenReturn(true); - when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(false); - mockSuccessfulPrepareSubmitCall(); - - underTest.submit(defaultOrganizationKey, PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); - assertThat(db.favorites().hasNoFavorite(createdProject)).isTrue(); - } - - @Test - public void do_no_add_favorite_when_already_100_favorite_projects_and_no_project_creator_permission_on_permission_template() { - UserDto user = db.users().insertUser(); - rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject(), user.getId())); - OrganizationDto organization = db.organizations().insert(); - userSession - .logIn(user) - .addPermission(OrganizationPermission.SCAN, organization.getUuid()) - .addPermission(PROVISION_PROJECTS, organization); - mockSuccessfulPrepareSubmitCall(); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY))).thenReturn(true); - when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - - underTest.submit(organization.getKey(), PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); - assertThat(db.favorites().hasNoFavorite(createdProject)).isTrue(); - } - - @Test - public void submit_a_report_on_new_project_with_scan_permission_on_organization() { - userSession - .addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) - .addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); - mockSuccessfulPrepareSubmitCall(); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY))) - .thenReturn(true); - - underTest.submit(defaultOrganizationKey, PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - - verify(queue).submit(any(CeTaskSubmit.class)); - } - - @Test - public void user_with_scan_permission_on_organization_is_allowed_to_submit_a_report_on_existing_project() { - OrganizationDto org = db.organizations().insert(); - ComponentDto project = db.components().insertPrivateProject(org); - userSession.addPermission(SCAN, org); - mockSuccessfulPrepareSubmitCall(); - - underTest.submit(org.getKey(), project.getDbKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); - - verify(queue).submit(any(CeTaskSubmit.class)); - } - - @Test - public void submit_a_report_on_existing_project_with_project_scan_permission() { - ComponentDto project = db.components().insertPrivateProject(db.getDefaultOrganization()); - userSession.addProjectPermission(SCAN_EXECUTION, project); - mockSuccessfulPrepareSubmitCall(); - - underTest.submit(defaultOrganizationKey, project.getDbKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); - - verify(queue).submit(any(CeTaskSubmit.class)); - } - - @Test - public void fail_with_NotFoundException_if_organization_with_specified_key_does_not_exist() { - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Organization with key 'fop' does not exist"); - - underTest.submit("fop", PROJECT_KEY, null, emptyMap(), null /* method will fail before parameter is used */); - } - - @Test - public void fail_with_organizationKey_does_not_match_organization_of_specified_component() { - userSession.logIn().setRoot(); - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertPrivateProject(organization); - mockSuccessfulPrepareSubmitCall(); - - underTest.submit(organization.getKey(), project.getDbKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); - } - - @Test - public void fail_if_component_is_not_a_project() { - ComponentDto component = db.components().insertPublicPortfolio(db.getDefaultOrganization()); - userSession.logIn().addProjectPermission(SCAN_EXECUTION, component); - mockSuccessfulPrepareSubmitCall(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Component '%s' is not a project", component.getKey())); - - underTest.submit(defaultOrganizationKey, component.getDbKey(), component.name(), emptyMap(), IOUtils.toInputStream("{binary}")); - } - - @Test - public void fail_if_project_key_already_exists_as_module() { - ComponentDto project = db.components().insertPrivateProject(db.getDefaultOrganization()); - ComponentDto module = db.components().insertComponent(newModuleDto(project)); - userSession.logIn().addProjectPermission(SCAN_EXECUTION, project); - mockSuccessfulPrepareSubmitCall(); - - try { - underTest.submit(defaultOrganizationKey, module.getDbKey(), module.name(), emptyMap(), IOUtils.toInputStream("{binary}")); - fail(); - } catch (BadRequestException e) { - assertThat(e.errors()).contains( - format("The project '%s' is already defined in SonarQube but as a module of project '%s'. " + - "If you really want to stop directly analysing project '%s', please first delete it from SonarQube and then relaunch the analysis of project '%s'.", - module.getKey(), project.getKey(), project.getKey(), module.getKey())); - } - } - - @Test - public void fail_with_forbidden_exception_when_no_scan_permission() { - expectedException.expect(ForbiddenException.class); - - underTest.submit(defaultOrganizationKey, PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - } - - @Test - public void fail_with_forbidden_exception_on_new_project_when_only_project_scan_permission() { - ComponentDto component = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID); - userSession.addProjectPermission(SCAN_EXECUTION, component); - mockSuccessfulPrepareSubmitCall(); - - expectedException.expect(ForbiddenException.class); - underTest.submit(defaultOrganizationKey, PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - } - - private void verifyReportIsPersisted(String taskUuid) { - assertThat(db.selectFirst("select task_uuid from ce_task_input where task_uuid='" + taskUuid + "'")).isNotNull(); - } - - private void mockSuccessfulPrepareSubmitCall() { - when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID)); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java deleted file mode 100644 index 744cf1847d6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.utils.System2; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.component.SnapshotDto; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.webhook.WebhookDto; -import org.sonar.server.es.TestProjectIndexers; - -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION; - -public class ComponentCleanerServiceTest { - - private System2 system2 = System2.INSTANCE; - - @Rule - public DbTester db = DbTester.create(system2); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private DbClient dbClient = db.getDbClient(); - private DbSession dbSession = db.getSession(); - private TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private ResourceTypes mockResourceTypes = mock(ResourceTypes.class); - private ComponentCleanerService underTest = new ComponentCleanerService(dbClient, mockResourceTypes, projectIndexers); - - @Test - public void delete_project_from_db_and_index() { - DbData data1 = insertData(); - DbData data2 = insertData(); - - underTest.delete(dbSession, data1.project); - - assertNotExists(data1); - assertExists(data2); - } - - @Test - public void delete_list_of_projects_from_db_and_index() { - DbData data1 = insertData(); - DbData data2 = insertData(); - DbData data3 = insertData(); - - underTest.delete(dbSession, asList(data1.project, data2.project)); - dbSession.commit(); - - assertNotExists(data1); - assertNotExists(data2); - assertExists(data3); - } - - @Test - public void delete_branch() { - DbData data1 = insertData(); - DbData data2 = insertData(); - DbData data3 = insertData(); - - underTest.deleteBranch(dbSession, data1.project); - dbSession.commit(); - - assertNotExists(data1); - assertExists(data2); - assertExists(data3); - } - - @Test - public void delete_webhooks_from_projects() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project1 = db.components().insertPrivateProject(organization); - WebhookDto webhook1 = db.webhooks().insertWebhook(project1); - db.webhookDelivery().insert(webhook1); - ComponentDto project2 = db.components().insertPrivateProject(organization); - WebhookDto webhook2 = db.webhooks().insertWebhook(project2); - db.webhookDelivery().insert(webhook2); - ComponentDto projectNotToBeDeleted = db.components().insertPrivateProject(organization); - WebhookDto webhook3 = db.webhooks().insertWebhook(projectNotToBeDeleted); - db.webhookDelivery().insert(webhook3); - mockResourceTypeAsValidProject(); - - underTest.delete(dbSession, asList(project1, project2)); - - assertThat(db.countRowsOfTable(db.getSession(), "webhooks")).isEqualTo(1); - assertThat(db.countRowsOfTable(db.getSession(), "webhook_deliveries")).isEqualTo(1); - } - - @Test - public void fail_with_IAE_if_not_a_project() { - mockResourceTypeAsValidProject(); - ComponentDto project = ComponentTesting.newPrivateProjectDto(db.organizations().insert()); - dbClient.componentDao().insert(dbSession, project); - ComponentDto file = newFileDto(project, null); - dbClient.componentDao().insert(dbSession, file); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - underTest.delete(dbSession, file); - } - - @Test - public void fail_to_delete_not_deletable_resource_type() { - ResourceType resourceType = mock(ResourceType.class); - when(resourceType.getBooleanProperty("deletable")).thenReturn(false); - when(mockResourceTypes.get(anyString())).thenReturn(resourceType); - ComponentDto project = ComponentTesting.newPrivateProjectDto(db.organizations().insert()); - dbClient.componentDao().insert(dbSession, project); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - underTest.delete(dbSession, project); - } - - @Test - public void fail_to_delete_null_resource_type() { - when(mockResourceTypes.get(anyString())).thenReturn(null); - ComponentDto project = ComponentTesting.newPrivateProjectDto(db.organizations().insert()); - dbClient.componentDao().insert(dbSession, project); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - underTest.delete(dbSession, project); - } - - @Test - public void fail_to_delete_project_when_branch() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project); - - expectedException.expect(IllegalArgumentException.class); - - underTest.delete(dbSession, branch); - } - - private DbData insertData() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertPrivateProject(organization); - RuleDefinitionDto rule = db.rules().insert(); - IssueDto issue = db.issues().insert(rule, project, project); - SnapshotDto analysis = db.components().insertSnapshot(project); - mockResourceTypeAsValidProject(); - return new DbData(project, analysis, issue); - } - - private void mockResourceTypeAsValidProject() { - ResourceType resourceType = mock(ResourceType.class); - when(resourceType.getBooleanProperty(anyString())).thenReturn(true); - when(mockResourceTypes.get(anyString())).thenReturn(resourceType); - } - - private void assertNotExists(DbData data) { - assertDataInDb(data, false); - - assertThat(projectIndexers.hasBeenCalled(data.project.uuid(), PROJECT_DELETION)).isTrue(); - } - - private void assertExists(DbData data) { - assertDataInDb(data, true); - assertThat(projectIndexers.hasBeenCalled(data.project.uuid(), PROJECT_DELETION)).isFalse(); - } - - private void assertDataInDb(DbData data, boolean exists) { - assertThat(dbClient.componentDao().selectByUuid(dbSession, data.project.uuid()).isPresent()).isEqualTo(exists); - assertThat(dbClient.snapshotDao().selectByUuid(dbSession, data.snapshot.getUuid()).isPresent()).isEqualTo(exists); - assertThat(dbClient.issueDao().selectByKey(dbSession, data.issue.getKey()).isPresent()).isEqualTo(exists); - } - - private static class DbData { - final ComponentDto project; - final SnapshotDto snapshot; - final IssueDto issue; - - DbData(ComponentDto project, SnapshotDto snapshot, IssueDto issue) { - this.project = project; - this.snapshot = snapshot; - this.issue = issue; - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentFinderTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentFinderTest.java deleted file mode 100644 index dfcae499d22..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentFinderTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.exceptions.NotFoundException; - -import static java.lang.String.format; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.db.component.BranchType.PULL_REQUEST; -import static org.sonar.db.component.ComponentTesting.newDirectory; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.component.ComponentTesting.newModuleDto; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; -import static org.sonar.server.component.ComponentFinder.ParamNames.ID_AND_KEY; - -public class ComponentFinderTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - private final DbSession dbSession = db.getSession(); - private ComponentFinder underTest = TestComponentFinder.from(db); - - @Test - public void fail_when_the_uuid_and_key_are_null() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Either 'id' or 'key' must be provided"); - - underTest.getByUuidOrKey(dbSession, null, null, ID_AND_KEY); - } - - @Test - public void fail_when_the_uuid_and_key_are_provided() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Either 'id' or 'key' must be provided"); - - underTest.getByUuidOrKey(dbSession, "project-uuid", "project-key", ID_AND_KEY); - } - - @Test - public void fail_when_the_uuid_is_empty() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The 'id' parameter must not be empty"); - - underTest.getByUuidOrKey(dbSession, "", null, ID_AND_KEY); - } - - @Test - public void fail_when_the_key_is_empty() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The 'key' parameter must not be empty"); - - underTest.getByUuidOrKey(dbSession, null, "", ID_AND_KEY); - } - - @Test - public void fail_when_component_uuid_not_found() { - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Component id 'project-uuid' not found"); - - underTest.getByUuidOrKey(dbSession, "project-uuid", null, ID_AND_KEY); - } - - @Test - public void fail_when_component_key_not_found() { - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Component key 'project-key' not found"); - - underTest.getByUuidOrKey(dbSession, null, "project-key", ID_AND_KEY); - } - - @Test - public void fail_to_getByUuidOrKey_when_using_branch_uuid() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Component id '%s' not found", branch.uuid())); - - underTest.getByUuidOrKey(dbSession, branch.uuid(), null, ID_AND_KEY); - } - - @Test - public void fail_to_getByUuidOrKey_when_using_branch_key() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey())); - - underTest.getByUuidOrKey(dbSession, null, branch.getDbKey(), ID_AND_KEY); - } - - @Test - public void fail_when_component_uuid_is_removed() { - ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization())); - db.components().insertComponent(newFileDto(project, null, "file-uuid").setEnabled(false)); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Component id 'file-uuid' not found"); - - underTest.getByUuid(dbSession, "file-uuid"); - } - - @Test - public void fail_to_getByUuid_on_branch() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Component id '%s' not found", branch.uuid())); - - underTest.getByUuid(dbSession, branch.uuid()); - } - - @Test - public void fail_when_component_key_is_removed() { - ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization())); - db.components().insertComponent(newFileDto(project).setDbKey("file-key").setEnabled(false)); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Component key 'file-key' not found"); - - underTest.getByKey(dbSession, "file-key"); - } - - @Test - public void fail_getByKey_on_branch() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey())); - - underTest.getByKey(dbSession, branch.getDbKey()); - } - - @Test - public void get_component_by_uuid() { - db.components().insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid")); - - ComponentDto component = underTest.getByUuidOrKey(dbSession, "project-uuid", null, ID_AND_KEY); - - assertThat(component.uuid()).isEqualTo("project-uuid"); - } - - @Test - public void get_component_by_key() { - db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("project-key")); - - ComponentDto component = underTest.getByUuidOrKey(dbSession, null, "project-key", ID_AND_KEY); - - assertThat(component.getDbKey()).isEqualTo("project-key"); - } - - @Test - public void get_by_key_and_branch() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); - ComponentDto module = db.components().insertComponent(newModuleDto(branch)); - ComponentDto directory = db.components().insertComponent(newDirectory(module, "scr")); - ComponentDto file = db.components().insertComponent(newFileDto(module)); - - assertThat(underTest.getByKeyAndBranch(dbSession, project.getKey(), "my_branch").uuid()).isEqualTo(branch.uuid()); - assertThat(underTest.getByKeyAndBranch(dbSession, module.getKey(), "my_branch").uuid()).isEqualTo(module.uuid()); - assertThat(underTest.getByKeyAndBranch(dbSession, file.getKey(), "my_branch").uuid()).isEqualTo(file.uuid()); - assertThat(underTest.getByKeyAndBranch(dbSession, directory.getKey(), "my_branch").uuid()).isEqualTo(directory.uuid()); - } - - @Test - public void get_by_key_and_pull_request() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST).setMergeBranchUuid(project.uuid())); - ComponentDto module = db.components().insertComponent(newModuleDto(branch)); - ComponentDto directory = db.components().insertComponent(newDirectory(module, "scr")); - ComponentDto file = db.components().insertComponent(newFileDto(module)); - - assertThat(underTest.getByKeyAndOptionalBranchOrPullRequest(dbSession, project.getKey(), null, "pr-123").uuid()).isEqualTo(branch.uuid()); - assertThat(underTest.getByKeyAndOptionalBranchOrPullRequest(dbSession, module.getKey(), null, "pr-123").uuid()).isEqualTo(module.uuid()); - assertThat(underTest.getByKeyAndOptionalBranchOrPullRequest(dbSession, file.getKey(), null, "pr-123").uuid()).isEqualTo(file.uuid()); - assertThat(underTest.getByKeyAndOptionalBranchOrPullRequest(dbSession, directory.getKey(), null, "pr-123").uuid()).isEqualTo(directory.uuid()); - } - - @Test - public void fail_when_pull_request_branch_provided() { - ComponentDto project = db.components().insertMainBranch(); - ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST)); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Either branch or pull request can be provided, not both"); - - assertThat(underTest.getByKeyAndOptionalBranchOrPullRequest(dbSession, project.getKey(), "pr-123", "pr-123").uuid()).isEqualTo(pullRequest.uuid()); - } - - @Test - public void get_by_key_and_branch_accept_main_branch() { - ComponentDto project = db.components().insertMainBranch(); - - assertThat(underTest.getByKeyAndBranch(dbSession, project.getKey(), "master").uuid()).isEqualTo(project.uuid()); - } - - @Test - public void fail_to_get_by_key_and_branch_when_branch_does_not_exist() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); - ComponentDto file = db.components().insertComponent(newFileDto(branch)); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Component '%s' on branch 'other_branch' not found", file.getKey())); - - underTest.getByKeyAndBranch(dbSession, file.getKey(), "other_branch"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java deleted file mode 100644 index 4f330773992..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.System2; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.server.es.TestProjectIndexers; -import org.sonar.server.project.ProjectLifeCycleListeners; -import org.sonar.server.tester.UserSessionRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.component.ComponentTesting.newModuleDto; - -public class ComponentServiceTest { - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - private ComponentDbTester componentDb = new ComponentDbTester(dbTester); - private DbClient dbClient = dbTester.getDbClient(); - private DbSession dbSession = dbTester.getSession(); - private TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); - - private ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexers, projectLifeCycleListeners); - - @Test - public void bulk_update() { - ComponentDto project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()).setDbKey("my_project")); - ComponentDto module = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:module")); - ComponentDto inactiveModule = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:inactive_module").setEnabled(false)); - ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); - ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false)); - - underTest.bulkUpdateKey(dbSession, project, "my_", "your_"); - - assertComponentKeyUpdated(project.getDbKey(), "your_project"); - assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); - assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); - assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module"); - assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo"); - } - - private void assertComponentKeyUpdated(String oldKey, String newKey) { - assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty(); - assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java deleted file mode 100644 index 66583ddfbf2..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import com.google.common.collect.ImmutableSet; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.System2; -import org.sonar.api.web.UserRole; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.TestProjectIndexers; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.project.Project; -import org.sonar.server.project.ProjectLifeCycleListeners; -import org.sonar.server.project.RekeyedProject; -import org.sonar.server.tester.UserSessionRule; - -import static java.util.Collections.emptyList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.component.ComponentTesting.newModuleDto; - -public class ComponentServiceUpdateKeyTest { - - private System2 system2 = System2.INSTANCE; - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(system2); - - private ComponentDbTester componentDb = new ComponentDbTester(db); - private DbClient dbClient = db.getDbClient(); - private DbSession dbSession = db.getSession(); - private TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); - private ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexers, projectLifeCycleListeners); - - @Test - public void update_project_key() { - ComponentDto project = insertSampleRootProject(); - ComponentDto file = componentDb.insertComponent(ComponentTesting.newFileDto(project, null).setDbKey("sample:root:src/File.xoo")); - ComponentDto inactiveFile = componentDb.insertComponent(ComponentTesting.newFileDto(project, null).setDbKey("sample:root:src/InactiveFile.xoo").setEnabled(false)); - - dbSession.commit(); - - logInAsProjectAdministrator(project); - underTest.updateKey(dbSession, project, "sample2:root"); - dbSession.commit(); - - // Check project key has been updated - assertThat(db.getDbClient().componentDao().selectByKey(dbSession, project.getDbKey())).isEmpty(); - assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root")).isNotNull(); - - // Check file key has been updated - assertThat(db.getDbClient().componentDao().selectByKey(dbSession, file.getDbKey())).isEmpty(); - assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root:src/File.xoo")).isNotNull(); - assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root:src/InactiveFile.xoo")).isNotNull(); - - assertThat(dbClient.componentDao().selectByKey(dbSession, inactiveFile.getDbKey())).isEmpty(); - - assertThat(projectIndexers.hasBeenCalled(project.uuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue(); - } - - @Test - public void update_module_key() { - ComponentDto project = insertSampleRootProject(); - ComponentDto module = ComponentTesting.newModuleDto(project).setDbKey("sample:root:module"); - db.components().insertComponent(module); - ComponentDto file = ComponentTesting.newFileDto(module, null).setDbKey("sample:root:module:src/File.xoo"); - db.components().insertComponent(file); - logInAsProjectAdministrator(project); - - underTest.updateKey(dbSession, module, "sample:root2:module"); - dbSession.commit(); - - assertThat(dbClient.componentDao().selectByKey(dbSession, project.getDbKey())).isPresent(); - assertComponentKeyHasBeenUpdated(module.getDbKey(), "sample:root2:module"); - assertComponentKeyHasBeenUpdated(file.getDbKey(), "sample:root2:module:src/File.xoo"); - - // do not index the module but the project - assertThat(projectIndexers.hasBeenCalled(project.uuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue(); - } - - @Test - public void update_provisioned_project_key() { - ComponentDto provisionedProject = insertProject("provisionedProject"); - - dbSession.commit(); - - logInAsProjectAdministrator(provisionedProject); - underTest.updateKey(dbSession, provisionedProject, "provisionedProject2"); - dbSession.commit(); - - assertComponentKeyHasBeenUpdated(provisionedProject.getDbKey(), "provisionedProject2"); - assertThat(projectIndexers.hasBeenCalled(provisionedProject.uuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue(); - } - - @Test - public void fail_to_update_project_key_without_admin_permission() { - expectedException.expect(ForbiddenException.class); - - ComponentDto project = insertSampleRootProject(); - userSession.logIn("john").addProjectPermission(UserRole.USER, project); - - underTest.updateKey(dbSession, project, "sample2:root"); - } - - @Test - public void fail_if_old_key_and_new_key_are_the_same() { - ComponentDto project = insertSampleRootProject(); - ComponentDto anotherProject = componentDb.insertPrivateProject(); - logInAsProjectAdministrator(project); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Impossible to update key: a component with key \"" + anotherProject.getDbKey() + "\" already exists."); - - underTest.updateKey(dbSession, project, anotherProject.getDbKey()); - } - - @Test - public void fail_if_new_key_is_empty() { - ComponentDto project = insertSampleRootProject(); - logInAsProjectAdministrator(project); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for ''. It cannot be empty nor contain whitespaces."); - - underTest.updateKey(dbSession, project, ""); - } - - @Test - public void fail_if_new_key_is_invalid() { - ComponentDto project = insertSampleRootProject(); - logInAsProjectAdministrator(project); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for 'sample root'. It cannot be empty nor contain whitespaces."); - - underTest.updateKey(dbSession, project, "sample root"); - } - - @Test - public void fail_if_update_is_not_on_module_or_project() { - ComponentDto project = insertSampleRootProject(); - ComponentDto file = componentDb.insertComponent(newFileDto(project, null)); - logInAsProjectAdministrator(project); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Component updated must be a module or a key"); - - underTest.updateKey(dbSession, file, "file:key"); - } - - @Test - public void bulk_update_key() { - ComponentDto project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("my_project")); - ComponentDto module = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:module")); - ComponentDto inactiveModule = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:inactive_module").setEnabled(false)); - ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); - ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false)); - - underTest.bulkUpdateKey(dbSession, project, "my_", "your_"); - - assertComponentKeyUpdated(project.getDbKey(), "your_project"); - assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); - assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); - assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module"); - assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo"); - verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of( - new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid(), emptyList()), "my_project") - )); - } - - @Test - public void bulk_update_key_with_branch_and_pr() { - ComponentDto project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("my_project")); - ComponentDto branch = componentDb.insertProjectBranch(project); - ComponentDto module = componentDb.insertComponent(newModuleDto(branch).setDbKey("my_project:root:module")); - ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); - - underTest.bulkUpdateKey(dbSession, project, "my_", "your_"); - - assertComponentKeyUpdated(project.getDbKey(), "your_project"); - assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); - assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); - verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of( - new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid(), emptyList()), "my_project") - )); - } - - private void assertComponentKeyUpdated(String oldKey, String newKey) { - assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty(); - assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent(); - } - - private ComponentDto insertSampleRootProject() { - return insertProject("sample:root"); - } - - private ComponentDto insertProject(String key) { - ComponentDto project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey(key)); - return project; - } - - private void assertComponentKeyHasBeenUpdated(String oldKey, String newKey) { - assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty(); - assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent(); - } - - private void logInAsProjectAdministrator(ComponentDto provisionedProject) { - userSession.logIn("john").addProjectPermission(UserRole.ADMIN, provisionedProject); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java deleted file mode 100644 index c8edc8156fa..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import java.util.Optional; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.TestProjectIndexers; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.favorite.FavoriteUpdater; -import org.sonar.server.l18n.I18nRule; -import org.sonar.server.permission.PermissionTemplateService; - -import static java.util.stream.IntStream.rangeClosed; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.api.resources.Qualifiers.APP; -import static org.sonar.api.resources.Qualifiers.VIEW; - -public class ComponentUpdaterTest { - - private static final String DEFAULT_PROJECT_KEY = "project-key"; - private static final String DEFAULT_PROJECT_NAME = "project-name"; - - private System2 system2 = System2.INSTANCE; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(system2); - @Rule - public I18nRule i18n = new I18nRule().put("qualifier.TRK", "Project"); - - private TestProjectIndexers projectIndexers = new TestProjectIndexers(); - private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); - - private ComponentUpdater underTest = new ComponentUpdater(db.getDbClient(), i18n, system2, - permissionTemplateService, - new FavoriteUpdater(db.getDbClient()), - projectIndexers); - - @Test - public void persist_and_index_when_creating_project() { - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .setPrivate(true) - .build(); - ComponentDto returned = underTest.create(db.getSession(), project, null); - - ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.uuid()); - assertThat(loaded.getDbKey()).isEqualTo(DEFAULT_PROJECT_KEY); - assertThat(loaded.name()).isEqualTo(DEFAULT_PROJECT_NAME); - assertThat(loaded.longName()).isEqualTo(DEFAULT_PROJECT_NAME); - assertThat(loaded.qualifier()).isEqualTo(Qualifiers.PROJECT); - assertThat(loaded.scope()).isEqualTo(Scopes.PROJECT); - assertThat(loaded.getOrganizationUuid()).isEqualTo(db.getDefaultOrganization().getUuid()); - assertThat(loaded.uuid()).isNotNull(); - assertThat(loaded.projectUuid()).isEqualTo(loaded.uuid()); - assertThat(loaded.moduleUuid()).isNull(); - assertThat(loaded.moduleUuidPath()).isEqualTo("." + loaded.uuid() + "."); - assertThat(loaded.isPrivate()).isEqualTo(project.isPrivate()); - assertThat(loaded.getCreatedAt()).isNotNull(); - assertThat(db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY)).isNotNull(); - - assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); - - Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); - assertThat(branch).isPresent(); - assertThat(branch.get().getKey()).isEqualTo(BranchDto.DEFAULT_MAIN_BRANCH_NAME); - assertThat(branch.get().getMergeBranchUuid()).isNull(); - assertThat(branch.get().getBranchType()).isEqualTo(BranchType.LONG); - assertThat(branch.get().getUuid()).isEqualTo(returned.uuid()); - assertThat(branch.get().getProjectUuid()).isEqualTo(returned.uuid()); - } - - @Test - public void persist_private_flag_true_when_creating_project() { - OrganizationDto organization = db.organizations().insert(); - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(organization.getUuid()) - .setPrivate(true) - .build(); - ComponentDto returned = underTest.create(db.getSession(), project, null); - ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.uuid()); - assertThat(loaded.isPrivate()).isEqualTo(project.isPrivate()); - } - - @Test - public void persist_private_flag_false_when_creating_project() { - OrganizationDto organization = db.organizations().insert(); - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(organization.getUuid()) - .setPrivate(false) - .build(); - ComponentDto returned = underTest.create(db.getSession(), project, null); - ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.uuid()); - assertThat(loaded.isPrivate()).isEqualTo(project.isPrivate()); - } - - @Test - public void create_view() { - NewComponent view = NewComponent.newComponentBuilder() - .setKey("view-key") - .setName("view-name") - .setQualifier(VIEW) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(); - - ComponentDto returned = underTest.create(db.getSession(), view, null); - - ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.uuid()); - assertThat(loaded.getDbKey()).isEqualTo("view-key"); - assertThat(loaded.name()).isEqualTo("view-name"); - assertThat(loaded.qualifier()).isEqualTo("VW"); - assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); - Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); - assertThat(branch).isNotPresent(); - } - - @Test - public void create_application() { - NewComponent application = NewComponent.newComponentBuilder() - .setKey("app-key") - .setName("app-name") - .setQualifier(APP) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(); - - ComponentDto returned = underTest.create(db.getSession(), application, null); - - ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.uuid()); - assertThat(loaded.getDbKey()).isEqualTo("app-key"); - assertThat(loaded.name()).isEqualTo("app-name"); - assertThat(loaded.qualifier()).isEqualTo("APP"); - assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); - Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); - assertThat(branch).isPresent(); - assertThat(branch.get().getKey()).isEqualTo(BranchDto.DEFAULT_MAIN_BRANCH_NAME); - assertThat(branch.get().getMergeBranchUuid()).isNull(); - assertThat(branch.get().getBranchType()).isEqualTo(BranchType.LONG); - assertThat(branch.get().getUuid()).isEqualTo(returned.uuid()); - assertThat(branch.get().getProjectUuid()).isEqualTo(returned.uuid()); - } - - @Test - public void apply_default_permission_template() { - int userId = 42; - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(); - ComponentDto dto = underTest.create(db.getSession(), project, userId); - - verify(permissionTemplateService).applyDefault(db.getSession(), dto, userId); - } - - @Test - public void add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template() { - UserDto userDto = db.users().insertUser(); - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(); - when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))) - .thenReturn(true); - - ComponentDto dto = underTest.create(db.getSession(), project, userDto.getId()); - - assertThat(db.favorites().hasFavorite(dto, userDto.getId())).isTrue(); - } - - @Test - public void do_not_add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template_and_already_100_favorites() { - UserDto user = db.users().insertUser(); - rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject(), user.getId())); - NewComponent project = NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(); - when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(eq(db.getSession()), any(ComponentDto.class))) - .thenReturn(true); - - ComponentDto dto = underTest.create(db.getSession(), - project, - user.getId()); - - assertThat(db.favorites().hasFavorite(dto, user.getId())).isFalse(); - } - - @Test - public void does_not_add_project_to_favorite_when_anonymously_created() { - ComponentDto project = underTest.create(db.getSession(), - NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(), - null); - - assertThat(db.favorites().hasNoFavorite(project)).isTrue(); - } - - @Test - public void does_not_add_project_to_favorite_when_project_has_no_permission_on_template() { - ComponentDto project = underTest.create(db.getSession(), - NewComponent.newComponentBuilder() - .setKey(DEFAULT_PROJECT_KEY) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(), - null); - - assertThat(db.favorites().hasNoFavorite(project)).isTrue(); - } - - @Test - public void fail_when_project_key_already_exists() { - ComponentDto existing = db.components().insertPrivateProject(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Could not create Project, key already exists: " + existing.getDbKey()); - - underTest.create(db.getSession(), - NewComponent.newComponentBuilder() - .setKey(existing.getDbKey()) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(existing.getOrganizationUuid()) - .build(), - null); - } - - @Test - public void fail_when_project_key_already_exists_on_other_organization() { - ComponentDto existing = db.components().insertPrivateProject(db.organizations().insert()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Could not create Project, key already exists: " + existing.getDbKey()); - - underTest.create(db.getSession(), - NewComponent.newComponentBuilder() - .setKey(existing.getDbKey()) - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(existing.getOrganizationUuid()) - .build(), - null); - } - - @Test - public void fail_when_key_has_bad_format() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for Project: ' '"); - - underTest.create(db.getSession(), - NewComponent.newComponentBuilder() - .setKey(" ") - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(), - null); - } - - @Test - public void properly_fail_when_key_contains_percent_character() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for Project: ' '"); - - underTest.create(db.getSession(), - NewComponent.newComponentBuilder() - .setKey(" ") - .setName(DEFAULT_PROJECT_NAME) - .setOrganizationUuid(db.getDefaultOrganization().getUuid()) - .build(), - null); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/NewComponentTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/NewComponentTest.java deleted file mode 100644 index 10b8505dedb..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/NewComponentTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static com.google.common.base.Strings.repeat; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.server.component.NewComponent.newComponentBuilder; - -public class NewComponentTest { - private static final String ORGANIZATION_UUID = "org1"; - private static final String KEY = "key"; - private static final String NAME = "name"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private NewComponent.Builder underTest = newComponentBuilder(); - - @Test - public void build_throws_NPE_if_organizationUuid_is_null() { - expectBuildException(NullPointerException.class, "organization uuid can't be null"); - } - - @Test - public void build_throws_IAE_when_key_is_null() { - underTest.setOrganizationUuid(ORGANIZATION_UUID); - - expectBuildException(IllegalArgumentException.class, "Component key can't be empty"); - } - - @Test - public void build_throws_IAE_when_key_is_empty() { - underTest - .setKey("") - .setOrganizationUuid(ORGANIZATION_UUID); - - expectBuildException(IllegalArgumentException.class, "Component key can't be empty"); - } - - @Test - public void build_throws_IAE_when_key_is_longer_than_400_characters() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(repeat("a", 400 + 1)); - - expectBuildException( - IllegalArgumentException.class, - "Component key length (401) is longer than the maximum authorized (400)"); - } - - @Test - public void build_fails_with_IAE_when_name_is_null() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY); - - expectBuildException(IllegalArgumentException.class, "Component name can't be empty"); - } - - @Test - public void build_fails_with_IAE_when_name_is_empty() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY) - .setName(""); - - expectBuildException(IllegalArgumentException.class, "Component name can't be empty"); - } - - @Test - public void build_fails_with_IAE_when_name_is_longer_than_2000_characters() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY) - .setName(repeat("a", 501)); - - expectBuildException( - IllegalArgumentException.class, - "Component name length (501) is longer than the maximum authorized (500)"); - } - - @Test - public void build_fails_with_IAE_when_qualifier_is_null() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY) - .setName(NAME) - .setQualifier(null); - - expectBuildException(IllegalArgumentException.class, "Component qualifier can't be empty"); - } - - @Test - public void build_fails_with_IAE_when_qualifier_is_empty() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY) - .setName(NAME) - .setQualifier(""); - - expectBuildException(IllegalArgumentException.class, "Component qualifier can't be empty"); - } - - @Test - public void build_fails_with_IAE_when_qualifier_is_longer_than_10_characters() { - underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY) - .setName(NAME) - .setQualifier(repeat("a", 10 + 1)); - - expectBuildException( - IllegalArgumentException.class, - "Component qualifier length (11) is longer than the maximum authorized (10)"); - } - - @Test - public void getQualifier_returns_PROJECT_when_no_set_in_builder() { - NewComponent newComponent = underTest.setOrganizationUuid(ORGANIZATION_UUID) - .setKey(KEY) - .setName(NAME) - .build(); - - assertThat(newComponent.qualifier()).isEqualTo(PROJECT); - } - - private void expectBuildException(Class<? extends Exception> expectedExceptionType, String expectedMessage) { - expectedException.expect(expectedExceptionType); - expectedException.expectMessage(expectedMessage); - - underTest.build(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/TestComponentFinder.java b/server/sonar-server/src/test/java/org/sonar/server/component/TestComponentFinder.java deleted file mode 100644 index 2e2a9fcc787..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/component/TestComponentFinder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.component; - -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.db.DbClient; -import org.sonar.db.DbTester; -import org.sonar.db.component.ResourceTypesRule; - -public class TestComponentFinder extends ComponentFinder { - private TestComponentFinder(DbClient dbClient, ResourceTypes resourceTypes) { - super(dbClient, resourceTypes); - } - - public static TestComponentFinder from(DbTester dbTester) { - return new TestComponentFinder(dbTester.getDbClient(), new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT)); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/favorite/FavoriteModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/favorite/FavoriteModuleTest.java deleted file mode 100644 index 790c4863c17..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/favorite/FavoriteModuleTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.favorite; - -import org.junit.Test; -import org.sonar.core.platform.ComponentContainer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; - -public class FavoriteModuleTest { - @Test - public void verify_count_of_added_components() { - ComponentContainer container = new ComponentContainer(); - new FavoriteModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/AppNodeClusterCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/AppNodeClusterCheckTest.java deleted file mode 100644 index c629a4a7bf6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/AppNodeClusterCheckTest.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Arrays; -import java.util.Random; -import java.util.Set; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import org.junit.Test; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; - -import static java.util.stream.Collectors.toSet; -import static java.util.stream.Stream.of; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.sonar.process.cluster.health.NodeHealth.Status.GREEN; -import static org.sonar.process.cluster.health.NodeHealth.Status.RED; -import static org.sonar.process.cluster.health.NodeHealth.Status.YELLOW; -import static org.sonar.server.health.HealthAssert.assertThat; - -public class AppNodeClusterCheckTest { - private final Random random = new Random(); - - private AppNodeClusterCheck underTest = new AppNodeClusterCheck(); - - @Test - public void status_RED_when_no_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths().collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.RED) - .andCauses("No application node"); - } - - @Test - public void status_RED_when_single_RED_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(RED).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.RED) - .andCauses("Status of all application nodes is RED", - "There should be at least two application nodes"); - } - - @Test - public void status_YELLOW_when_single_YELLOW_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(YELLOW).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses( - "Status of all application nodes is YELLOW", - "There should be at least two application nodes"); - } - - @Test - public void status_YELLOW_when_single_GREEN_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(GREEN).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses("There should be at least two application nodes"); - } - - @Test - public void status_RED_when_two_RED_application_nodes() { - Set<NodeHealth> nodeHealths = nodeHealths(RED, RED).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.RED) - .andCauses("Status of all application nodes is RED"); - } - - @Test - public void status_YELLOW_when_two_YELLOW_application_nodes() { - Set<NodeHealth> nodeHealths = nodeHealths(YELLOW, YELLOW).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses("Status of all application nodes is YELLOW"); - } - - @Test - public void status_YELLOW_when_one_RED_node_and_one_YELLOW_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(RED, YELLOW).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses( - "At least one application node is RED", - "At least one application node is YELLOW"); - } - - @Test - public void status_YELLOW_when_one_RED_node_and_one_GREEN_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(RED, GREEN).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses("At least one application node is RED"); - } - - @Test - public void status_YELLOW_when_one_YELLOW_node_and_one_GREEN_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(YELLOW, GREEN).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses("At least one application node is YELLOW"); - } - - @Test - public void status_GREEN_when_two_GREEN_application_node() { - Set<NodeHealth> nodeHealths = nodeHealths(GREEN, GREEN).collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.GREEN) - .andCauses(); - } - - @Test - public void status_GREEN_when_two_GREEN_application_node_and_any_number_of_other_is_GREEN() { - Set<NodeHealth> nodeHealths = of( - // at least 1 extra GREEN - of(appNodeHealth(GREEN)), - // 0 to 10 GREEN - randomNumberOfAppNodeHealthOfAnyStatus(GREEN), - // 2 GREEN - nodeHealths(GREEN, GREEN)) - .flatMap(s -> s) - .collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.GREEN) - .andCauses(); - } - - @Test - public void status_YELLOW_when_two_GREEN_application_node_and_any_number_of_other_is_YELLOW_or_GREEN() { - Set<NodeHealth> nodeHealths = of( - // at least 1 YELLOW - of(appNodeHealth(YELLOW)), - // 0 to 10 YELLOW/GREEN - randomNumberOfAppNodeHealthOfAnyStatus(GREEN, YELLOW), - // 2 GREEN - nodeHealths(GREEN, GREEN)) - .flatMap(s -> s) - .collect(toSet()); - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses("At least one application node is YELLOW"); - } - - @Test - public void status_YELLOW_when_two_GREEN_application_node_and_any_number_of_other_is_RED_or_GREEN() { - Set<NodeHealth> nodeHealths = of( - // at least 1 RED - of(appNodeHealth(RED)), - // 0 to 10 RED/GREEN - randomNumberOfAppNodeHealthOfAnyStatus(GREEN, RED), - // 2 GREEN - nodeHealths(GREEN, GREEN)) - .flatMap(s -> s) - .collect(toSet()); - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses("At least one application node is RED"); - } - - @Test - public void status_YELLOW_when_two_GREEN_application_node_and_any_number_of_other_is_either_RED_or_YELLOW() { - Set<NodeHealth> nodeHealths = of( - // at least 1 RED - of(appNodeHealth(RED)), - // at least 1 YELLOW - of(appNodeHealth(YELLOW)), - // 0 to 10 RED/YELLOW/GREEN - randomNumberOfAppNodeHealthOfAnyStatus(RED, YELLOW, GREEN), - // 2 GREEN - nodeHealths(GREEN, GREEN)) - .flatMap(s -> s) - .collect(toSet()); - - Health check = underTest.check(nodeHealths); - - assertThat(check) - .forInput(nodeHealths) - .hasStatus(Health.Status.YELLOW) - .andCauses( - "At least one application node is YELLOW", - "At least one application node is RED"); - } - - /** - * Between 0 and 10 NodeHealth of Application node with any of the specified statuses. - */ - private Stream<NodeHealth> randomNumberOfAppNodeHealthOfAnyStatus(NodeHealth.Status... randomStatuses) { - return IntStream.range(0, random.nextInt(10)) - .mapToObj(i -> appNodeHealth(randomStatuses[random.nextInt(randomStatuses.length)])); - } - - private Stream<NodeHealth> nodeHealths(NodeHealth.Status... appNodeStatuses) { - return of( - // random number of Search nodes with random status - IntStream.range(0, random.nextInt(3)) - .mapToObj(i -> appNodeHealth(NodeDetails.Type.SEARCH, NodeHealth.Status.values()[random.nextInt(NodeHealth.Status.values().length)])), - Arrays.stream(appNodeStatuses).map(this::appNodeHealth)) - .flatMap(s -> s); - } - - private NodeHealth appNodeHealth(NodeHealth.Status status) { - return appNodeHealth(NodeDetails.Type.APPLICATION, status); - } - - private NodeHealth appNodeHealth(NodeDetails.Type type, NodeHealth.Status status) { - return NodeHealth.newNodeHealthBuilder() - .setStatus(status) - .setDetails(NodeDetails.newNodeDetailsBuilder() - .setType(type) - .setHost(randomAlphanumeric(32)) - .setName(randomAlphanumeric(32)) - .setPort(1 + random.nextInt(88)) - .setStartedAt(1 + random.nextInt(54)) - .build()) - .build(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/CeStatusNodeCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/CeStatusNodeCheckTest.java deleted file mode 100644 index 82e315e19ec..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/CeStatusNodeCheckTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.junit.Test; -import org.sonar.server.app.ProcessCommandWrapper; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class CeStatusNodeCheckTest { - private ProcessCommandWrapper processCommandWrapper = mock(ProcessCommandWrapper.class); - private CeStatusNodeCheck underTest = new CeStatusNodeCheck(processCommandWrapper); - - @Test - public void check_returns_GREEN_status_without_cause_if_ce_is_operational() { - when(processCommandWrapper.isCeOperational()).thenReturn(true); - - Health health = underTest.check(); - - assertThat(health).isEqualTo(Health.GREEN); - } - - @Test - public void check_returns_RED_status_with_cause_if_ce_is_not_operational() { - when(processCommandWrapper.isCeOperational()).thenReturn(false); - - Health health = underTest.check(); - - assertThat(health.getStatus()).isEqualTo(Health.Status.RED); - assertThat(health.getCauses()).containsOnly("Compute Engine is not operational"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java deleted file mode 100644 index 1265cf8e218..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; - -import static java.util.stream.Collectors.toSet; -import static java.util.stream.Stream.concat; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.process.cluster.health.NodeHealth.newNodeHealthBuilder; -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -public class ClusterHealthTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private final Random random = new Random(); - - @Test - public void constructor_fails_with_NPE_if_Health_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("health can't be null"); - - new ClusterHealth(null, Collections.emptySet()); - } - - @Test - public void constructor_fails_with_NPE_if_NodeHealth_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("nodes can't be null"); - - new ClusterHealth(Health.GREEN, null); - } - - @Test - public void verify_getters() { - Health health = randomHealth(); - Set<NodeHealth> nodeHealths = randomNodeHealths(); - ClusterHealth underTest = new ClusterHealth(health, nodeHealths); - - assertThat(underTest.getHealth()).isSameAs(health); - assertThat(underTest.getNodes()).isEqualTo(nodeHealths); - } - - @Test - public void equals_is_based_on_content() { - Health health = randomHealth(); - Set<NodeHealth> nodeHealths = randomNodeHealths(); - ClusterHealth underTest = new ClusterHealth(health, nodeHealths); - - assertThat(underTest) - .isEqualTo(underTest) - .isEqualTo(new ClusterHealth(health, nodeHealths)) - .isNotEqualTo(new Object()) - .isNotEqualTo(null) - .isNotEqualTo(new ClusterHealth( - newHealthCheckBuilder() - .setStatus(health.getStatus()) - .addCause("foo_bar") - .build(), - randomNodeHealths())) - .isNotEqualTo(new ClusterHealth( - health, - concat(nodeHealths.stream(), Stream.of(randomNodeHealth())).collect(toSet()))); - } - - @Test - public void hashcode_is_based_on_content() { - Health health = randomHealth(); - Set<NodeHealth> nodeHealths = randomNodeHealths(); - ClusterHealth underTest = new ClusterHealth(health, nodeHealths); - - assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode()); - } - - @Test - public void verify_toString() { - Health health = randomHealth(); - Set<NodeHealth> nodeHealths = randomNodeHealths(); - - ClusterHealth underTest = new ClusterHealth(health, nodeHealths); - - assertThat(underTest.toString()).isEqualTo("ClusterHealth{health=" + health + ", nodes=" + nodeHealths + "}"); - } - - @Test - public void test_getNodeHealth() { - Health health = randomHealth(); - Set<NodeHealth> nodeHealths = new HashSet<>(Arrays.asList(newNodeHealth("foo"), newNodeHealth("bar"))); - - ClusterHealth underTest = new ClusterHealth(health, nodeHealths); - - assertThat(underTest.getNodeHealth("does_not_exist")).isEmpty(); - assertThat(underTest.getNodeHealth("bar")).isPresent(); - } - - private Health randomHealth() { - Health.Builder healthBuilder = newHealthCheckBuilder(); - healthBuilder.setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]); - IntStream.range(0, random.nextInt(3)).mapToObj(i -> randomAlphanumeric(3)).forEach(healthBuilder::addCause); - return healthBuilder.build(); - } - - private Set<NodeHealth> randomNodeHealths() { - return IntStream.range(0, random.nextInt(4)).mapToObj(i -> randomNodeHealth()).collect(toSet()); - } - - private NodeHealth randomNodeHealth() { - return newNodeHealthBuilder() - .setStatus(NodeHealth.Status.values()[random.nextInt(NodeHealth.Status.values().length)]) - .setDetails( - NodeDetails.newNodeDetailsBuilder() - .setType(random.nextBoolean() ? NodeDetails.Type.SEARCH : NodeDetails.Type.APPLICATION) - .setName(randomAlphanumeric(3)) - .setHost(randomAlphanumeric(4)) - .setPort(1 + random.nextInt(344)) - .setStartedAt(1 + random.nextInt(999)) - .build()) - .build(); - } - - private static NodeHealth newNodeHealth(String nodeName) { - return newNodeHealthBuilder() - .setStatus(NodeHealth.Status.YELLOW) - .setDetails(randomNodeDetails(nodeName)) - .build(); - } - - private static NodeDetails randomNodeDetails(String nodeName) { - return NodeDetails.newNodeDetailsBuilder() - .setType(NodeDetails.Type.APPLICATION) - .setName(nodeName) - .setHost(randomAlphanumeric(4)) - .setPort(3000) - .setStartedAt(1_000L) - .build(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/DbConnectionNodeCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/DbConnectionNodeCheckTest.java deleted file mode 100644 index 4bdc794e71a..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/DbConnectionNodeCheckTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.IsAliveMapper; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class DbConnectionNodeCheckTest { - private DbClient dbClient = mock(DbClient.class); - private DbSession dbSession = mock(DbSession.class); - private IsAliveMapper isAliveMapper = mock(IsAliveMapper.class); - - private DbConnectionNodeCheck underTest = new DbConnectionNodeCheck(dbClient); - - @Before - public void wireMocks() { - when(dbClient.openSession(anyBoolean())).thenReturn(dbSession); - when(dbSession.getMapper(IsAliveMapper.class)).thenReturn(isAliveMapper); - } - - @Test - public void status_is_GREEN_without_cause_if_isAlive_returns_1() { - when(isAliveMapper.isAlive()).thenReturn(1); - - Health health = underTest.check(); - - assertThat(health).isEqualTo(Health.GREEN); - } - - @Test - public void status_is_RED_with_single_cause_if_any_error_occurs_when_checking_DB() { - when(isAliveMapper.isAlive()).thenThrow(new RuntimeException("simulated runtime exception when querying DB")); - - Health health = underTest.check(); - - verifyRedStatus(health); - } - - /** - * By contract {@link IsAliveMapper#isAlive()} can not return anything but 1. Still we write this test as a - * protection against change in this contract. - */ - @Test - public void status_is_RED_with_single_cause_if_isAlive_does_not_return_1() { - when(isAliveMapper.isAlive()).thenReturn(12); - - Health health = underTest.check(); - - verifyRedStatus(health); - } - - private void verifyRedStatus(Health health) { - assertThat(health.getStatus()).isEqualTo(Health.Status.RED); - assertThat(health.getCauses()).containsOnly("Can't connect to DB"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/EsStatusClusterCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/EsStatusClusterCheckTest.java deleted file mode 100644 index f8a2c288c8b..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/EsStatusClusterCheckTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import com.google.common.collect.ImmutableSet; -import java.util.Random; -import java.util.Set; -import org.elasticsearch.cluster.health.ClusterHealthStatus; -import org.junit.Test; -import org.mockito.Mockito; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; -import org.sonar.server.es.EsClient; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.when; - -public class EsStatusClusterCheckTest { - - private EsClient esClient = Mockito.mock(EsClient.class, RETURNS_DEEP_STUBS); - private Random random = new Random(); - private EsStatusClusterCheck underTest = new EsStatusClusterCheck(esClient); - - @Test - public void check_ignores_NodeHealth_arg_and_returns_RED_with_cause_if_an_exception_occurs_checking_ES_cluster_status() { - Set<NodeHealth> nodeHealths = ImmutableSet.of(newNodeHealth(NodeHealth.Status.GREEN)); - when(esClient.prepareClusterStats()).thenThrow(new RuntimeException("Faking an exception occurring while using the EsClient")); - - Health health = new EsStatusClusterCheck(esClient).check(nodeHealths); - - assertThat(health.getStatus()).isEqualTo(Health.Status.RED); - assertThat(health.getCauses()).containsOnly("Elasticsearch status is RED (unavailable)"); - } - - @Test - public void check_ignores_NodeHealth_arg_and_returns_GREEN_without_cause_if_ES_cluster_status_is_GREEN() { - Set<NodeHealth> nodeHealths = ImmutableSet.of(newNodeHealth(NodeHealth.Status.YELLOW)); - when(esClient.prepareClusterStats().get().getStatus()).thenReturn(ClusterHealthStatus.GREEN); - - Health health = underTest.check(nodeHealths); - - assertThat(health).isEqualTo(Health.GREEN); - } - - private NodeHealth newNodeHealth(NodeHealth.Status status) { - return NodeHealth.newNodeHealthBuilder() - .setStatus(status) - .setDetails(NodeDetails.newNodeDetailsBuilder() - .setType(random.nextBoolean() ? NodeDetails.Type.APPLICATION : NodeDetails.Type.SEARCH) - .setName(randomAlphanumeric(23)) - .setHost(randomAlphanumeric(23)) - .setPort(1 + random.nextInt(96)) - .setStartedAt(1 + random.nextInt(966)) - .build()) - .build(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/EsStatusNodeCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/EsStatusNodeCheckTest.java deleted file mode 100644 index 58d9e8a1cf6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/EsStatusNodeCheckTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.elasticsearch.cluster.health.ClusterHealthStatus; -import org.junit.Test; -import org.mockito.Mockito; -import org.sonar.server.es.EsClient; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class EsStatusNodeCheckTest { - - private EsClient esClient = mock(EsClient.class, Mockito.RETURNS_DEEP_STUBS); - private EsStatusNodeCheck underTest = new EsStatusNodeCheck(esClient); - - @Test - public void check_ignores_NodeHealth_arg_and_returns_RED_with_cause_if_an_exception_occurs_checking_ES_cluster_status() { - EsClient esClient = mock(EsClient.class); - when(esClient.prepareClusterStats()).thenThrow(new RuntimeException("Faking an exception occurring while using the EsClient")); - - Health health = new EsStatusNodeCheck(esClient).check(); - - assertThat(health.getStatus()).isEqualTo(Health.Status.RED); - assertThat(health.getCauses()).containsOnly("Elasticsearch status is RED (unavailable)"); - } - - @Test - public void check_returns_GREEN_without_cause_if_ES_cluster_status_is_GREEN() { - when(esClient.prepareClusterStats().get().getStatus()).thenReturn(ClusterHealthStatus.GREEN); - - Health health = underTest.check(); - - assertThat(health).isEqualTo(Health.GREEN); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/HealthAssert.java b/server/sonar-server/src/test/java/org/sonar/server/health/HealthAssert.java deleted file mode 100644 index ec8e06598f4..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/HealthAssert.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import com.google.common.collect.ImmutableList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.assertj.core.api.AbstractAssert; -import org.sonar.process.cluster.health.NodeHealth; - -final class HealthAssert extends AbstractAssert<HealthAssert, Health> { - private Set<NodeHealth> nodeHealths; - - private HealthAssert(Health actual) { - super(actual, HealthAssert.class); - } - - public static HealthAssert assertThat(Health actual) { - return new HealthAssert(actual); - } - - public HealthAssert forInput(Set<NodeHealth> nodeHealths) { - this.nodeHealths = nodeHealths; - - return this; - } - - public HealthAssert hasStatus(Health.Status expected) { - isNotNull(); - - if (actual.getStatus() != expected) { - failWithMessage( - "Expected Status of Health to be <%s> but was <%s> for NodeHealth \n%s", - expected, - actual.getStatus(), - printStatusesAndTypes(this.nodeHealths)); - } - - return this; - } - - public HealthAssert andCauses(String... causes) { - isNotNull(); - - if (!checkCauses(causes)) { - failWithMessage( - "Expected causes of Health to contain only \n%s\n but was \n%s\n for NodeHealth \n%s", - Arrays.asList(causes), - actual.getCauses(), - printStatusesAndTypes(this.nodeHealths)); - } - - return this; - } - - private String printStatusesAndTypes(@Nullable Set<NodeHealth> nodeHealths) { - if (nodeHealths == null) { - return "<null>"; - } - return nodeHealths.stream() - // sort by type then status for debugging convenience - .sorted(Comparator.<NodeHealth>comparingInt(s1 -> s1.getDetails().getType().ordinal()) - .thenComparingInt(s -> s.getStatus().ordinal())) - .map(s -> ImmutableList.of(s.getDetails().getType().name(), s.getStatus().name())) - .map(String::valueOf) - .collect(Collectors.joining(",")); - } - - private boolean checkCauses(String... causes) { - if (causes.length != this.actual.getCauses().size()) { - return false; - } - return Objects.equals(new HashSet<>(Arrays.asList(causes)), this.actual.getCauses()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/HealthCheckerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/HealthCheckerImplTest.java deleted file mode 100644 index 84893a43792..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/HealthCheckerImplTest.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; -import org.sonar.process.cluster.health.SharedHealthState; -import org.sonar.server.platform.WebServer; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.process.cluster.health.NodeDetails.newNodeDetailsBuilder; -import static org.sonar.process.cluster.health.NodeHealth.newNodeHealthBuilder; -import static org.sonar.server.health.Health.newHealthCheckBuilder; -import static org.sonar.server.health.Health.Status.GREEN; -import static org.sonar.server.health.Health.Status.RED; -import static org.sonar.server.health.Health.Status.YELLOW; - -public class HealthCheckerImplTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private final WebServer webServer = mock(WebServer.class); - private final SharedHealthState sharedHealthState = mock(SharedHealthState.class); - private final Random random = new Random(); - - @Test - public void check_returns_green_status_without_any_cause_when_there_is_no_NodeHealthCheck() { - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0]); - - assertThat(underTest.checkNode()).isEqualTo(Health.GREEN); - } - - @Test - public void checkNode_returns_GREEN_status_if_only_GREEN_statuses_returned_by_NodeHealthCheck() { - List<Health.Status> statuses = IntStream.range(1, 1 + random.nextInt(20)).mapToObj(i -> GREEN).collect(Collectors.toList()); - HealthCheckerImpl underTest = newNodeHealthCheckerImpl(statuses.stream()); - - assertThat(underTest.checkNode().getStatus()) - .describedAs("%s should have been computed from %s statuses", GREEN, statuses) - .isEqualTo(GREEN); - } - - @Test - public void checkNode_returns_YELLOW_status_if_only_GREEN_and_at_least_one_YELLOW_statuses_returned_by_NodeHealthCheck() { - List<Health.Status> statuses = new ArrayList<>(); - Stream.concat( - IntStream.range(0, 1 + random.nextInt(20)).mapToObj(i -> YELLOW), // at least 1 YELLOW - IntStream.range(0, random.nextInt(20)).mapToObj(i -> GREEN)).forEach(statuses::add); // between 0 and 19 GREEN - Collections.shuffle(statuses); - HealthCheckerImpl underTest = newNodeHealthCheckerImpl(statuses.stream()); - - assertThat(underTest.checkNode().getStatus()) - .describedAs("%s should have been computed from %s statuses", YELLOW, statuses) - .isEqualTo(YELLOW); - } - - @Test - public void checkNode_returns_RED_status_if_at_least_one_RED_status_returned_by_NodeHealthCheck() { - List<Health.Status> statuses = new ArrayList<>(); - Stream.of( - IntStream.range(0, 1 + random.nextInt(20)).mapToObj(i -> RED), // at least 1 RED - IntStream.range(0, random.nextInt(20)).mapToObj(i -> YELLOW), // between 0 and 19 YELLOW - IntStream.range(0, random.nextInt(20)).mapToObj(i -> GREEN) // between 0 and 19 GREEN - ).flatMap(s -> s) - .forEach(statuses::add); - Collections.shuffle(statuses); - HealthCheckerImpl underTest = newNodeHealthCheckerImpl(statuses.stream()); - - assertThat(underTest.checkNode().getStatus()) - .describedAs("%s should have been computed from %s statuses", RED, statuses) - .isEqualTo(RED); - } - - @Test - public void checkNode_returns_causes_of_all_NodeHealthCheck_whichever_their_status() { - NodeHealthCheck[] nodeHealthChecks = IntStream.range(0, 1 + random.nextInt(20)) - .mapToObj(s -> new HardcodedHealthNodeCheck(IntStream.range(0, random.nextInt(3)).mapToObj(i -> randomAlphanumeric(3)).toArray(String[]::new))) - .map(NodeHealthCheck.class::cast) - .toArray(NodeHealthCheck[]::new); - String[] expected = Arrays.stream(nodeHealthChecks).map(NodeHealthCheck::check).flatMap(s -> s.getCauses().stream()).toArray(String[]::new); - - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, nodeHealthChecks); - - assertThat(underTest.checkNode().getCauses()).containsOnly(expected); - } - - @Test - public void checkCluster_fails_with_ISE_in_standalone() { - when(webServer.isStandalone()).thenReturn(true); - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0], new ClusterHealthCheck[0], sharedHealthState); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Clustering is not enabled"); - - underTest.checkCluster(); - } - - @Test - public void checkCluster_fails_with_ISE_in_clustering_and_HealthState_is_null() { - when(webServer.isStandalone()).thenReturn(false); - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0], new ClusterHealthCheck[0], null); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("HealthState instance can't be null when clustering is enabled"); - - underTest.checkCluster(); - } - - @Test - public void checkCluster_returns_GREEN_when_there_is_no_ClusterHealthCheck() { - when(webServer.isStandalone()).thenReturn(false); - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0], new ClusterHealthCheck[0], sharedHealthState); - - assertThat(underTest.checkCluster().getHealth()).isEqualTo(Health.GREEN); - } - - @Test - public void checkCluster_returns_GREEN_status_if_only_GREEN_statuses_returned_by_ClusterHealthChecks() { - when(webServer.isStandalone()).thenReturn(false); - List<Health.Status> statuses = IntStream.range(1, 1 + random.nextInt(20)).mapToObj(i -> GREEN).collect(Collectors.toList()); - HealthCheckerImpl underTest = newClusterHealthCheckerImpl(statuses.stream()); - - assertThat(underTest.checkCluster().getHealth().getStatus()) - .describedAs("%s should have been computed from %s statuses", GREEN, statuses) - .isEqualTo(GREEN); - } - - @Test - public void checkCluster_returns_YELLOW_status_if_only_GREEN_and_at_least_one_YELLOW_statuses_returned_by_ClusterHealthChecks() { - when(webServer.isStandalone()).thenReturn(false); - List<Health.Status> statuses = new ArrayList<>(); - Stream.concat( - IntStream.range(0, 1 + random.nextInt(20)).mapToObj(i -> YELLOW), // at least 1 YELLOW - IntStream.range(0, random.nextInt(20)).mapToObj(i -> GREEN)).forEach(statuses::add); // between 0 and 19 GREEN - Collections.shuffle(statuses); - HealthCheckerImpl underTest = newClusterHealthCheckerImpl(statuses.stream()); - - assertThat(underTest.checkCluster().getHealth().getStatus()) - .describedAs("%s should have been computed from %s statuses", YELLOW, statuses) - .isEqualTo(YELLOW); - } - - @Test - public void checkCluster_returns_RED_status_if_at_least_one_RED_status_returned_by_ClusterHealthChecks() { - when(webServer.isStandalone()).thenReturn(false); - List<Health.Status> statuses = new ArrayList<>(); - Stream.of( - IntStream.range(0, 1 + random.nextInt(20)).mapToObj(i -> RED), // at least 1 RED - IntStream.range(0, random.nextInt(20)).mapToObj(i -> YELLOW), // between 0 and 19 YELLOW - IntStream.range(0, random.nextInt(20)).mapToObj(i -> GREEN) // between 0 and 19 GREEN - ).flatMap(s -> s) - .forEach(statuses::add); - Collections.shuffle(statuses); - HealthCheckerImpl underTest = newClusterHealthCheckerImpl(statuses.stream()); - - assertThat(underTest.checkCluster().getHealth().getStatus()) - .describedAs("%s should have been computed from %s statuses", RED, statuses) - .isEqualTo(RED); - } - - @Test - public void checkCluster_returns_causes_of_all_ClusterHealthChecks_whichever_their_status() { - when(webServer.isStandalone()).thenReturn(false); - List<String[]> causesGroups = IntStream.range(0, 1 + random.nextInt(20)) - .mapToObj(s -> IntStream.range(0, random.nextInt(3)).mapToObj(i -> randomAlphanumeric(3)).toArray(String[]::new)) - .collect(Collectors.toList()); - ClusterHealthCheck[] clusterHealthChecks = causesGroups.stream() - .map(HardcodedHealthClusterCheck::new) - .map(ClusterHealthCheck.class::cast) - .toArray(ClusterHealthCheck[]::new); - String[] expectedCauses = causesGroups.stream().flatMap(Arrays::stream).collect(Collectors.toSet()).stream().toArray(String[]::new); - - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0], clusterHealthChecks, sharedHealthState); - - assertThat(underTest.checkCluster().getHealth().getCauses()).containsOnly(expectedCauses); - } - - @Test - public void checkCluster_passes_set_of_NodeHealth_returns_by_HealthState_to_all_ClusterHealthChecks() { - when(webServer.isStandalone()).thenReturn(false); - ClusterHealthCheck[] mockedClusterHealthChecks = IntStream.range(0, 1 + random.nextInt(3)) - .mapToObj(i -> mock(ClusterHealthCheck.class)) - .toArray(ClusterHealthCheck[]::new); - Set<NodeHealth> nodeHealths = IntStream.range(0, 1 + random.nextInt(4)).mapToObj(i -> randomNodeHealth()).collect(Collectors.toSet()); - when(sharedHealthState.readAll()).thenReturn(nodeHealths); - for (ClusterHealthCheck mockedClusterHealthCheck : mockedClusterHealthChecks) { - when(mockedClusterHealthCheck.check(same(nodeHealths))).thenReturn(Health.GREEN); - } - - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0], mockedClusterHealthChecks, sharedHealthState); - underTest.checkCluster(); - - for (ClusterHealthCheck mockedClusterHealthCheck : mockedClusterHealthChecks) { - verify(mockedClusterHealthCheck).check(same(nodeHealths)); - } - } - - @Test - public void checkCluster_returns_NodeHealths_returned_by_HealthState() { - when(webServer.isStandalone()).thenReturn(false); - Set<NodeHealth> nodeHealths = IntStream.range(0, 1 + random.nextInt(4)).mapToObj(i -> randomNodeHealth()).collect(Collectors.toSet()); - when(sharedHealthState.readAll()).thenReturn(nodeHealths); - - HealthCheckerImpl underTest = new HealthCheckerImpl(webServer, new NodeHealthCheck[0], new ClusterHealthCheck[0], sharedHealthState); - - ClusterHealth clusterHealth = underTest.checkCluster(); - assertThat(clusterHealth.getNodes()).isEqualTo(nodeHealths); - } - - private NodeHealth randomNodeHealth() { - return newNodeHealthBuilder() - .setStatus(NodeHealth.Status.values()[random.nextInt(NodeHealth.Status.values().length)]) - .setDetails(newNodeDetailsBuilder() - .setType(random.nextBoolean() ? NodeDetails.Type.APPLICATION : NodeDetails.Type.SEARCH) - .setName(randomAlphanumeric(10)) - .setHost(randomAlphanumeric(5)) - .setPort(1 + random.nextInt(333)) - .setStartedAt(1 + random.nextInt(444)) - .build()) - .build(); - } - - private HealthCheckerImpl newNodeHealthCheckerImpl(Stream<Health.Status> statuses) { - Stream<HardcodedHealthNodeCheck> staticHealthCheckStream = statuses.map(HardcodedHealthNodeCheck::new); - return new HealthCheckerImpl( - webServer, - staticHealthCheckStream.map(NodeHealthCheck.class::cast).toArray(NodeHealthCheck[]::new)); - } - - private HealthCheckerImpl newClusterHealthCheckerImpl(Stream<Health.Status> statuses) { - Stream<HardcodedHealthClusterCheck> staticHealthCheckStream = statuses.map(HardcodedHealthClusterCheck::new); - return new HealthCheckerImpl( - webServer, - new NodeHealthCheck[0], - staticHealthCheckStream.map(ClusterHealthCheck.class::cast).toArray(ClusterHealthCheck[]::new), - sharedHealthState); - } - - private class HardcodedHealthNodeCheck implements NodeHealthCheck { - private final Health health; - - public HardcodedHealthNodeCheck(Health.Status status) { - this.health = newHealthCheckBuilder().setStatus(status).build(); - } - - public HardcodedHealthNodeCheck(String... causes) { - Health.Builder builder = newHealthCheckBuilder().setStatus(Health.Status.values()[random.nextInt(3)]); - Stream.of(causes).forEach(builder::addCause); - this.health = builder.build(); - } - - @Override - public Health check() { - return health; - } - } - - private class HardcodedHealthClusterCheck implements ClusterHealthCheck { - private final Health health; - - public HardcodedHealthClusterCheck(Health.Status status) { - this.health = newHealthCheckBuilder().setStatus(status).build(); - } - - public HardcodedHealthClusterCheck(String... causes) { - Health.Builder builder = newHealthCheckBuilder().setStatus(Health.Status.values()[random.nextInt(3)]); - Stream.of(causes).forEach(builder::addCause); - this.health = builder.build(); - } - - @Override - public Health check(Set<NodeHealth> nodeHealths) { - return health; - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/HealthTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/HealthTest.java deleted file mode 100644 index 00452fc0fc5..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/HealthTest.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import com.google.common.base.Strings; -import java.util.Random; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import org.assertj.core.api.AbstractCharSequenceAssert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.health.Health.newHealthCheckBuilder; - -public class HealthTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private final Random random = new Random(); - private final Health.Status anyStatus = Health.Status.values()[random.nextInt(Health.Status.values().length)]; - private final Set<String> randomCauses = IntStream.range(0, random.nextInt(5)).mapToObj(s -> randomAlphanumeric(3)).collect(Collectors.toSet()); - - @Test - public void build_throws_NPE_if_status_is_null() { - Health.Builder builder = newHealthCheckBuilder(); - - expectStatusNotNullNPE(); - - builder.build(); - } - - @Test - public void setStatus_throws_NPE_if_status_is_null() { - Health.Builder builder = newHealthCheckBuilder(); - - expectStatusNotNullNPE(); - - builder.setStatus(null); - } - - @Test - public void getStatus_returns_status_from_builder() { - Health underTest = newHealthCheckBuilder().setStatus(anyStatus).build(); - - assertThat(underTest.getStatus()).isEqualTo(anyStatus); - } - - @Test - public void addCause_throws_NPE_if_arg_is_null() { - Health.Builder builder = newHealthCheckBuilder(); - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("cause can't be null"); - - builder.addCause(null); - } - - @Test - public void addCause_throws_IAE_if_arg_is_empty() { - Health.Builder builder = newHealthCheckBuilder(); - - expectCauseCannotBeEmptyIAE(); - - builder.addCause(""); - } - - @Test - public void addCause_throws_IAE_if_arg_contains_only_spaces() { - Health.Builder builder = newHealthCheckBuilder(); - - expectCauseCannotBeEmptyIAE(); - - builder.addCause(Strings.repeat(" ", 1 + random.nextInt(5))); - } - - @Test - public void getCause_returns_causes_from_builder() { - Health.Builder builder = newHealthCheckBuilder().setStatus(anyStatus); - randomCauses.forEach(builder::addCause); - Health underTest = builder.build(); - - assertThat(underTest.getCauses()) - .isEqualTo(randomCauses); - } - - @Test - public void green_constant() { - assertThat(Health.GREEN).isEqualTo(newHealthCheckBuilder().setStatus(Health.Status.GREEN).build()); - } - - @Test - public void equals_is_based_on_status_and_causes() { - Health.Builder builder1 = newHealthCheckBuilder(); - Health.Builder builder2 = newHealthCheckBuilder(); - - builder1.setStatus(anyStatus); - builder2.setStatus(anyStatus); - randomCauses.forEach(s -> { - builder1.addCause(s); - builder2.addCause(s); - }); - - assertThat(builder1.build()) - .isEqualTo(builder1.build()) - .isEqualTo(builder2.build()) - .isEqualTo(builder2.build()); - } - - @Test - public void not_equals_to_null_nor_other_type() { - assertThat(Health.GREEN).isNotEqualTo(null); - assertThat(Health.GREEN).isNotEqualTo(new Object()); - assertThat(Health.GREEN).isNotEqualTo(Health.Status.GREEN); - } - - @Test - public void hashcode_is_based_on_status_and_causes() { - Health.Builder builder1 = newHealthCheckBuilder(); - Health.Builder builder2 = newHealthCheckBuilder(); - builder1.setStatus(anyStatus); - builder2.setStatus(anyStatus); - randomCauses.forEach(s -> { - builder1.addCause(s); - builder2.addCause(s); - }); - - assertThat(builder1.build().hashCode()) - .isEqualTo(builder1.build().hashCode()) - .isEqualTo(builder2.build().hashCode()) - .isEqualTo(builder2.build().hashCode()); - } - - @Test - public void verify_toString() { - assertThat(Health.GREEN.toString()).isEqualTo("Health{GREEN, causes=[]}"); - Health.Builder builder = newHealthCheckBuilder().setStatus(anyStatus); - randomCauses.forEach(builder::addCause); - - String underTest = builder.build().toString(); - - AbstractCharSequenceAssert<?, String> a = assertThat(underTest) - .describedAs("toString for status %s and causes %s", anyStatus, randomCauses); - if (randomCauses.isEmpty()) { - a.isEqualTo("Health{" + anyStatus + ", causes=[]}"); - } else if (randomCauses.size() == 1) { - a.isEqualTo("Health{" + anyStatus + ", causes=[" + randomCauses.iterator().next() + "]}"); - } else { - a.startsWith("Health{" + anyStatus + ", causes=[") - .endsWith("]}") - .contains(randomCauses); - } - } - - private void expectStatusNotNullNPE() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("status can't be null"); - } - - private void expectCauseCannotBeEmptyIAE() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("cause can't be empty"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/NodeHealthModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/NodeHealthModuleTest.java deleted file mode 100644 index 4e278877bad..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/NodeHealthModuleTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Random; -import java.util.stream.Collectors; -import org.junit.Test; -import org.picocontainer.ComponentAdapter; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.platform.Server; -import org.sonar.api.utils.System2; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.process.NetworkUtils; -import org.sonar.process.cluster.health.SharedHealthStateImpl; -import org.sonar.process.cluster.hz.HazelcastMember; - -import static java.lang.String.valueOf; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class NodeHealthModuleTest { - private Random random = new Random(); - private MapSettings mapSettings = new MapSettings(); - private NodeHealthModule underTest = new NodeHealthModule(); - - @Test - public void no_broken_dependencies() { - ComponentContainer container = new ComponentContainer(); - Server server = mock(Server.class); - NetworkUtils networkUtils = mock(NetworkUtils.class); - // settings required by NodeHealthProvider - mapSettings.setProperty("sonar.cluster.node.name", randomAlphanumeric(3)); - mapSettings.setProperty("sonar.cluster.node.port", valueOf(1 + random.nextInt(10))); - when(server.getStartedAt()).thenReturn(new Date()); - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(12)); - // upper level dependencies - container.add( - mock(System2.class), - mapSettings.asConfig(), - server, - networkUtils, - mock(HazelcastMember.class)); - // HealthAction dependencies - container.add(mock(HealthChecker.class)); - - underTest.configure(container); - - container.startComponents(); - } - - @Test - public void provides_implementation_of_SharedHealthState() { - ComponentContainer container = new ComponentContainer(); - - underTest.configure(container); - - assertThat(classesAddedToContainer(container)) - .contains(SharedHealthStateImpl.class); - } - - private List<Class<?>> classesAddedToContainer(ComponentContainer container) { - Collection<ComponentAdapter<?>> componentAdapters = container.getPicoContainer().getComponentAdapters(); - return componentAdapters.stream().map(ComponentAdapter::getComponentImplementation).collect(Collectors.toList()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/NodeHealthProviderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/NodeHealthProviderImplTest.java deleted file mode 100644 index 72366851eb6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/NodeHealthProviderImplTest.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Arrays; -import java.util.Date; -import java.util.Random; -import java.util.stream.IntStream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.platform.Server; -import org.sonar.process.NetworkUtils; -import org.sonar.process.cluster.health.NodeDetails; -import org.sonar.process.cluster.health.NodeHealth; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_HOST; -import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME; -import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_HZ_PORT; - -public class NodeHealthProviderImplTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private final Random random = new Random(); - private MapSettings mapSettings = new MapSettings(); - private HealthChecker healthChecker = mock(HealthChecker.class); - private Server server = mock(Server.class); - private NetworkUtils networkUtils = mock(NetworkUtils.class); - - @Test - public void constructor_throws_ISE_if_node_name_property_is_not_set() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Property sonar.cluster.node.name is not defined"); - - new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - } - - @Test - public void constructor_thows_NPE_if_NetworkUtils_getHostname_returns_null() { - mapSettings.setProperty(CLUSTER_NODE_NAME.getKey(), randomAlphanumeric(3)); - - expectedException.expect(NullPointerException.class); - - new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - } - - @Test - public void constructor_throws_ISE_if_node_port_property_is_not_set() { - mapSettings.setProperty(CLUSTER_NODE_NAME.getKey(), randomAlphanumeric(3)); - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(23)); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Property sonar.cluster.node.port is not defined"); - - new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - } - - @Test - public void constructor_throws_NPE_is_Server_getStartedAt_is_null() { - setRequiredPropertiesForConstructor(); - - expectedException.expect(NullPointerException.class); - - new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - } - - @Test - public void get_returns_HEALTH_status_and_causes_from_HealthChecker_checkNode() { - setRequiredPropertiesForConstructor(); - setStartedAt(); - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(4)); - Health.Status randomStatus = Health.Status.values()[random.nextInt(Health.Status.values().length)]; - String[] expected = IntStream.range(0, random.nextInt(4)).mapToObj(s -> randomAlphabetic(55)).toArray(String[]::new); - Health.Builder healthBuilder = Health.newHealthCheckBuilder() - .setStatus(randomStatus); - Arrays.stream(expected).forEach(healthBuilder::addCause); - when(healthChecker.checkNode()).thenReturn(healthBuilder.build()); - NodeHealthProviderImpl underTest = new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - - NodeHealth nodeHealth = underTest.get(); - - assertThat(nodeHealth.getStatus().name()).isEqualTo(randomStatus.name()); - assertThat(nodeHealth.getCauses()).containsOnly(expected); - } - - @Test - public void get_returns_APPLICATION_type() { - setRequiredPropertiesForConstructor(); - setStartedAt(); - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(23)); - when(healthChecker.checkNode()).thenReturn(Health.newHealthCheckBuilder() - .setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]) - .build()); - NodeHealthProviderImpl underTest = new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - - NodeHealth nodeHealth = underTest.get(); - - assertThat(nodeHealth.getDetails().getType()).isEqualTo(NodeDetails.Type.APPLICATION); - } - - @Test - public void get_returns_name_and_port_from_properties_at_constructor_time() { - String name = randomAlphanumeric(3); - int port = 1 + random.nextInt(4); - mapSettings.setProperty(CLUSTER_NODE_NAME.getKey(), name); - mapSettings.setProperty(CLUSTER_NODE_HZ_PORT.getKey(), port); - setStartedAt(); - when(healthChecker.checkNode()).thenReturn(Health.newHealthCheckBuilder() - .setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]) - .build()); - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(3)); - NodeHealthProviderImpl underTest = new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - - NodeHealth nodeHealth = underTest.get(); - - assertThat(nodeHealth.getDetails().getName()).isEqualTo(name); - assertThat(nodeHealth.getDetails().getPort()).isEqualTo(port); - - // change values in properties - setRequiredPropertiesForConstructor(); - - NodeHealth newNodeHealth = underTest.get(); - - assertThat(newNodeHealth.getDetails().getName()).isEqualTo(name); - assertThat(newNodeHealth.getDetails().getPort()).isEqualTo(port); - } - - @Test - public void get_returns_host_from_property_if_set_at_constructor_time() { - String host = randomAlphanumeric(4); - mapSettings.setProperty(CLUSTER_NODE_NAME.getKey(), randomAlphanumeric(3)); - mapSettings.setProperty(CLUSTER_NODE_HZ_PORT.getKey(), 1 + random.nextInt(4)); - mapSettings.setProperty(CLUSTER_NODE_HOST.getKey(), host); - setStartedAt(); - when(healthChecker.checkNode()).thenReturn(Health.newHealthCheckBuilder() - .setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]) - .build()); - NodeHealthProviderImpl underTest = new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - - NodeHealth nodeHealth = underTest.get(); - - assertThat(nodeHealth.getDetails().getHost()).isEqualTo(host); - - // change values in properties - mapSettings.setProperty(CLUSTER_NODE_HOST.getKey(), randomAlphanumeric(66)); - - NodeHealth newNodeHealth = underTest.get(); - - assertThat(newNodeHealth.getDetails().getHost()).isEqualTo(host); - } - - @Test - public void get_returns_hostname_from_NetworkUtils_if_property_is_not_set_at_constructor_time() { - getReturnsHostnameFromNetworkUtils(null); - } - - @Test - public void get_returns_hostname_from_NetworkUtils_if_property_is_empty_at_constructor_time() { - getReturnsHostnameFromNetworkUtils(random.nextBoolean() ? "" : " "); - } - - private void getReturnsHostnameFromNetworkUtils(String hostPropertyValue) { - String host = randomAlphanumeric(3); - setRequiredPropertiesForConstructor(); - if (hostPropertyValue != null) { - mapSettings.setProperty(CLUSTER_NODE_HOST.getKey(), hostPropertyValue); - } - setStartedAt(); - when(healthChecker.checkNode()).thenReturn(Health.newHealthCheckBuilder() - .setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]) - .build()); - when(networkUtils.getHostname()).thenReturn(host); - NodeHealthProviderImpl underTest = new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - - NodeHealth nodeHealth = underTest.get(); - - assertThat(nodeHealth.getDetails().getHost()).isEqualTo(host); - - // change hostname - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(4)); - - NodeHealth newNodeHealth = underTest.get(); - - assertThat(newNodeHealth.getDetails().getHost()).isEqualTo(host); - } - - @Test - public void get_returns_started_from_server_startedAt_at_constructor_time() { - setRequiredPropertiesForConstructor(); - when(networkUtils.getHostname()).thenReturn(randomAlphanumeric(4)); - Date date = new Date(); - when(server.getStartedAt()).thenReturn(date); - when(healthChecker.checkNode()).thenReturn(Health.newHealthCheckBuilder() - .setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]) - .build()); - NodeHealthProviderImpl underTest = new NodeHealthProviderImpl(mapSettings.asConfig(), healthChecker, server, networkUtils); - - NodeHealth nodeHealth = underTest.get(); - - assertThat(nodeHealth.getDetails().getStartedAt()).isEqualTo(date.getTime()); - - // change startedAt value - setStartedAt(); - - NodeHealth newNodeHealth = underTest.get(); - - assertThat(newNodeHealth.getDetails().getStartedAt()).isEqualTo(date.getTime()); - } - - private void setStartedAt() { - when(server.getStartedAt()).thenReturn(new Date()); - } - - private void setRequiredPropertiesForConstructor() { - mapSettings.setProperty(CLUSTER_NODE_NAME.getKey(), randomAlphanumeric(3)); - mapSettings.setProperty(CLUSTER_NODE_HZ_PORT.getKey(), 1 + random.nextInt(4)); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/TestStandaloneHealthChecker.java b/server/sonar-server/src/test/java/org/sonar/server/health/TestStandaloneHealthChecker.java deleted file mode 100644 index 27c2e469dde..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/TestStandaloneHealthChecker.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -public class TestStandaloneHealthChecker implements HealthChecker { - - private Health health = Health.newHealthCheckBuilder().setStatus(Health.Status.GREEN).build(); - - public void setHealth(Health h) { - this.health = h; - } - - @Override - public Health checkNode() { - return health; - } - - @Override - public ClusterHealth checkCluster() { - throw new IllegalStateException(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/WebServerSafemodeNodeCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/WebServerSafemodeNodeCheckTest.java deleted file mode 100644 index a18121e0213..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/WebServerSafemodeNodeCheckTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class WebServerSafemodeNodeCheckTest { - private WebServerSafemodeNodeCheck underTest = new WebServerSafemodeNodeCheck(); - - @Test - public void always_returns_RED_status_with_cause() { - Health health = underTest.check(); - - assertThat(health.getStatus()).isEqualTo(Health.Status.RED); - assertThat(health.getCauses()).containsOnly("SonarQube webserver is not up"); - - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/WebServerStatusNodeCheckTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/WebServerStatusNodeCheckTest.java deleted file mode 100644 index 05977854180..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/health/WebServerStatusNodeCheckTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.health; - -import java.util.Arrays; -import java.util.Random; -import org.junit.Test; -import org.sonar.server.app.RestartFlagHolder; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.db.migration.DatabaseMigrationState; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class WebServerStatusNodeCheckTest { - private final DatabaseMigrationState migrationState = mock(DatabaseMigrationState.class); - private final Platform platform = mock(Platform.class); - private final RestartFlagHolder restartFlagHolder = mock(RestartFlagHolder.class); - - private final Random random = new Random(); - - private WebServerStatusNodeCheck underTest = new WebServerStatusNodeCheck(migrationState, platform, restartFlagHolder); - - @Test - public void returns_RED_status_with_cause_if_platform_status_is_not_UP() { - Platform.Status[] statusesButUp = Arrays.stream(Platform.Status.values()) - .filter(s -> s != Platform.Status.UP) - .toArray(Platform.Status[]::new); - Platform.Status randomStatusButUp = statusesButUp[random.nextInt(statusesButUp.length)]; - when(platform.status()).thenReturn(randomStatusButUp); - - Health health = underTest.check(); - - verifyRedHealthWithCause(health); - } - - @Test - public void returns_RED_status_with_cause_if_platform_status_is_UP_but_migrationStatus_is_neither_NONE_nor_SUCCEED() { - when(platform.status()).thenReturn(Platform.Status.UP); - DatabaseMigrationState.Status[] statusesButValidOnes = Arrays.stream(DatabaseMigrationState.Status.values()) - .filter(s -> s != DatabaseMigrationState.Status.NONE) - .filter(s -> s != DatabaseMigrationState.Status.SUCCEEDED) - .toArray(DatabaseMigrationState.Status[]::new); - DatabaseMigrationState.Status randomInvalidStatus = statusesButValidOnes[random.nextInt(statusesButValidOnes.length)]; - when(migrationState.getStatus()).thenReturn(randomInvalidStatus); - - Health health = underTest.check(); - - verifyRedHealthWithCause(health); - } - - @Test - public void returns_RED_with_cause_if_platform_status_is_UP_migration_status_is_valid_but_SQ_is_restarting() { - when(platform.status()).thenReturn(Platform.Status.UP); - when(migrationState.getStatus()).thenReturn(random.nextBoolean() ? DatabaseMigrationState.Status.NONE : DatabaseMigrationState.Status.SUCCEEDED); - when(restartFlagHolder.isRestarting()).thenReturn(true); - - Health health = underTest.check(); - - verifyRedHealthWithCause(health); - } - - @Test - public void returns_GREEN_without_cause_if_platform_status_is_UP_migration_status_is_valid_and_SQ_is_not_restarting() { - when(platform.status()).thenReturn(Platform.Status.UP); - when(migrationState.getStatus()).thenReturn(random.nextBoolean() ? DatabaseMigrationState.Status.NONE : DatabaseMigrationState.Status.SUCCEEDED); - when(restartFlagHolder.isRestarting()).thenReturn(false); - - Health health = underTest.check(); - - assertThat(health).isEqualTo(Health.GREEN); - } - - private void verifyRedHealthWithCause(Health health) { - assertThat(health.getStatus()).isEqualTo(Health.Status.RED); - assertThat(health.getCauses()).containsOnly("SonarQube webserver is not up"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java deleted file mode 100644 index 16343e1a5ae..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.server.user.UserSession; - -public class ActionTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void key_should_not_be_empty() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Action key must be set"); - - new FakeAction(""); - } - - @Test - public void key_should_not_be_null() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Action key must be set"); - - new FakeAction(null); - } - - private static class FakeAction extends Action { - - FakeAction(String key) { - super(key); - } - - @Override - public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) { - return false; - } - - @Override - public boolean execute(Map<String, Object> properties, Context context) { - return false; - } - - @Override - public boolean shouldRefreshMeasures() { - return false; - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/AddTagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/AddTagsActionTest.java deleted file mode 100644 index fe6a79e456f..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/AddTagsActionTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.ImmutableSet; -import java.util.HashMap; -import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.core.issue.DefaultIssue; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class AddTagsActionTest { - - @Rule - public ExpectedException throwable = ExpectedException.none(); - - private IssueFieldsSetter issueUpdater = new IssueFieldsSetter(); - private AddTagsAction underTest = new AddTagsAction(issueUpdater); - - @Test - @SuppressWarnings("unchecked") - public void should_execute() { - Map<String, Object> properties = new HashMap<>(); - properties.put("tags", "tag2,tag3"); - - DefaultIssue issue = mock(DefaultIssue.class); - when(issue.tags()).thenReturn(ImmutableSet.of("tag1", "tag3")); - - Action.Context context = mock(Action.Context.class, Mockito.RETURNS_DEEP_STUBS); - when(context.issue()).thenReturn(issue); - - underTest.execute(properties, context); - verify(issue).setTags(ImmutableSet.of("tag1", "tag2", "tag3")); - } - - @Test - public void should_fail_if_tag_is_not_valid() { - throwable.expect(IllegalArgumentException.class); - throwable.expectMessage("Tag 'th ag' is invalid. Rule tags accept only the characters: a-z, 0-9, '+', '-', '#', '.'"); - - Map<String, Object> properties = new HashMap<>(); - properties.put("tags", "th ag"); - - DefaultIssue issue = mock(DefaultIssue.class); - when(issue.tags()).thenReturn(ImmutableSet.of("tag1", "tag3")); - - Action.Context context = mock(Action.Context.class); - when(context.issue()).thenReturn(issue); - - underTest.execute(properties, context); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java deleted file mode 100644 index cdfe07d39a4..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.issue.Issue; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.tester.UserSessionRule; - -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.rules.ExpectedException.none; -import static org.sonar.server.tester.UserSessionRule.standalone; - -public class AssignActionTest { - - private static final String ISSUE_CURRENT_ASSIGNEE_UUID = "current assignee uuid"; - - @Rule - public ExpectedException expectedException = none(); - - @Rule - public UserSessionRule userSession = standalone(); - - @Rule - public DbTester db = DbTester.create(); - - private IssueChangeContext issueChangeContext = IssueChangeContext.createUser(new Date(), "user_uuid"); - private DefaultIssue issue = new DefaultIssue().setKey("ABC").setAssigneeUuid(ISSUE_CURRENT_ASSIGNEE_UUID); - private ComponentDto project; - private Action.Context context; - private OrganizationDto issueOrganizationDto; - - private AssignAction underTest = new AssignAction(db.getDbClient(), new IssueFieldsSetter()); - - @Before - public void setUp() throws Exception { - issueOrganizationDto = db.organizations().insert(); - project = db.components().insertPrivateProject(issueOrganizationDto); - context = new ActionContext(issue, issueChangeContext, project); - } - - @Test - public void assign_issue() { - UserDto assignee = db.users().insertUser("john"); - db.organizations().addMember(issueOrganizationDto, assignee); - Map<String, Object> properties = new HashMap<>(ImmutableMap.of("assignee", "john")); - - underTest.verify(properties, Collections.emptyList(), userSession); - boolean executeResult = underTest.execute(properties, context); - - assertThat(executeResult).isTrue(); - assertThat(issue.assignee()).isEqualTo(assignee.getUuid()); - } - - @Test - public void unassign_issue_if_assignee_is_empty() { - Map<String, Object> properties = new HashMap<>(ImmutableMap.of("assignee", "")); - - underTest.verify(properties, Collections.emptyList(), userSession); - boolean executeResult = underTest.execute(properties, context); - - assertThat(executeResult).isTrue(); - assertThat(issue.assignee()).isNull(); - } - - @Test - public void unassign_issue_if_assignee_is_null() { - Map<String, Object> properties = new HashMap<>(); - properties.put("assignee", null); - - underTest.verify(properties, Collections.emptyList(), userSession); - boolean executeResult = underTest.execute(properties, context); - - assertThat(executeResult).isTrue(); - assertThat(issue.assignee()).isNull(); - } - - @Test - public void does_not_assign_issue_when_assignee_is_not_member_of_project_issue_organization() { - OrganizationDto otherOrganizationDto = db.organizations().insert(); - UserDto assignee = db.users().insertUser("john"); - // User is not member of the organization of the issue - db.organizations().addMember(otherOrganizationDto, assignee); - Map<String, Object> properties = new HashMap<>(ImmutableMap.of("assignee", "john")); - - underTest.verify(properties, Collections.emptyList(), userSession); - boolean executeResult = underTest.execute(properties, context); - - assertThat(executeResult).isFalse(); - } - - @Test - public void fail_if_assignee_is_not_verified() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Assignee is missing from the execution parameters"); - - underTest.execute(emptyMap(), context); - } - - @Test - public void fail_if_assignee_does_not_exists() { - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Unknown user: arthur"); - - underTest.verify(ImmutableMap.of("assignee", "arthur"), singletonList(issue), userSession); - } - - @Test - public void fail_if_assignee_is_disabled() { - db.users().insertUser(user -> user.setLogin("arthur").setActive(false)); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Unknown user: arthur"); - - underTest.verify(new HashMap<>(ImmutableMap.of("assignee", "arthur")), singletonList(issue), userSession); - } - - @Test - public void support_only_unresolved_issues() { - assertThat(underTest.supports(new DefaultIssue().setResolution(null))).isTrue(); - assertThat(underTest.supports(new DefaultIssue().setResolution(Issue.RESOLUTION_FIXED))).isFalse(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java deleted file mode 100644 index 2e1d68afb1f..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.Lists; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.issue.Issue; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.server.tester.AnonymousMockUserSession; - -import static com.google.common.collect.Maps.newHashMap; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.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; - -public class CommentActionTest { - - private CommentAction action; - - private IssueFieldsSetter issueUpdater = mock(IssueFieldsSetter.class); - - @Before - public void before() { - action = new CommentAction(issueUpdater); - } - - @Test - public void should_execute() { - String comment = "My bulk change comment"; - Map<String, Object> properties = newHashMap(); - properties.put("comment", comment); - DefaultIssue issue = mock(DefaultIssue.class); - - Action.Context context = mock(Action.Context.class); - when(context.issue()).thenReturn(issue); - - action.execute(properties, context); - verify(issueUpdater).addComment(eq(issue), eq(comment), any()); - } - - @Test - public void should_verify_fail_if_parameter_not_found() { - Map<String, Object> properties = newHashMap(); - properties.put("unknwown", "unknown value"); - try { - action.verify(properties, Lists.newArrayList(), new AnonymousMockUserSession()); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Missing parameter : 'comment'"); - } - verifyZeroInteractions(issueUpdater); - } - - @Test - public void should_support_all_issues() { - assertThat(action.supports(new DefaultIssue().setResolution(null))).isTrue(); - assertThat(action.supports(new DefaultIssue().setResolution(Issue.RESOLUTION_FIXED))).isTrue(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueFinderTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueFinderTest.java deleted file mode 100644 index 51f1566f9d0..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueFinderTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -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 org.sonar.db.component.ComponentDbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueDbTester; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.rule.RuleDbTester; -import org.sonar.db.rule.RuleDto; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.tester.UserSessionRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.web.UserRole.CODEVIEWER; -import static org.sonar.api.web.UserRole.USER; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.issue.IssueTesting.newDto; -import static org.sonar.db.rule.RuleTesting.newRuleDto; - -public class IssueFinderTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - private RuleDbTester ruleDbTester = new RuleDbTester(db); - private IssueDbTester issueDbTester = new IssueDbTester(db); - private ComponentDbTester componentDbTester = new ComponentDbTester(db); - - private IssueFinder underTest = new IssueFinder(db.getDbClient(), userSession); - - @Test - public void get_by_issue_key() { - IssueDto issueDto = insertIssue(); - String permission = USER; - addProjectPermission(issueDto, permission); - - IssueDto result = underTest.getByKey(db.getSession(), issueDto.getKey()); - - assertThat(result).isNotNull(); - assertThat(result.getKey()).isEqualTo(issueDto.getKey()); - } - - @Test - public void fail_when_issue_key_does_not_exist() { - IssueDto issueDto = insertIssue(); - addProjectPermission(issueDto, USER); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Issue with key 'UNKNOWN' does not exist"); - underTest.getByKey(db.getSession(), "UNKNOWN"); - } - - @Test - public void fail_when_not_enough_permission() { - IssueDto issueDto = insertIssue(); - addProjectPermission(issueDto, CODEVIEWER); - - expectedException.expect(ForbiddenException.class); - underTest.getByKey(db.getSession(), issueDto.getKey()); - } - - private IssueDto insertIssue() { - RuleDto rule = ruleDbTester.insertRule(newRuleDto()); - ComponentDto project = componentDbTester.insertPrivateProject(); - ComponentDto file = componentDbTester.insertComponent(newFileDto(project)); - return issueDbTester.insertIssue(newDto(rule, file, project)); - } - - private void addProjectPermission(IssueDto issueDto, String permission) { - userSession.addProjectPermission(permission, db.getDbClient().componentDao().selectByUuid(db.getSession(), issueDto.getProjectUuid()).get()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssuesFinderSortTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssuesFinderSortTest.java deleted file mode 100644 index 7d7e2a4bb65..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssuesFinderSortTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Date; -import java.util.List; -import org.apache.commons.lang.time.DateUtils; -import org.junit.Test; -import org.sonar.db.issue.IssueDto; -import org.sonar.server.issue.index.IssueQuery; - -import static com.google.common.collect.Lists.newArrayList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class IssuesFinderSortTest { - - @Test - public void should_sort_by_status() { - IssueDto issue1 = new IssueDto().setId(1L).setStatus("CLOSED"); - IssueDto issue2 = new IssueDto().setId(2L).setStatus("REOPENED"); - IssueDto issue3 = new IssueDto().setId(3L).setStatus("OPEN"); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3); - - IssueQuery query = IssueQuery.builder().sort(IssueQuery.SORT_BY_STATUS).asc(false).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(3); - assertThat(result.get(0).getStatus()).isEqualTo("REOPENED"); - assertThat(result.get(1).getStatus()).isEqualTo("OPEN"); - assertThat(result.get(2).getStatus()).isEqualTo("CLOSED"); - } - - @Test - public void should_sort_by_severity() { - IssueDto issue1 = new IssueDto().setId(1L).setSeverity("INFO"); - IssueDto issue2 = new IssueDto().setId(2L).setSeverity("BLOCKER"); - IssueDto issue3 = new IssueDto().setId(3L).setSeverity("MAJOR"); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3); - - IssueQuery query = IssueQuery.builder().sort(IssueQuery.SORT_BY_SEVERITY).asc(true).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(3); - assertThat(result.get(0).getSeverity()).isEqualTo("INFO"); - assertThat(result.get(1).getSeverity()).isEqualTo("MAJOR"); - assertThat(result.get(2).getSeverity()).isEqualTo("BLOCKER"); - } - - @Test - public void should_sort_by_desc_severity() { - IssueDto issue1 = new IssueDto().setId(1L).setSeverity("INFO"); - IssueDto issue2 = new IssueDto().setId(2L).setSeverity("BLOCKER"); - IssueDto issue3 = new IssueDto().setId(3L).setSeverity("MAJOR"); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3); - - IssueQuery query = IssueQuery.builder().sort(IssueQuery.SORT_BY_SEVERITY).asc(false).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(3); - assertThat(result.get(0).getSeverity()).isEqualTo("BLOCKER"); - assertThat(result.get(1).getSeverity()).isEqualTo("MAJOR"); - assertThat(result.get(2).getSeverity()).isEqualTo("INFO"); - } - - @Test - public void should_sort_by_creation_date() { - Date date = new Date(); - Date date1 = DateUtils.addDays(date, -3); - Date date2 = DateUtils.addDays(date, -2); - Date date3 = DateUtils.addDays(date, -1); - IssueDto issue1 = new IssueDto().setId(1L).setIssueCreationDate(date1); - IssueDto issue2 = new IssueDto().setId(2L).setIssueCreationDate(date3); - IssueDto issue3 = new IssueDto().setId(3L).setIssueCreationDate(date2); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3); - - IssueQuery query = IssueQuery.builder().sort(IssueQuery.SORT_BY_CREATION_DATE).asc(false).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(3); - assertThat(result.get(0).getIssueCreationDate()).isEqualTo(date3); - assertThat(result.get(1).getIssueCreationDate()).isEqualTo(date2); - assertThat(result.get(2).getIssueCreationDate()).isEqualTo(date1); - } - - @Test - public void should_sort_by_update_date() { - Date date = new Date(); - Date date1 = DateUtils.addDays(date, -3); - Date date2 = DateUtils.addDays(date, -2); - Date date3 = DateUtils.addDays(date, -1); - IssueDto issue1 = new IssueDto().setId(1L).setIssueUpdateDate(date1); - IssueDto issue2 = new IssueDto().setId(2L).setIssueUpdateDate(date3); - IssueDto issue3 = new IssueDto().setId(3L).setIssueUpdateDate(date2); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3); - - IssueQuery query = IssueQuery.builder().sort(IssueQuery.SORT_BY_UPDATE_DATE).asc(false).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(3); - assertThat(result.get(0).getIssueUpdateDate()).isEqualTo(date3); - assertThat(result.get(1).getIssueUpdateDate()).isEqualTo(date2); - assertThat(result.get(2).getIssueUpdateDate()).isEqualTo(date1); - } - - @Test - public void should_sort_by_close_date() { - Date date = new Date(); - Date date1 = DateUtils.addDays(date, -3); - Date date2 = DateUtils.addDays(date, -2); - Date date3 = DateUtils.addDays(date, -1); - IssueDto issue1 = new IssueDto().setId(1L).setIssueCloseDate(date1); - IssueDto issue2 = new IssueDto().setId(2L).setIssueCloseDate(date3); - IssueDto issue3 = new IssueDto().setId(3L).setIssueCloseDate(date2); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3); - - IssueQuery query = IssueQuery.builder().sort(IssueQuery.SORT_BY_CLOSE_DATE).asc(false).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(3); - assertThat(result.get(0).getIssueCloseDate()).isEqualTo(date3); - assertThat(result.get(1).getIssueCloseDate()).isEqualTo(date2); - assertThat(result.get(2).getIssueCloseDate()).isEqualTo(date1); - } - - @Test - public void should_not_sort_with_null_sort() { - IssueDto issue1 = new IssueDto().setId(1L).setAssigneeUuid("perceval"); - IssueDto issue2 = new IssueDto().setId(2L).setAssigneeUuid("arthur"); - IssueDto issue3 = new IssueDto().setId(3L).setAssigneeUuid("vincent"); - IssueDto issue4 = new IssueDto().setId(4L).setAssigneeUuid(null); - List<IssueDto> dtoList = newArrayList(issue1, issue2, issue3, issue4); - - IssueQuery query = IssueQuery.builder().sort(null).build(); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(dtoList, query); - - List<IssueDto> result = newArrayList(issuesFinderSort.sort()); - - assertThat(result).hasSize(4); - assertThat(result.get(0).getAssigneeUuid()).isEqualTo("perceval"); - assertThat(result.get(1).getAssigneeUuid()).isEqualTo("arthur"); - assertThat(result.get(2).getAssigneeUuid()).isEqualTo("vincent"); - assertThat(result.get(3).getAssigneeUuid()).isNull(); - } - - @Test - public void should_fail_to_sort_with_unknown_sort() { - IssueQuery query = mock(IssueQuery.class); - when(query.sort()).thenReturn("unknown"); - IssuesFinderSort issuesFinderSort = new IssuesFinderSort(null, query); - try { - issuesFinderSort.sort(); - } catch (Exception e) { - assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Cannot sort on field : unknown"); - } - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/RemoveTagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/RemoveTagsActionTest.java deleted file mode 100644 index 9ad3bc3d751..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/RemoveTagsActionTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.ImmutableSet; -import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.core.issue.DefaultIssue; - -import static com.google.common.collect.Maps.newHashMap; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class RemoveTagsActionTest { - - @Rule - public ExpectedException throwable = ExpectedException.none(); - - private IssueFieldsSetter issueUpdater = new IssueFieldsSetter(); - private RemoveTagsAction action = new RemoveTagsAction(issueUpdater); - - @Test - @SuppressWarnings("unchecked") - public void should_execute() { - Map<String, Object> properties = newHashMap(); - properties.put("tags", "tag2,tag3"); - - DefaultIssue issue = mock(DefaultIssue.class); - when(issue.tags()).thenReturn(ImmutableSet.of("tag1", "tag3")); - - Action.Context context = mock(Action.Context.class, Mockito.RETURNS_DEEP_STUBS); - when(context.issue()).thenReturn(issue); - - action.execute(properties, context); - verify(issue).setTags(ImmutableSet.of("tag1")); - } - - @Test - public void should_fail_if_tag_is_not_valid() { - throwable.expect(IllegalArgumentException.class); - throwable.expectMessage("Tag 'th ag' is invalid. Rule tags accept only the characters: a-z, 0-9, '+', '-', '#', '.'"); - - Map<String, Object> properties = newHashMap(); - properties.put("tags", "th ag"); - - DefaultIssue issue = mock(DefaultIssue.class); - when(issue.tags()).thenReturn(ImmutableSet.of("tag1", "tag3")); - - Action.Context context = mock(Action.Context.class); - when(context.issue()).thenReturn(issue); - - action.execute(properties, context); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ResultTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ResultTest.java deleted file mode 100644 index 9cf037551cb..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ResultTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ResultTest { - @Test - public void test_default_result() { - Result<Object> result = Result.of(); - assertThat(result.ok()).isTrue(); - assertThat(result.errors()).isEmpty(); - assertThat(result.httpStatus()).isEqualTo(200); - assertThat(result.get()).isNull(); - - Object obj = new Object(); - result.set(obj); - assertThat(result.get()).isSameAs(obj); - } - - @Test - public void test_error() { - Result<Object> result = Result.of(); - result.addError("Something goes wrong"); - - assertThat(result.ok()).isFalse(); - assertThat(result.errors()).hasSize(1).contains(Result.Message.of("Something goes wrong")); - assertThat(result.httpStatus()).isEqualTo(400); - assertThat(result.get()).isNull(); - } - - @Test - public void test_l10n_errors() { - Result<Object> result = Result.of(); - Result.Message message = Result.Message.ofL10n("issue.error.123", "10"); - result.addError(message); - - assertThat(result.ok()).isFalse(); - assertThat(result.errors()).hasSize(1).containsOnly(message); - - message = result.errors().get(0); - assertThat(message.text()).isNull(); - assertThat(message.l10nKey()).isEqualTo("issue.error.123"); - assertThat(message.l10nParams()).hasSize(1); - assertThat(message.l10nParams()[0]).isEqualTo("10"); - } - - @Test - public void test_text_message() { - Result.Message txtMessage = Result.Message.of("the error"); - Result.Message sameMessage = Result.Message.of("the error"); - Result.Message otherMessage = Result.Message.of("other"); - - assertThat(txtMessage.toString()).contains("the error"); - assertThat(txtMessage).isEqualTo(txtMessage); - assertThat(txtMessage).isEqualTo(sameMessage); - assertThat(txtMessage.hashCode()).isEqualTo(txtMessage.hashCode()); - assertThat(txtMessage.hashCode()).isEqualTo(sameMessage.hashCode()); - assertThat(txtMessage).isNotEqualTo(otherMessage); - assertThat(txtMessage).isNotEqualTo("the error"); - } - - @Test - public void test_l10n_message() { - Result.Message msg = Result.Message.ofL10n("issue.error.123", "10"); - Result.Message sameMsg = Result.Message.ofL10n("issue.error.123", "10"); - Result.Message msg2 = Result.Message.ofL10n("issue.error.123", "200"); - Result.Message msg3 = Result.Message.ofL10n("issue.error.50"); - - assertThat(msg.toString()).contains("issue.error.123").contains("10"); - assertThat(msg).isEqualTo(msg); - assertThat(msg).isEqualTo(sameMsg); - assertThat(msg.hashCode()).isEqualTo(msg.hashCode()); - assertThat(msg.hashCode()).isEqualTo(sameMsg.hashCode()); - - assertThat(msg).isNotEqualTo(msg2); - assertThat(msg).isNotEqualTo(msg3); - assertThat(msg).isNotEqualTo("issue.error.123"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregation.java b/server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregation.java deleted file mode 100644 index fc14607055e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregation.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; -import java.util.Collection; -import org.sonar.api.rule.RuleKey; -import org.sonar.db.rule.RuleDefinitionDto; - -public class RulesAggregation { - - private Multiset<Rule> rules; - - public RulesAggregation() { - this.rules = HashMultiset.create(); - } - - public RulesAggregation add(RuleDefinitionDto ruleDto) { - rules.add(new Rule(ruleDto.getKey(), ruleDto.getName())); - return this; - } - - public Collection<Rule> rules() { - return rules.elementSet(); - } - - public int countRule(Rule rule) { - return rules.count(rule); - } - - public static class Rule { - - private RuleKey ruleKey; - private String name; - - public Rule(RuleKey ruleKey, String name) { - this.ruleKey = ruleKey; - this.name = name; - } - - public RuleKey ruleKey() { - return ruleKey; - } - - public String name() { - return name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Rule rule = (Rule) o; - - return ruleKey.equals(rule.ruleKey); - } - - @Override - public int hashCode() { - return ruleKey.hashCode(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregationTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregationTest.java deleted file mode 100644 index a22a654980a..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregationTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import org.junit.Test; -import org.sonar.api.rule.RuleKey; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleTesting; - -import static org.assertj.core.api.Assertions.assertThat; - -public class RulesAggregationTest { - - @Test - public void empty() { - RulesAggregation rulesAggregation = new RulesAggregation(); - assertThat(rulesAggregation.rules()).isEmpty(); - } - - @Test - public void count_rules() { - RulesAggregation rulesAggregation = new RulesAggregation(); - RuleKey ruleKey = RuleKey.of("xoo", "S001"); - RuleDefinitionDto ruleDto = RuleTesting.newRule(ruleKey).setName("Rule name"); - rulesAggregation.add(ruleDto); - rulesAggregation.add(ruleDto); - - RulesAggregation.Rule rule = new RulesAggregation.Rule(ruleKey, "Rule name"); - - assertThat(rulesAggregation.rules()).hasSize(1); - assertThat(rulesAggregation.rules().iterator().next().name()).isEqualTo("Rule name"); - assertThat(rulesAggregation.countRule(rule)).isEqualTo(2); - } - - @Test - public void count_rules_with_different_rules() { - RulesAggregation rulesAggregation = new RulesAggregation(); - - RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("xoo", "S001")).setName("Rule name 1"); - rulesAggregation.add(ruleDto); - rulesAggregation.add(ruleDto); - rulesAggregation.add(RuleTesting.newRule(RuleKey.of("xoo", "S002")).setName("Rule name 2")); - - assertThat(rulesAggregation.rules()).hasSize(2); - } - - @Test - public void test_equals_and_hash_code() { - RulesAggregation.Rule rule = new RulesAggregation.Rule(RuleKey.of("xoo", "S001"), "S001"); - RulesAggregation.Rule ruleSameRuleKey = new RulesAggregation.Rule(RuleKey.of("xoo", "S001"), "S001"); - RulesAggregation.Rule ruleWithDifferentRuleKey = new RulesAggregation.Rule(RuleKey.of("xoo", "S002"), "S002"); - - assertThat(rule).isEqualTo(rule); - assertThat(rule).isEqualTo(ruleSameRuleKey); - assertThat(rule).isNotEqualTo(ruleWithDifferentRuleKey); - - assertThat(rule.hashCode()).isEqualTo(rule.hashCode()); - assertThat(rule.hashCode()).isEqualTo(ruleSameRuleKey.hashCode()); - assertThat(rule.hashCode()).isNotEqualTo(ruleWithDifferentRuleKey.hashCode()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/SetSeverityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/SetSeverityActionTest.java deleted file mode 100644 index 3021160d7ef..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/SetSeverityActionTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import java.util.Date; -import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.RuleType; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.FieldDiffs; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.server.tester.AnonymousMockUserSession; -import org.sonar.server.tester.UserSessionRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.rule.Severity.MAJOR; -import static org.sonar.api.rule.Severity.MINOR; -import static org.sonar.api.web.UserRole.ISSUE_ADMIN; -import static org.sonar.api.web.UserRole.USER; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.issue.IssueTesting.newDto; -import static org.sonar.db.rule.RuleTesting.newRuleDto; - -public class SetSeverityActionTest { - - private static final Date NOW = new Date(10_000_000_000L); - private static final String USER_LOGIN = "john"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - @Rule - public DbTester db = DbTester.create(); - - private IssueFieldsSetter issueUpdater = new IssueFieldsSetter(); - - private SetSeverityAction action = new SetSeverityAction(issueUpdater, userSession); - - @Test - public void set_severity() { - IssueDto issueDto = newIssue().setSeverity(MAJOR); - DefaultIssue issue = issueDto.toDefaultIssue(); - setUserWithBrowseAndAdministerIssuePermission(issueDto); - Action.Context context = new ActionContext(issue, IssueChangeContext.createUser(NOW, userSession.getUuid()), null); - - action.execute(ImmutableMap.of("severity", MINOR), context); - - assertThat(issue.severity()).isEqualTo(MINOR); - assertThat(issue.isChanged()).isTrue(); - assertThat(issue.manualSeverity()).isTrue(); - assertThat(issue.updateDate()).isEqualTo(NOW); - assertThat(issue.mustSendNotifications()).isTrue(); - Map<String, FieldDiffs.Diff> change = issue.currentChange().diffs(); - assertThat(change.get("severity").newValue()).isEqualTo(MINOR); - assertThat(change.get("severity").oldValue()).isEqualTo(MAJOR); - } - - @Test - public void fail_if_parameter_not_found() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Missing parameter : 'severity'"); - - action.verify(ImmutableMap.of("unknwown", MINOR), Lists.newArrayList(), new AnonymousMockUserSession()); - } - - @Test - public void support_only_unresolved_issues() { - IssueDto issueDto = newIssue().setSeverity(MAJOR); - DefaultIssue issue = issueDto.toDefaultIssue(); - setUserWithBrowseAndAdministerIssuePermission(issueDto); - - assertThat(action.supports(issue.setResolution(null))).isTrue(); - assertThat(action.supports(issue.setResolution(Issue.RESOLUTION_FIXED))).isFalse(); - } - - @Test - public void doesnt_support_security_hotspots() { - IssueDto issueDto = newIssue().setSeverity(MAJOR); - DefaultIssue issue = issueDto.toDefaultIssue(); - setUserWithBrowseAndAdministerIssuePermission(issueDto); - - assertThat(action.supports(issue.setType(RuleType.CODE_SMELL))).isTrue(); - assertThat(action.supports(issue.setType(RuleType.SECURITY_HOTSPOT))).isFalse(); - } - - @Test - public void support_only_issues_with_issue_admin_permission() { - IssueDto authorizedIssue = newIssue().setSeverity(MAJOR); - setUserWithBrowseAndAdministerIssuePermission(authorizedIssue); - IssueDto unauthorizedIssue = newIssue().setSeverity(MAJOR); - - assertThat(action.supports(authorizedIssue.toDefaultIssue().setResolution(null))).isTrue(); - assertThat(action.supports(unauthorizedIssue.toDefaultIssue().setResolution(null))).isFalse(); - } - - private void setUserWithBrowseAndAdministerIssuePermission(IssueDto issue) { - ComponentDto project = db.getDbClient().componentDao().selectByUuid(db.getSession(), issue.getProjectUuid()).get(); - ComponentDto component = db.getDbClient().componentDao().selectByUuid(db.getSession(), issue.getComponentUuid()).get(); - userSession.logIn(USER_LOGIN) - .addProjectPermission(ISSUE_ADMIN, project, component) - .addProjectPermission(USER, project, component); - } - - private IssueDto newIssue() { - RuleDto rule = db.rules().insertRule(newRuleDto()); - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - return newDto(rule, file, project); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/SetTypeActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/SetTypeActionTest.java deleted file mode 100644 index 2585b44f5b9..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/SetTypeActionTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import java.util.Date; -import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.issue.Issue; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.FieldDiffs; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.server.tester.UserSessionRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.rules.RuleType.BUG; -import static org.sonar.api.rules.RuleType.VULNERABILITY; -import static org.sonar.api.web.UserRole.ISSUE_ADMIN; -import static org.sonar.api.web.UserRole.USER; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.issue.IssueTesting.newDto; -import static org.sonar.db.rule.RuleTesting.newRuleDto; - -public class SetTypeActionTest { - - private static final Date NOW = new Date(10_000_000_000L); - private static final String USER_LOGIN = "john"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - @Rule - public DbTester db = DbTester.create(); - - private IssueFieldsSetter issueUpdater = new IssueFieldsSetter(); - - private SetTypeAction action = new SetTypeAction(issueUpdater, userSession); - - @Test - public void set_type() { - IssueDto issueDto = newIssue().setType(BUG); - DefaultIssue issue = issueDto.toDefaultIssue(); - setUserWithBrowseAndAdministerIssuePermission(issueDto); - - action.execute(ImmutableMap.of("type", VULNERABILITY.name()), - new ActionContext(issue, IssueChangeContext.createUser(NOW, userSession.getUuid()), null)); - - assertThat(issue.type()).isEqualTo(VULNERABILITY); - assertThat(issue.isChanged()).isTrue(); - assertThat(issue.updateDate()).isEqualTo(NOW); - assertThat(issue.mustSendNotifications()).isFalse(); - Map<String, FieldDiffs.Diff> change = issue.currentChange().diffs(); - assertThat(change.get("type").newValue()).isEqualTo(VULNERABILITY); - assertThat(change.get("type").oldValue()).isEqualTo(BUG); - } - - @Test - public void verify_fail_if_parameter_not_found() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Missing parameter : 'type'"); - - action.verify(ImmutableMap.of("unknwown", VULNERABILITY.name()), Lists.newArrayList(), userSession); - } - - @Test - public void verify_fail_if_type_is_invalid() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Unknown type : unknown"); - - action.verify(ImmutableMap.of("type", "unknown"), Lists.newArrayList(), userSession); - } - - @Test - public void support_only_unresolved_issues() { - IssueDto issueDto = newIssue().setType(BUG); - DefaultIssue issue = issueDto.toDefaultIssue(); - setUserWithBrowseAndAdministerIssuePermission(issueDto); - - assertThat(action.supports(issue.setResolution(null))).isTrue(); - assertThat(action.supports(issue.setResolution(Issue.RESOLUTION_FIXED))).isFalse(); - } - - @Test - public void support_only_issues_with_issue_admin_permission() { - IssueDto authorizedIssueDto = newIssue().setType(BUG); - DefaultIssue authorizedIssue = authorizedIssueDto.toDefaultIssue(); - setUserWithBrowseAndAdministerIssuePermission(authorizedIssueDto); - DefaultIssue unauthorizedIssue = newIssue().setType(BUG).toDefaultIssue(); - - assertThat(action.supports(authorizedIssue.setResolution(null))).isTrue(); - assertThat(action.supports(unauthorizedIssue.setResolution(null))).isFalse(); - } - - private void setUserWithBrowseAndAdministerIssuePermission(IssueDto issueDto) { - ComponentDto project = db.getDbClient().componentDao().selectByUuid(db.getSession(), issueDto.getProjectUuid()).get(); - ComponentDto component = db.getDbClient().componentDao().selectByUuid(db.getSession(), issueDto.getComponentUuid()).get(); - userSession.logIn(USER_LOGIN) - .addProjectPermission(ISSUE_ADMIN, project, component) - .addProjectPermission(USER, project, component); - } - - private IssueDto newIssue() { - RuleDto rule = db.rules().insertRule(newRuleDto()); - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - return newDto(rule, file, project); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/TestIssueChangePostProcessor.java b/server/sonar-server/src/test/java/org/sonar/server/issue/TestIssueChangePostProcessor.java deleted file mode 100644 index 59c1cc8d8b9..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/TestIssueChangePostProcessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; - -public class TestIssueChangePostProcessor implements IssueChangePostProcessor { - - private boolean called = false; - private final List<ComponentDto> calledComponents = new ArrayList<>(); - - @Override - public void process(DbSession dbSession, List<DefaultIssue> changedIssues, Collection<ComponentDto> components) { - called = true; - calledComponents.addAll(components); - } - - public boolean wasCalled() { - return called; - } - - public List<ComponentDto> calledComponents() { - return calledComponents; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/TransitionActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/TransitionActionTest.java deleted file mode 100644 index 8a2866dfd97..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/TransitionActionTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import java.util.Date; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.issue.Issue; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.organization.OrganizationTesting; -import org.sonar.db.rule.RuleDto; -import org.sonar.server.issue.workflow.FunctionExecutor; -import org.sonar.server.issue.workflow.IssueWorkflow; -import org.sonar.server.tester.UserSessionRule; - -import static java.util.Collections.emptyList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.api.issue.Issue.STATUS_CLOSED; -import static org.sonar.api.web.UserRole.ISSUE_ADMIN; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.issue.IssueTesting.newDto; -import static org.sonar.db.rule.RuleTesting.newRuleDto; - -public class TransitionActionTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - private IssueFieldsSetter updater = new IssueFieldsSetter(); - private IssueWorkflow workflow = new IssueWorkflow(new FunctionExecutor(updater), updater); - private TransitionService transitionService = new TransitionService(userSession, workflow); - - private Action.Context context = mock(Action.Context.class); - private DefaultIssue issue = newIssue().toDefaultIssue(); - - private TransitionAction action = new TransitionAction(transitionService); - - @Before - public void setUp() throws Exception { - workflow.start(); - when(context.issue()).thenReturn(issue); - when(context.issueChangeContext()).thenReturn(IssueChangeContext.createUser(new Date(), "user_uuid")); - } - - @Test - public void execute() { - loginAndAddProjectPermission("john", ISSUE_ADMIN); - issue.setStatus(Issue.STATUS_RESOLVED); - issue.setResolution(Issue.RESOLUTION_FIXED); - - action.execute(ImmutableMap.of("transition", "reopen"), context); - - assertThat(issue.status()).isEqualTo(Issue.STATUS_REOPENED); - assertThat(issue.resolution()).isNull(); - } - - @Test - public void does_not_execute_if_transition_is_not_available() { - loginAndAddProjectPermission("john", ISSUE_ADMIN); - issue.setStatus(STATUS_CLOSED); - - action.execute(ImmutableMap.of("transition", "reopen"), context); - - assertThat(issue.status()).isEqualTo(STATUS_CLOSED); - } - - @Test - public void test_verify() { - assertThat(action.verify(ImmutableMap.of("transition", "reopen"), emptyList(), userSession)).isTrue(); - assertThat(action.verify(ImmutableMap.of("transition", "close"), emptyList(), userSession)).isTrue(); - } - - @Test - public void fail_to_verify_when_parameter_not_found() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Missing parameter : 'transition'"); - action.verify(ImmutableMap.of("unknwown", "reopen"), Lists.newArrayList(), userSession); - } - - @Test - public void should_support_all_issues() { - assertThat(action.supports(new DefaultIssue().setResolution(null))).isTrue(); - assertThat(action.supports(new DefaultIssue().setResolution(Issue.RESOLUTION_FIXED))).isTrue(); - } - - private IssueDto newIssue() { - RuleDto rule = newRuleDto().setId(10); - ComponentDto project = ComponentTesting.newPrivateProjectDto(OrganizationTesting.newOrganizationDto()); - ComponentDto file = (newFileDto(project)); - return newDto(rule, file, project); - } - - private void loginAndAddProjectPermission(String login, String permission) { - userSession.logIn(login).addProjectPermission(permission, ComponentTesting.newPrivateProjectDto(OrganizationTesting.newOrganizationDto(), issue.projectUuid())); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/TransitionServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/TransitionServiceTest.java deleted file mode 100644 index 69729235480..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/TransitionServiceTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -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.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.issue.workflow.FunctionExecutor; -import org.sonar.server.issue.workflow.IssueWorkflow; -import org.sonar.server.issue.workflow.Transition; -import org.sonar.server.tester.UserSessionRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.issue.Issue.STATUS_CONFIRMED; -import static org.sonar.api.issue.Issue.STATUS_OPEN; -import static org.sonar.api.rules.RuleType.CODE_SMELL; -import static org.sonar.api.web.UserRole.ISSUE_ADMIN; -import static org.sonar.db.component.ComponentTesting.newFileDto; - -public class TransitionServiceTest { - - @Rule - public DbTester db = DbTester.create(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private IssueFieldsSetter updater = new IssueFieldsSetter(); - private IssueWorkflow workflow = new IssueWorkflow(new FunctionExecutor(updater), updater); - - private TransitionService underTest = new TransitionService(userSession, workflow); - - @Before - public void setUp() throws Exception { - workflow.start(); - } - - @Test - public void list_transitions() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto rule = db.rules().insert(); - IssueDto issue = db.issues().insert(rule, project, file, i -> i.setStatus(STATUS_OPEN).setResolution(null).setType(CODE_SMELL)); - userSession.logIn().addProjectPermission(ISSUE_ADMIN, project); - - List<Transition> result = underTest.listTransitions(issue.toDefaultIssue()); - - assertThat(result).extracting(Transition::key).containsOnly("confirm", "resolve", "falsepositive", "wontfix"); - } - - @Test - public void list_transitions_returns_empty_list_on_external_issue() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto externalRule = db.rules().insert(r -> r.setIsExternal(true)); - IssueDto externalIssue = db.issues().insert(externalRule, project, file, i -> i.setStatus(STATUS_OPEN).setResolution(null).setType(CODE_SMELL)); - userSession.logIn().addProjectPermission(ISSUE_ADMIN, project); - - List<Transition> result = underTest.listTransitions(externalIssue.toDefaultIssue()); - - assertThat(result).isEmpty(); - } - - @Test - public void list_transitions_returns_only_transitions_that_do_not_requires_issue_admin_permission() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto rule = db.rules().insert(); - IssueDto issue = db.issues().insert(rule, project, file, i -> i.setStatus(STATUS_OPEN).setResolution(null).setType(CODE_SMELL)); - userSession.logIn(); - - List<Transition> result = underTest.listTransitions(issue.toDefaultIssue()); - - assertThat(result).extracting(Transition::key).containsOnly("confirm"); - } - - @Test - public void list_transitions_returns_nothing_when_not_logged() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto rule = db.rules().insert(); - IssueDto issue = db.issues().insert(rule, project, file, i -> i.setStatus(STATUS_OPEN).setResolution(null).setType(CODE_SMELL)); - - List<Transition> result = underTest.listTransitions(issue.toDefaultIssue()); - - assertThat(result).isEmpty(); - } - - @Test - public void do_transition() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto rule = db.rules().insert(); - IssueDto issue = db.issues().insert(rule, project, file, i -> i.setStatus(STATUS_OPEN).setResolution(null).setType(CODE_SMELL)); - - DefaultIssue defaultIssue = issue.toDefaultIssue(); - boolean result = underTest.doTransition(defaultIssue, IssueChangeContext.createUser(new Date(), "user_uuid"), "confirm"); - - assertThat(result).isTrue(); - assertThat(defaultIssue.status()).isEqualTo(STATUS_CONFIRMED); - } - - @Test - public void do_transition_fail_on_external_issue() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto externalRule = db.rules().insert(r -> r.setIsExternal(true)); - IssueDto externalIssue = db.issues().insert(externalRule, project, file, i -> i.setStatus(STATUS_OPEN).setResolution(null).setType(CODE_SMELL)); - DefaultIssue defaultIssue = externalIssue.toDefaultIssue(); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Transition is not allowed on issues imported from external rule engines"); - - underTest.doTransition(defaultIssue, IssueChangeContext.createUser(new Date(), "user_uuid"), "confirm"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/WebIssueStorageTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/WebIssueStorageTest.java deleted file mode 100644 index f103c91017e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/WebIssueStorageTest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.issue; - -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import org.junit.Test; -import org.sonar.api.rules.RuleType; -import org.sonar.api.utils.DateUtils; -import org.sonar.api.utils.Duration; -import org.sonar.api.utils.System2; -import org.sonar.api.impl.utils.TestSystem2; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.DefaultIssueComment; -import org.sonar.core.issue.IssueChangeContext; -import org.sonar.db.DbClient; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.organization.TestDefaultOrganizationProvider; -import org.sonar.server.rule.DefaultRuleFinder; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.sonar.api.rule.RuleStatus.REMOVED; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.component.ComponentTesting.newModuleDto; -import static org.sonar.db.issue.IssueTesting.newIssue; - -public class WebIssueStorageTest { - - private System2 system2 = new TestSystem2().setNow(2_000_000_000L); - - @org.junit.Rule - public DbTester db = DbTester.create(system2); - - private DbClient dbClient = db.getDbClient(); - - private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - - private IssueIndexer issueIndexer = mock(IssueIndexer.class); - private WebIssueStorage underTest = new WebIssueStorage(system2, dbClient, new DefaultRuleFinder(db.getDbClient(), defaultOrganizationProvider), issueIndexer); - - @Test - public void load_component_id_from_db() { - OrganizationDto organizationDto = db.organizations().insert(); - ComponentDto project = db.components().insertPrivateProject(organizationDto); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - - long componentId = underTest.component(db.getSession(), new DefaultIssue().setComponentUuid(file.uuid())).getId(); - - assertThat(componentId).isEqualTo(file.getId()); - } - - @Test - public void load_project_id_from_db() { - OrganizationDto organizationDto = db.organizations().insert(); - ComponentDto project = db.components().insertPrivateProject(organizationDto); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - - long projectId = underTest.project(db.getSession(), new DefaultIssue().setProjectUuid(project.uuid())).getId(); - - assertThat(projectId).isEqualTo(project.getId()); - } - - @Test - public void insert_new_issues() { - RuleDefinitionDto rule = db.rules().insert(); - ComponentDto project = db.components().insertMainBranch(); - ComponentDto module = db.components().insertComponent(newModuleDto(project)); - ComponentDto file = db.components().insertComponent(newFileDto(module)); - - String issueKey = "ABCDE"; - DefaultIssueComment comment = DefaultIssueComment.create(issueKey, "user_uuid", "the comment"); - // override generated key - comment.setKey("FGHIJ"); - - Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); - DefaultIssue issue = new DefaultIssue() - .setKey(issueKey) - .setType(RuleType.BUG) - .setNew(true) - .setRuleKey(rule.getKey()) - .setProjectUuid(project.uuid()) - .setComponentUuid(file.uuid()) - .setLine(5000) - .setEffort(Duration.create(10L)) - .setResolution("OPEN") - .setStatus("OPEN") - .setSeverity("BLOCKER") - .setAttribute("foo", "bar") - .addComment(comment) - .setCreationDate(date) - .setUpdateDate(date) - .setCloseDate(date); - - underTest.save(db.getSession(), singletonList(issue)); - - assertThat(db.countRowsOfTable("issues")).isEqualTo(1); - assertThat(db.selectFirst("select * from issues")) - .containsEntry("PROJECT_UUID", project.uuid()) - .containsEntry("COMPONENT_UUID", file.uuid()) - .containsEntry("KEE", issue.key()) - .containsEntry("RESOLUTION", issue.resolution()) - .containsEntry("STATUS", issue.status()) - .containsEntry("SEVERITY", issue.severity()); - - assertThat(db.countRowsOfTable("issue_changes")).isEqualTo(1); - assertThat(db.selectFirst("select * from issue_changes")) - .containsEntry("KEE", comment.key()) - .containsEntry("ISSUE_KEY", issue.key()) - .containsEntry("CHANGE_DATA", comment.markdownText()) - .containsEntry("USER_LOGIN", comment.userUuid()); - } - - @Test - public void update_issues() { - RuleDefinitionDto rule = db.rules().insert(); - ComponentDto project = db.components().insertMainBranch(); - ComponentDto module = db.components().insertComponent(newModuleDto(project)); - ComponentDto file = db.components().insertComponent(newFileDto(module)); - - Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); - DefaultIssue issue = new DefaultIssue() - .setKey("ABCDE") - .setType(RuleType.BUG) - .setNew(true) - .setRuleKey(rule.getKey()) - .setProjectUuid(project.uuid()) - .setComponentUuid(file.uuid()) - .setLine(5000) - .setEffort(Duration.create(10L)) - .setResolution("OPEN") - .setStatus("OPEN") - .setSeverity("BLOCKER") - .setAttribute("foo", "bar") - .setCreationDate(date) - .setUpdateDate(date) - .setCloseDate(date); - - underTest.save(db.getSession(), singletonList(issue)); - - assertThat(db.countRowsOfTable("issues")).isEqualTo(1); - assertThat(db.countRowsOfTable("issue_changes")).isEqualTo(0); - - DefaultIssue updated = new DefaultIssue() - .setKey(issue.key()) - .setType(RuleType.VULNERABILITY) - .setNew(false) - .setChanged(true) - - // updated fields - .setLine(issue.getLine() + 10) - .setProjectUuid("foo") - .setEffort(Duration.create(issue.effortInMinutes() + 10L)) - .setChecksum("FFFFF") - .setAuthorLogin("simon") - .setAssigneeUuid("loic") - .setFieldChange(IssueChangeContext.createUser(new Date(), "user_uuid"), "severity", "INFO", "BLOCKER") - .addComment(DefaultIssueComment.create("ABCDE", "user_uuid", "the comment")) - .setResolution("FIXED") - .setStatus("RESOLVED") - .setSeverity("MAJOR") - .setAttribute("fox", "bax") - .setCreationDate(DateUtils.addDays(date, 1)) - .setUpdateDate(DateUtils.addDays(date, 1)) - .setCloseDate(DateUtils.addDays(date, 1)) - - // unmodifiable fields - .setRuleKey(rule.getKey()) - .setComponentKey("struts:Action") - .setProjectKey("struts"); - - underTest.save(db.getSession(), singletonList(updated)); - - assertThat(db.countRowsOfTable("issues")).isEqualTo(1); - assertThat(db.selectFirst("select * from issues")) - .containsEntry("ASSIGNEE", updated.assignee()) - .containsEntry("AUTHOR_LOGIN", updated.authorLogin()) - .containsEntry("CHECKSUM", updated.checksum()) - .containsEntry("COMPONENT_UUID", issue.componentUuid()) - .containsEntry("EFFORT", updated.effortInMinutes()) - .containsEntry("ISSUE_ATTRIBUTES", "fox=bax") - .containsEntry("ISSUE_TYPE", 3) - .containsEntry("KEE", issue.key()) - .containsEntry("LINE", (long) updated.line()) - .containsEntry("PROJECT_UUID", updated.projectUuid()) - .containsEntry("RESOLUTION", updated.resolution()) - .containsEntry("STATUS", updated.status()) - .containsEntry("SEVERITY", updated.severity()); - - List<Map<String, Object>> rows = db.select("select * from issue_changes order by id"); - assertThat(rows).hasSize(2); - assertThat(rows.get(0)) - .extracting("CHANGE_DATA", "CHANGE_TYPE", "USER_LOGIN") - .containsExactlyInAnyOrder("the comment", "comment", "user_uuid"); - assertThat(rows.get(1)) - .extracting("CHANGE_DATA", "CHANGE_TYPE", "USER_LOGIN") - .containsExactlyInAnyOrder("severity=INFO|BLOCKER", "diff", "user_uuid"); - } - - @Test - public void rule_id_is_set_on_updated_issue() { - RuleDefinitionDto rule = db.rules().insert(); - ComponentDto project = db.components().insertMainBranch(); - ComponentDto module = db.components().insertComponent(newModuleDto(project)); - ComponentDto file = db.components().insertComponent(newFileDto(module)); - DefaultIssue issue = newIssue(rule, project, file).toDefaultIssue(); - - Collection<IssueDto> results = underTest.save(db.getSession(), singletonList(issue)); - - assertThat(results).hasSize(1); - assertThat(results.iterator().next().getRuleId()).isEqualTo(rule.getId()); - } - - @Test - public void rule_id_is_not_set_on_updated_issue_when_rule_is_removed() { - RuleDefinitionDto rule = db.rules().insert(r -> r.setStatus(REMOVED)); - ComponentDto project = db.components().insertMainBranch(); - ComponentDto module = db.components().insertComponent(newModuleDto(project)); - ComponentDto file = db.components().insertComponent(newFileDto(module)); - DefaultIssue issue = newIssue(rule, project, file).toDefaultIssue(); - - Collection<IssueDto> results = underTest.save(db.getSession(), singletonList(issue)); - - assertThat(results).hasSize(1); - assertThat(results.iterator().next().getRuleId()).isNull(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/IssueMetricFormulaFactoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/IssueMetricFormulaFactoryImplTest.java deleted file mode 100644 index 5051f4305f7..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/IssueMetricFormulaFactoryImplTest.java +++ /dev/null @@ -1,879 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.issue.Issue; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.rule.Severity; -import org.sonar.api.rules.RuleType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueGroupDto; -import org.sonar.server.measure.DebtRatingGrid; -import org.sonar.server.measure.Rating; - -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; - -public class IssueMetricFormulaFactoryImplTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private IssueMetricFormulaFactoryImpl underTest = new IssueMetricFormulaFactoryImpl(); - - @Test - public void getFormulaMetrics_include_the_dependent_metrics() { - for (IssueMetricFormula formula : underTest.getFormulas()) { - assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric()); - for (Metric dependentMetric : formula.getDependentMetrics()) { - assertThat(underTest.getFormulaMetrics()).contains(dependentMetric); - } - } - } - - @Test - public void test_violations() { - withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0); - with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5); - - // exclude resolved - IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED); - with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2); - - // include issues on leak - IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true); - with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11); - } - - @Test - public void test_bugs() { - withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0); - with( - newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5), - // exclude resolved - newResolvedGroup(RuleType.BUG).setCount(7), - // not bugs - newGroup(RuleType.CODE_SMELL).setCount(11)) - .assertThatValueIs(CoreMetrics.BUGS, 3 + 5); - } - - @Test - public void test_code_smells() { - withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0); - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5), - // exclude resolved - newResolvedGroup(RuleType.CODE_SMELL).setCount(7), - // not code smells - newGroup(RuleType.BUG).setCount(11)) - .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5); - } - - @Test - public void test_vulnerabilities() { - withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0); - with( - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5), - // exclude resolved - newResolvedGroup(RuleType.VULNERABILITY).setCount(7), - // not vulnerabilities - newGroup(RuleType.BUG).setCount(11)) - .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5); - } - - @Test - public void test_security_hotspots() { - withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0); - with( - newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5), - // exclude resolved - newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7), - // not hotspots - newGroup(RuleType.BUG).setCount(11)) - .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5); - } - - @Test - public void test_security_review_rating() { - withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REVIEW_RATING, Rating.A); - - with(CoreMetrics.SECURITY_HOTSPOTS, 12.0) - .and(CoreMetrics.NCLOC, 1000.0) - .assertThatValueIs(CoreMetrics.SECURITY_REVIEW_RATING, Rating.C); - } - - @Test - public void count_unresolved_by_severity() { - withNoIssues() - .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0) - .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0) - .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0) - .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0) - .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0); - - with( - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5), - newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7), - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11), - // exclude security hotspot - newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15), - // include leak - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13), - // exclude resolved - newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17), - newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19), - newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21)) - .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13) - .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7) - .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5) - .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0) - .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0); - } - - @Test - public void count_resolved() { - withNoIssues() - .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0) - .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 0); - - with( - newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3), - newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5), - newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7), - newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11), - newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13), - // exclude security hotspot - newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()), - // exclude unresolved - newGroup(RuleType.VULNERABILITY).setCount(17), - newGroup(RuleType.BUG).setCount(19)) - .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5) - .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 7 + 11); - } - - @Test - public void count_by_status() { - withNoIssues() - .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0) - .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0) - .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0); - - with( - newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3), - newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5), - newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7), - newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9), - newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11), - // exclude security hotspot - newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12), - newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13)) - .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5) - .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11) - .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7); - } - - @Test - public void test_technical_debt() { - withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0); - - with( - newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false), - newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true), - // exclude security hotspot - newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true), - newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false), - // not code smells - newGroup(RuleType.BUG).setEffort(7.0), - // exclude resolved - newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0)) - .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0); - } - - @Test - public void test_reliability_remediation_effort() { - withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0); - - with( - newGroup(RuleType.BUG).setEffort(3.0), - newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER), - // not bugs - newGroup(RuleType.CODE_SMELL).setEffort(7.0), - // exclude resolved - newResolvedGroup(RuleType.BUG).setEffort(17.0)) - .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0); - } - - @Test - public void test_security_remediation_effort() { - withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0); - - with( - newGroup(RuleType.VULNERABILITY).setEffort(3.0), - newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER), - // not vulnerability - newGroup(RuleType.CODE_SMELL).setEffort(7.0), - // exclude resolved - newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0)) - .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0); - } - - @Test - public void test_sqale_debt_ratio_and_sqale_rating() { - withNoIssues() - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - // technical_debt not computed - with(CoreMetrics.DEVELOPMENT_COST, 0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - with(CoreMetrics.DEVELOPMENT_COST, 20) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - // development_cost not computed - with(CoreMetrics.TECHNICAL_DEBT, 0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - with(CoreMetrics.TECHNICAL_DEBT, 20) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - // input measures are available - with(CoreMetrics.TECHNICAL_DEBT, 20.0) - .and(CoreMetrics.DEVELOPMENT_COST, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - with(CoreMetrics.TECHNICAL_DEBT, 20.0) - .and(CoreMetrics.DEVELOPMENT_COST, 160.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 12.5) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.C); - - with(CoreMetrics.TECHNICAL_DEBT, 20.0) - .and(CoreMetrics.DEVELOPMENT_COST, 10.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 200.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.E); - - // A is 5% --> min debt is exactly 200*0.05=10 - with(CoreMetrics.DEVELOPMENT_COST, 200.0) - .and(CoreMetrics.TECHNICAL_DEBT, 10.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 5.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - with(CoreMetrics.TECHNICAL_DEBT, 0.0) - .and(CoreMetrics.DEVELOPMENT_COST, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - with(CoreMetrics.TECHNICAL_DEBT, 0.0) - .and(CoreMetrics.DEVELOPMENT_COST, 80.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0); - - with(CoreMetrics.TECHNICAL_DEBT, -20.0) - .and(CoreMetrics.DEVELOPMENT_COST, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - // bug, debt can't be negative - with(CoreMetrics.TECHNICAL_DEBT, -20.0) - .and(CoreMetrics.DEVELOPMENT_COST, 80.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - - // bug, cost can't be negative - with(CoreMetrics.TECHNICAL_DEBT, 20.0) - .and(CoreMetrics.DEVELOPMENT_COST, -80.0) - .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0) - .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); - } - - @Test - public void test_effort_to_reach_maintainability_rating_A() { - withNoIssues() - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); - - // technical_debt not computed - with(CoreMetrics.DEVELOPMENT_COST, 0.0) - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); - with(CoreMetrics.DEVELOPMENT_COST, 20.0) - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); - - // development_cost not computed - with(CoreMetrics.TECHNICAL_DEBT, 0.0) - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); - with(CoreMetrics.TECHNICAL_DEBT, 20.0) - // development cost is considered as zero, so the effort is to reach... zero - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 20.0); - - // B to A - with(CoreMetrics.DEVELOPMENT_COST, 200.0) - .and(CoreMetrics.TECHNICAL_DEBT, 40.0) - // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30 - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 40.0 - (200.0 * 0.05)); - - // E to A - with(CoreMetrics.DEVELOPMENT_COST, 200.0) - .and(CoreMetrics.TECHNICAL_DEBT, 180.0) - // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170 - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 180.0 - (200.0 * 0.05)); - - // already A - with(CoreMetrics.DEVELOPMENT_COST, 200.0) - .and(CoreMetrics.TECHNICAL_DEBT, 8.0) - // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); - - // exactly lower range of B - with(CoreMetrics.DEVELOPMENT_COST, 200.0) - .and(CoreMetrics.TECHNICAL_DEBT, 10.0) - // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero - // FIXME need zero to reach A but effective rating is B ! - .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); - } - - @Test - public void test_reliability_rating() { - withNoIssues() - .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A); - - with( - newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1), - newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5), - // excluded, not a bug - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3)) - // highest severity of bugs is CRITICAL --> D - .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5)) - // no bugs --> A - .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A); - } - - @Test - public void test_security_rating() { - withNoIssues() - .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A); - - with( - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5), - // excluded, not a vulnerability - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3)) - // highest severity of vulnerabilities is CRITICAL --> D - .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5)) - // no vulnerabilities --> A - .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A); - } - - @Test - public void test_new_bugs() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0); - - with( - newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5), - newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7), - // not bugs - newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9), - newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11)) - .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7); - } - - @Test - public void test_new_code_smells() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5), - newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7), - // not code smells - newGroup(RuleType.BUG).setInLeak(true).setCount(9), - newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11)) - .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7); - } - - @Test - public void test_new_vulnerabilities() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0); - - with( - newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5), - newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7), - // not vulnerabilities - newGroup(RuleType.BUG).setInLeak(true).setCount(9), - newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11)) - .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7); - } - - @Test - public void test_new_security_hotspots() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0.0); - - with( - newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3), - newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5), - newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7), - // not hotspots - newGroup(RuleType.BUG).setInLeak(true).setCount(9), - newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11)) - .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7); - } - - @Test - public void test_new_violations() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0); - - with( - newGroup(RuleType.BUG).setInLeak(true).setCount(5), - newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7), - newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9), - // not in leak - newGroup(RuleType.BUG).setInLeak(false).setCount(11), - newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13), - newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17)) - .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9); - } - - @Test - public void test_new_blocker_violations() { - withNoIssues() - .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7), - // not blocker - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9), - // not in leak - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11), - newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13)) - .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7); - } - - @Test - public void test_new_critical_violations() { - withNoIssues() - .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7), - // not CRITICAL - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9), - // not in leak - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11), - newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13)) - .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7); - } - - @Test - public void test_new_major_violations() { - withNoIssues() - .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7), - // not MAJOR - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9), - // not in leak - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11), - newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13)) - .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7); - } - - @Test - public void test_new_minor_violations() { - withNoIssues() - .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7), - // not MINOR - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9), - // not in leak - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11), - newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13)) - .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7); - } - - @Test - public void test_new_info_violations() { - withNoIssues() - .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3), - newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7), - // not INFO - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9), - // not in leak - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11), - newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13)) - .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7); - } - - @Test - public void test_new_technical_debt() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0); - - with( - newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true), - // not in leak - newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false), - // not code smells - newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true), - newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true), - // exclude resolved - newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true)) - .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0); - } - - @Test - public void test_new_reliability_remediation_effort() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0); - - with( - newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true), - // not in leak - newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false), - // not bugs - newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true), - // exclude resolved - newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true)) - .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0); - } - - @Test - public void test_new_security_remediation_effort() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0); - - with( - newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true), - // not in leak - newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false), - // not vulnerability - newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true), - // exclude resolved - newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true)) - .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0); - } - - @Test - public void test_new_reliability_rating() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A); - - with( - newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true), - newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true), - // not in leak - newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false), - // not bug - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true), - // exclude resolved - newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true)) - // highest severity of bugs on leak period is minor -> B - .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B); - } - - @Test - public void test_new_security_rating() { - withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A); - - with( - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true), - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true), - // not in leak - newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false), - // not vulnerability - newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true), - // exclude resolved - newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true)) - // highest severity of bugs on leak period is minor -> B - .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B); - } - - @Test - public void test_new_sqale_debt_ratio_and_new_maintainability_rating() { - withNoIssues() - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - // technical_debt not computed - withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 20) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - // development_cost not computed - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - // input measures are available - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 12.5) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.C); - - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 200.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.E); - - // A is 5% --> min debt is exactly 200*0.05=10 - withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0) - .andLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 10.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 5.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0); - - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - // bug, debt can't be negative - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - - // bug, cost can't be negative - withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0) - .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0) - .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0) - .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); - } - - private Verifier with(IssueGroupDto... groups) { - return new Verifier(groups); - } - - private Verifier withNoIssues() { - return new Verifier(new IssueGroupDto[0]); - } - - private Verifier with(Metric metric, double value) { - return new Verifier(new IssueGroupDto[0]).and(metric, value); - } - - private Verifier withLeak(Metric metric, double leakValue) { - return new Verifier(new IssueGroupDto[0]).andLeak(metric, leakValue); - } - - private class Verifier { - private final IssueGroupDto[] groups; - private final Map<Metric, Double> values = new HashMap<>(); - private final Map<Metric, Double> leakValues = new HashMap<>(); - - private Verifier(IssueGroupDto[] groups) { - this.groups = groups; - } - - Verifier and(Metric metric, double value) { - this.values.put(metric, value); - return this; - } - - Verifier andLeak(Metric metric, double value) { - this.leakValues.put(metric, value); - return this; - } - - Verifier assertThatValueIs(Metric metric, double expectedValue) { - TestContext context = run(metric, false); - assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue); - return this; - } - - Verifier assertThatLeakValueIs(Metric metric, double expectedValue) { - TestContext context = run(metric, true); - assertThat(context.doubleLeakValue).isNotNull().isEqualTo(expectedValue); - return this; - } - - Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) { - TestContext context = run(metric, true); - assertThat(context.ratingLeakValue).isNotNull().isEqualTo(expectedRating); - return this; - } - - Verifier assertThatValueIs(Metric metric, Rating expectedValue) { - TestContext context = run(metric, false); - assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue); - return this; - } - - private TestContext run(Metric metric, boolean expectLeakFormula) { - IssueMetricFormula formula = underTest.getFormulas().stream() - .filter(f -> f.getMetric().getKey().equals(metric.getKey())) - .findFirst() - .get(); - assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula); - TestContext context = new TestContext(formula.getDependentMetrics(), values, leakValues); - formula.compute(context, newIssueCounter(groups)); - return context; - } - } - - private static IssueCounter newIssueCounter(IssueGroupDto... issues) { - return new IssueCounter(asList(issues)); - } - - private static IssueGroupDto newGroup() { - return newGroup(RuleType.CODE_SMELL); - } - - private static IssueGroupDto newGroup(RuleType ruleType) { - IssueGroupDto dto = new IssueGroupDto(); - // set non-null fields - dto.setRuleType(ruleType.getDbConstant()); - dto.setCount(1); - dto.setEffort(0.0); - dto.setSeverity(Severity.INFO); - dto.setStatus(Issue.STATUS_OPEN); - dto.setInLeak(false); - return dto; - } - - private static IssueGroupDto newResolvedGroup(RuleType ruleType) { - return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED); - } - - private static IssueGroupDto newResolvedGroup(String resolution, String status) { - return newGroup().setResolution(resolution).setStatus(status); - } - - private static class TestContext implements IssueMetricFormula.Context { - private final Set<Metric> dependentMetrics; - private Double doubleValue; - private Rating ratingValue; - private Double doubleLeakValue; - private Rating ratingLeakValue; - private final Map<Metric, Double> values; - private final Map<Metric, Double> leakValues; - - private TestContext(Collection<Metric> dependentMetrics, Map<Metric, Double> values, Map<Metric, Double> leakValues) { - this.dependentMetrics = new HashSet<>(dependentMetrics); - this.values = values; - this.leakValues = leakValues; - } - - @Override - public ComponentDto getComponent() { - throw new UnsupportedOperationException(); - } - - @Override - public DebtRatingGrid getDebtRatingGrid() { - return new DebtRatingGrid(new double[] {0.05, 0.1, 0.2, 0.5}); - } - - @Override - public Optional<Double> getValue(Metric metric) { - if (!dependentMetrics.contains(metric)) { - throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency"); - } - if (values.containsKey(metric)) { - return Optional.of(values.get(metric)); - } - return Optional.empty(); - } - - @Override - public Optional<Double> getLeakValue(Metric metric) { - if (!dependentMetrics.contains(metric)) { - throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency"); - } - if (leakValues.containsKey(metric)) { - return Optional.of(leakValues.get(metric)); - } - return Optional.empty(); - } - - @Override - public void setValue(double value) { - this.doubleValue = value; - } - - @Override - public void setValue(Rating value) { - this.ratingValue = value; - } - - @Override - public void setLeakValue(double value) { - this.doubleLeakValue = value; - } - - @Override - public void setLeakValue(Rating value) { - this.ratingLeakValue = value; - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java deleted file mode 100644 index df8fff10315..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java +++ /dev/null @@ -1,507 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import javax.annotation.Nullable; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.sonar.api.config.PropertyDefinitions; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Qualifiers; -import org.sonar.core.config.CorePropertyDefinitions; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.measure.LiveMeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.es.ProjectIndexer; -import org.sonar.server.es.TestProjectIndexers; -import org.sonar.server.measure.Rating; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.QualityGate; -import org.sonar.server.qualitygate.changeevent.QGChangeEvent; -import org.sonar.server.settings.ProjectConfigurationLoader; -import org.sonar.server.settings.TestProjectConfigurationLoader; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.api.resources.Qualifiers.ORDERED_BOTTOM_UP; - -@RunWith(DataProviderRunner.class) -public class LiveMeasureComputerImplTest { - - @Rule - public DbTester db = DbTester.create(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private TestProjectIndexers projectIndexer = new TestProjectIndexers(); - private MetricDto intMetric; - private MetricDto ratingMetric; - private MetricDto alertStatusMetric; - private OrganizationDto organization; - private ComponentDto project; - private ComponentDto dir; - private ComponentDto file1; - private ComponentDto file2; - private ComponentDto branch; - private ComponentDto branchFile; - private LiveQualityGateComputer qGateComputer = mock(LiveQualityGateComputer.class); - private QualityGate qualityGate = mock(QualityGate.class); - private EvaluatedQualityGate newQualityGate = mock(EvaluatedQualityGate.class); - - @Before - public void setUp() throws Exception { - intMetric = db.measures().insertMetric(m -> m.setValueType(Metric.ValueType.INT.name())); - ratingMetric = db.measures().insertMetric(m -> m.setValueType(Metric.ValueType.RATING.name())); - alertStatusMetric = db.measures().insertMetric(m -> m.setKey(CoreMetrics.ALERT_STATUS_KEY)); - organization = db.organizations().insert(); - project = db.components().insertMainBranch(organization); - dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java")); - file1 = db.components().insertComponent(ComponentTesting.newFileDto(project, dir)); - file2 = db.components().insertComponent(ComponentTesting.newFileDto(project, dir)); - branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST)); - branchFile = db.components().insertComponent(ComponentTesting.newFileDto(branch)); - } - - @Test - public void compute_and_insert_measures_if_they_do_not_exist_yet() { - markProjectAsAnalyzed(project); - - List<QGChangeEvent> result = run(asList(file1, file2), newQualifierBasedIntFormula(), newRatingConstantFormula(Rating.C)); - - // 2 measures per component have been created - // Numeric value depends on qualifier (see newQualifierBasedIntFormula()) - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(8); - assertThatIntMeasureHasValue(file1, ORDERED_BOTTOM_UP.indexOf(Qualifiers.FILE)); - assertThatRatingMeasureHasValue(file1, Rating.C); - assertThatIntMeasureHasValue(file2, ORDERED_BOTTOM_UP.indexOf(Qualifiers.FILE)); - assertThatRatingMeasureHasValue(file2, Rating.C); - assertThatIntMeasureHasValue(dir, ORDERED_BOTTOM_UP.indexOf(Qualifiers.DIRECTORY)); - assertThatRatingMeasureHasValue(dir, Rating.C); - assertThatIntMeasureHasValue(project, ORDERED_BOTTOM_UP.indexOf(Qualifiers.PROJECT)); - assertThatRatingMeasureHasValue(project, Rating.C); - assertThatProjectChanged(result, project); - } - - @Test - public void compute_and_update_measures_if_they_already_exist() { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, intMetric, m -> m.setValue(42.0)); - db.measures().insertLiveMeasure(dir, intMetric, m -> m.setValue(42.0)); - db.measures().insertLiveMeasure(file1, intMetric, m -> m.setValue(42.0)); - db.measures().insertLiveMeasure(file2, intMetric, m -> m.setValue(42.0)); - - // generates values 1, 2, 3 - List<QGChangeEvent> result = run(file1, newQualifierBasedIntFormula()); - - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(4); - assertThatProjectChanged(result, project); - - // Numeric value depends on qualifier (see newQualifierBasedIntFormula()) - assertThatIntMeasureHasValue(file1, ORDERED_BOTTOM_UP.indexOf(Qualifiers.FILE)); - assertThatIntMeasureHasValue(dir, ORDERED_BOTTOM_UP.indexOf(Qualifiers.DIRECTORY)); - assertThatIntMeasureHasValue(project, ORDERED_BOTTOM_UP.indexOf(Qualifiers.PROJECT)); - // untouched - assertThatIntMeasureHasValue(file2, 42.0); - } - - @Test - public void variation_is_refreshed_when_int_value_is_changed() { - markProjectAsAnalyzed(project); - // value is: - // 42 on last analysis - // 42-12=30 on beginning of leak period - db.measures().insertLiveMeasure(project, intMetric, m -> m.setValue(42.0).setVariation(12.0)); - - // new value is 44, so variation on leak period is 44-30=14 - List<QGChangeEvent> result = run(file1, newIntConstantFormula(44.0)); - - LiveMeasureDto measure = assertThatIntMeasureHasValue(project, 44.0); - assertThat(measure.getVariation()).isEqualTo(14.0); - assertThatProjectChanged(result, project); - } - - @Test - public void variation_is_refreshed_when_rating_value_is_changed() { - markProjectAsAnalyzed(project); - // value is: - // B on last analysis - // D on beginning of leak period --> variation is -2 - db.measures().insertLiveMeasure(project, ratingMetric, m -> m.setValue((double) Rating.B.getIndex()).setData("B").setVariation(-2.0)); - - // new value is C, so variation on leak period is D to C = -1 - List<QGChangeEvent> result = run(file1, newRatingConstantFormula(Rating.C)); - - LiveMeasureDto measure = assertThatRatingMeasureHasValue(project, Rating.C); - assertThat(measure.getVariation()).isEqualTo(-1.0); - assertThatProjectChanged(result, project); - } - - @Test - public void variation_does_not_change_if_rating_value_does_not_change() { - markProjectAsAnalyzed(project); - // value is: - // B on last analysis - // D on beginning of leak period --> variation is -2 - db.measures().insertLiveMeasure(project, ratingMetric, m -> m.setValue((double) Rating.B.getIndex()).setData("B").setVariation(-2.0)); - - // new value is still B, so variation on leak period is still -2 - List<QGChangeEvent> result = run(file1, newRatingConstantFormula(Rating.B)); - - LiveMeasureDto measure = assertThatRatingMeasureHasValue(project, Rating.B); - assertThat(measure.getVariation()).isEqualTo(-2.0); - assertThatProjectChanged(result, project); - } - - @Test - public void refresh_leak_measures() { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, intMetric, m -> m.setVariation(42.0).setValue(null)); - db.measures().insertLiveMeasure(project, ratingMetric, m -> m.setVariation((double) Rating.E.getIndex())); - db.measures().insertLiveMeasure(dir, intMetric, m -> m.setVariation(42.0).setValue(null)); - db.measures().insertLiveMeasure(dir, ratingMetric, m -> m.setVariation((double) Rating.D.getIndex())); - db.measures().insertLiveMeasure(file1, intMetric, m -> m.setVariation(42.0).setValue(null)); - db.measures().insertLiveMeasure(file1, ratingMetric, m -> m.setVariation((double) Rating.C.getIndex())); - - // generates values 1, 2, 3 on leak measures - List<QGChangeEvent> result = run(file1, newQualifierBasedIntLeakFormula(), newRatingLeakFormula(Rating.B)); - - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(6); - - // Numeric value depends on qualifier (see newQualifierBasedIntLeakFormula()) - assertThatIntMeasureHasLeakValue(file1, ORDERED_BOTTOM_UP.indexOf(Qualifiers.FILE)); - assertThatRatingMeasureHasLeakValue(file1, Rating.B); - assertThatIntMeasureHasLeakValue(dir, ORDERED_BOTTOM_UP.indexOf(Qualifiers.DIRECTORY)); - assertThatRatingMeasureHasLeakValue(dir, Rating.B); - assertThatIntMeasureHasLeakValue(project, ORDERED_BOTTOM_UP.indexOf(Qualifiers.PROJECT)); - assertThatRatingMeasureHasLeakValue(project, Rating.B); - assertThatProjectChanged(result, project); - } - - @Test - public void calculate_new_metrics_if_it_is_pr_or_branch() { - markProjectAsAnalyzed(branch, null); - db.measures().insertLiveMeasure(branch, intMetric, m -> m.setVariation(42.0).setValue(null)); - db.measures().insertLiveMeasure(branchFile, intMetric, m -> m.setVariation(42.0).setValue(null)); - - // generates values 1, 2, 3 on leak measures - List<QGChangeEvent> result = run(branchFile, newQualifierBasedIntLeakFormula(), newRatingLeakFormula(Rating.B)); - - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(4); - - // Numeric value depends on qualifier (see newQualifierBasedIntLeakFormula()) - assertThatIntMeasureHasLeakValue(branchFile, ORDERED_BOTTOM_UP.indexOf(Qualifiers.FILE)); - assertThatRatingMeasureHasLeakValue(branchFile, Rating.B); - assertThatIntMeasureHasLeakValue(branch, ORDERED_BOTTOM_UP.indexOf(Qualifiers.PROJECT)); - assertThatRatingMeasureHasLeakValue(branch, Rating.B); - assertThatProjectChanged(result, branch); - } - - @Test - public void do_nothing_if_project_has_not_been_analyzed() { - // project has no snapshots - List<QGChangeEvent> result = run(file1, newIncrementalFormula()); - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(0); - assertThatProjectNotChanged(result, project); - } - - @Test - public void do_nothing_if_input_components_are_empty() { - List<QGChangeEvent> result = run(emptyList(), newIncrementalFormula()); - - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(0); - assertThatProjectNotChanged(result, project); - } - - @Test - public void refresh_multiple_projects_at_the_same_time() { - markProjectAsAnalyzed(project); - ComponentDto project2 = db.components().insertMainBranch(); - ComponentDto fileInProject2 = db.components().insertComponent(ComponentTesting.newFileDto(project2)); - markProjectAsAnalyzed(project2); - - List<QGChangeEvent> result = run(asList(file1, fileInProject2), newQualifierBasedIntFormula()); - - // generated values depend on position of qualifier in Qualifiers.ORDERED_BOTTOM_UP (see formula) - assertThatIntMeasureHasValue(file1, 0); - assertThatIntMeasureHasValue(dir, 2); - assertThatIntMeasureHasValue(project, 4); - assertThatIntMeasureHasValue(fileInProject2, 0); - assertThatIntMeasureHasValue(project2, 4); - - // no other measures generated - assertThat(db.countRowsOfTable(db.getSession(), "live_measures")).isEqualTo(5); - assertThatProjectChanged(result, project, project2); - } - - @Test - public void refresh_multiple_branches_at_the_same_time() { - // FIXME - } - - @Test - public void event_contains_no_previousStatus_if_measure_does_not_exist() { - markProjectAsAnalyzed(project); - - List<QGChangeEvent> result = run(file1); - - assertThat(result) - .extracting(QGChangeEvent::getPreviousStatus) - .containsExactly(Optional.empty()); - } - - @Test - public void event_contains_no_previousStatus_if_measure_exists_and_has_no_value() { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, alertStatusMetric, m -> m.setData((String) null)); - - List<QGChangeEvent> result = run(file1); - - assertThat(result) - .extracting(QGChangeEvent::getPreviousStatus) - .containsExactly(Optional.empty()); - } - - @Test - public void event_contains_no_previousStatus_if_measure_exists_and_is_empty() { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, alertStatusMetric, m -> m.setData("")); - - List<QGChangeEvent> result = run(file1); - - assertThat(result) - .extracting(QGChangeEvent::getPreviousStatus) - .containsExactly(Optional.empty()); - } - - @Test - public void event_contains_no_previousStatus_if_measure_exists_and_is_not_a_level() { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, alertStatusMetric, m -> m.setData("fooBar")); - - List<QGChangeEvent> result = run(file1); - - assertThat(result) - .extracting(QGChangeEvent::getPreviousStatus) - .containsExactly(Optional.empty()); - } - - @Test - @UseDataProvider("metricLevels") - public void event_contains_previousStatus_if_measure_exists(Metric.Level level) { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, alertStatusMetric, m -> m.setData(level.name())); - db.measures().insertLiveMeasure(project, intMetric, m -> m.setVariation(42.0).setValue(null)); - - List<QGChangeEvent> result = run(file1, newQualifierBasedIntLeakFormula()); - - assertThat(result) - .extracting(QGChangeEvent::getPreviousStatus) - .containsExactly(Optional.of(level)); - } - - @DataProvider - public static Object[][] metricLevels() { - return Arrays.stream(Metric.Level.values()) - .map(l -> new Object[] {l}) - .toArray(Object[][]::new); - } - - @Test - public void event_contains_newQualityGate_computed_by_LiveQualityGateComputer() { - markProjectAsAnalyzed(project); - db.measures().insertLiveMeasure(project, alertStatusMetric, m -> m.setData(Metric.Level.ERROR.name())); - db.measures().insertLiveMeasure(project, intMetric, m -> m.setVariation(42.0).setValue(null)); - BranchDto branch = db.getDbClient().branchDao().selectByBranchKey(db.getSession(), project.projectUuid(), "master") - .orElseThrow(() -> new IllegalStateException("Can't find master branch")); - - List<QGChangeEvent> result = run(file1, newQualifierBasedIntLeakFormula()); - - assertThat(result) - .extracting(QGChangeEvent::getQualityGateSupplier) - .extracting(Supplier::get) - .containsExactly(Optional.of(newQualityGate)); - verify(qGateComputer).loadQualityGate(any(DbSession.class), eq(organization), eq(project), eq(branch)); - verify(qGateComputer).getMetricsRelatedTo(qualityGate); - verify(qGateComputer).refreshGateStatus(eq(project), same(qualityGate), any(MeasureMatrix.class)); - } - - @Test - public void exception_describes_context_when_a_formula_fails() { - markProjectAsAnalyzed(project); - Metric metric = new Metric.Builder(intMetric.getKey(), intMetric.getShortName(), Metric.ValueType.valueOf(intMetric.getValueType())).create(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Fail to compute " + metric.getKey() + " on " + project.getDbKey()); - - run(project, new IssueMetricFormula(metric, false, (context, issueCounter) -> { - throw new NullPointerException("BOOM"); - })); - } - - private List<QGChangeEvent> run(ComponentDto component, IssueMetricFormula... formulas) { - return run(singleton(component), formulas); - } - - private List<QGChangeEvent> run(Collection<ComponentDto> components, IssueMetricFormula... formulas) { - IssueMetricFormulaFactory formulaFactory = new TestIssueMetricFormulaFactory(asList(formulas)); - - when(qGateComputer.loadQualityGate(any(DbSession.class), any(OrganizationDto.class), any(ComponentDto.class), any(BranchDto.class))) - .thenReturn(qualityGate); - when(qGateComputer.getMetricsRelatedTo(qualityGate)).thenReturn(singleton(CoreMetrics.ALERT_STATUS_KEY)); - when(qGateComputer.refreshGateStatus(eq(project), same(qualityGate), any(MeasureMatrix.class))) - .thenReturn(newQualityGate); - MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all())); - ProjectConfigurationLoader configurationLoader = new TestProjectConfigurationLoader(settings.asConfig()); - - LiveMeasureComputerImpl underTest = new LiveMeasureComputerImpl(db.getDbClient(), formulaFactory, qGateComputer, configurationLoader, projectIndexer); - - return underTest.refresh(db.getSession(), components); - } - - private void markProjectAsAnalyzed(ComponentDto p) { - markProjectAsAnalyzed(p, 1_490_000_000L); - } - - private void markProjectAsAnalyzed(ComponentDto p, @Nullable Long periodDate) { - assertThat(p.qualifier()).isEqualTo(Qualifiers.PROJECT); - db.components().insertSnapshot(p, s -> s.setPeriodDate(periodDate)); - } - - private LiveMeasureDto assertThatIntMeasureHasValue(ComponentDto component, double expectedValue) { - LiveMeasureDto measure = db.getDbClient().liveMeasureDao().selectMeasure(db.getSession(), component.uuid(), intMetric.getKey()).get(); - assertThat(measure.getComponentUuid()).isEqualTo(component.uuid()); - assertThat(measure.getProjectUuid()).isEqualTo(component.projectUuid()); - assertThat(measure.getMetricId()).isEqualTo(intMetric.getId()); - assertThat(measure.getValue()).isEqualTo(expectedValue); - return measure; - } - - private LiveMeasureDto assertThatRatingMeasureHasValue(ComponentDto component, Rating expectedRating) { - LiveMeasureDto measure = db.getDbClient().liveMeasureDao().selectMeasure(db.getSession(), component.uuid(), ratingMetric.getKey()).get(); - assertThat(measure.getComponentUuid()).isEqualTo(component.uuid()); - assertThat(measure.getProjectUuid()).isEqualTo(component.projectUuid()); - assertThat(measure.getMetricId()).isEqualTo(ratingMetric.getId()); - assertThat(measure.getValue()).isEqualTo(expectedRating.getIndex()); - assertThat(measure.getDataAsString()).isEqualTo(expectedRating.name()); - return measure; - } - - private void assertThatIntMeasureHasLeakValue(ComponentDto component, double expectedValue) { - LiveMeasureDto measure = db.getDbClient().liveMeasureDao().selectMeasure(db.getSession(), component.uuid(), intMetric.getKey()).get(); - assertThat(measure.getComponentUuid()).isEqualTo(component.uuid()); - assertThat(measure.getProjectUuid()).isEqualTo(component.projectUuid()); - assertThat(measure.getMetricId()).isEqualTo(intMetric.getId()); - assertThat(measure.getValue()).isNull(); - assertThat(measure.getVariation()).isEqualTo(expectedValue); - } - - private void assertThatRatingMeasureHasLeakValue(ComponentDto component, Rating expectedValue) { - LiveMeasureDto measure = db.getDbClient().liveMeasureDao().selectMeasure(db.getSession(), component.uuid(), ratingMetric.getKey()).get(); - assertThat(measure.getComponentUuid()).isEqualTo(component.uuid()); - assertThat(measure.getProjectUuid()).isEqualTo(component.projectUuid()); - assertThat(measure.getMetricId()).isEqualTo(ratingMetric.getId()); - assertThat(measure.getVariation()).isEqualTo((double) expectedValue.getIndex()); - } - - private IssueMetricFormula newIncrementalFormula() { - Metric metric = new Metric.Builder(intMetric.getKey(), intMetric.getShortName(), Metric.ValueType.valueOf(intMetric.getValueType())).create(); - AtomicInteger counter = new AtomicInteger(); - return new IssueMetricFormula(metric, false, (ctx, issues) -> { - ctx.setValue((double) counter.incrementAndGet()); - }); - } - - private IssueMetricFormula newIntConstantFormula(double constant) { - Metric metric = new Metric.Builder(intMetric.getKey(), intMetric.getShortName(), Metric.ValueType.valueOf(intMetric.getValueType())).create(); - return new IssueMetricFormula(metric, false, (ctx, issues) -> { - ctx.setValue(constant); - }); - } - - private IssueMetricFormula newRatingConstantFormula(Rating constant) { - Metric metric = new Metric.Builder(ratingMetric.getKey(), ratingMetric.getShortName(), Metric.ValueType.valueOf(ratingMetric.getValueType())).create(); - return new IssueMetricFormula(metric, false, (ctx, issues) -> { - ctx.setValue(constant); - }); - } - - private IssueMetricFormula newRatingLeakFormula(Rating rating) { - Metric metric = new Metric.Builder(ratingMetric.getKey(), ratingMetric.getShortName(), Metric.ValueType.valueOf(ratingMetric.getValueType())).create(); - return new IssueMetricFormula(metric, true, (ctx, issues) -> { - ctx.setLeakValue(rating); - }); - } - - private IssueMetricFormula newQualifierBasedIntFormula() { - Metric metric = new Metric.Builder(intMetric.getKey(), intMetric.getShortName(), Metric.ValueType.valueOf(intMetric.getValueType())).create(); - return new IssueMetricFormula(metric, false, (ctx, issues) -> { - ctx.setValue(ORDERED_BOTTOM_UP.indexOf(ctx.getComponent().qualifier())); - }); - } - - private IssueMetricFormula newQualifierBasedIntLeakFormula() { - Metric metric = new Metric.Builder(intMetric.getKey(), intMetric.getShortName(), Metric.ValueType.valueOf(intMetric.getValueType())).create(); - return new IssueMetricFormula(metric, true, (ctx, issues) -> { - ctx.setLeakValue(ORDERED_BOTTOM_UP.indexOf(ctx.getComponent().qualifier())); - }); - } - - private void assertThatProjectChanged(List<QGChangeEvent> events, ComponentDto... projects) { - for (ComponentDto p : projects) { - assertThat(projectIndexer.hasBeenCalled(p.uuid(), ProjectIndexer.Cause.MEASURE_CHANGE)).isTrue(); - } - - assertThat(events).extracting(e -> e.getProject().uuid()) - .containsExactlyInAnyOrder(Arrays.stream(projects).map(ComponentDto::uuid).toArray(String[]::new)); - } - - private void assertThatProjectNotChanged(List<QGChangeEvent> events, ComponentDto project) { - assertThat(projectIndexer.hasBeenCalled(project.uuid(), ProjectIndexer.Cause.MEASURE_CHANGE)).isFalse(); - assertThat(events).hasSize(0); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveMeasureModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveMeasureModuleTest.java deleted file mode 100644 index cb271141428..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveMeasureModuleTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import org.junit.Test; -import org.sonar.core.platform.ComponentContainer; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LiveMeasureModuleTest { - - @Test - public void verify_count_of_added_components() { - ComponentContainer container = new ComponentContainer(); - new LiveMeasureModule().configure(container); - assertThat(container.size()).isEqualTo(3 + 2); - } - - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java deleted file mode 100644 index 7ff3fbfdd51..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import com.google.common.collect.ImmutableSet; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.measure.LiveMeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualitygate.QGateWithOrgDto; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.server.qualitygate.Condition; -import org.sonar.server.qualitygate.EvaluatedCondition; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.QualityGate; -import org.sonar.server.qualitygate.QualityGateEvaluator; -import org.sonar.server.qualitygate.QualityGateFinder; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.groups.Tuple.tuple; -import static org.sonar.db.component.ComponentTesting.newBranchDto; -import static org.sonar.db.metric.MetricTesting.newMetricDto; -import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; - -public class LiveQualityGateComputerImplTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public DbTester db = DbTester.create(); - - private TestQualityGateEvaluator qualityGateEvaluator = new TestQualityGateEvaluator(); - private LiveQualityGateComputerImpl underTest = new LiveQualityGateComputerImpl(db.getDbClient(), new QualityGateFinder(db.getDbClient()), qualityGateEvaluator); - - @Test - public void loadQualityGate_returns_hardcoded_gate_for_short_living_branches() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertPublicProject(organization); - - BranchDto branch = newBranchDto(project).setBranchType(BranchType.SHORT); - db.components().insertProjectBranch(project, branch); - MetricDto metric1 = db.measures().insertMetric(m -> m.setKey("new_metric")); - MetricDto metric2 = db.measures().insertMetric(m -> m.setKey("metric")); - - QGateWithOrgDto gate = db.qualityGates().insertQualityGate(organization); - db.qualityGates().setDefaultQualityGate(organization, gate); - - db.qualityGates().addCondition(gate, metric1); - db.qualityGates().addCondition(gate, metric2); - - QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch); - assertThat(result.getConditions()).extracting(Condition::getMetricKey).containsExactly("new_metric"); - } - - @Test - public void loadQualityGate_returns_hardcoded_gate_for_pull_requests() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertPublicProject(organization); - - BranchDto branch = newBranchDto(project).setBranchType(BranchType.SHORT); - db.components().insertProjectBranch(project, branch); - MetricDto metric1 = db.measures().insertMetric(m -> m.setKey("new_metric")); - MetricDto metric2 = db.measures().insertMetric(m -> m.setKey("metric")); - - QGateWithOrgDto gate = db.qualityGates().insertQualityGate(organization); - db.qualityGates().setDefaultQualityGate(organization, gate); - - db.qualityGates().addCondition(gate, metric1); - db.qualityGates().addCondition(gate, metric2); - - QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch); - assertThat(result.getConditions()).extracting(Condition::getMetricKey).containsExactly("new_metric"); - } - - @Test - public void loadQualityGate_on_long_branch_returns_organization_default_gate() { - OrganizationDto organization = db.organizations().insert(); - ComponentDto project = db.components().insertPublicProject(organization); - BranchDto branch = newBranchDto(project).setBranchType(BranchType.LONG); - db.components().insertProjectBranch(project, branch); - - MetricDto metric = db.measures().insertMetric(); - QGateWithOrgDto gate = db.qualityGates().insertQualityGate(organization); - db.qualityGates().setDefaultQualityGate(organization, gate); - QualityGateConditionDto condition = db.qualityGates().addCondition(gate, metric); - - QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch); - - assertThat(result.getId()).isEqualTo("" + gate.getId()); - assertThat(result.getConditions()) - .extracting(Condition::getMetricKey, Condition::getOperator, Condition::getErrorThreshold) - .containsExactlyInAnyOrder( - tuple(metric.getKey(), Condition.Operator.fromDbValue(condition.getOperator()), condition.getErrorThreshold())); - } - - @Test - public void getMetricsRelatedTo() { - Condition condition = new Condition("metric1", Condition.Operator.GREATER_THAN, "10"); - QualityGate gate = new QualityGate("1", "foo", ImmutableSet.of(condition)); - - Set<String> result = underTest.getMetricsRelatedTo(gate); - - assertThat(result).containsExactlyInAnyOrder( - // the metrics needed to compute the status of gate - condition.getMetricKey(), - // generated metrics - CoreMetrics.ALERT_STATUS_KEY, CoreMetrics.QUALITY_GATE_DETAILS_KEY); - } - - @Test - public void refreshGateStatus_generates_gate_related_measures() { - ComponentDto project = ComponentTesting.newPublicProjectDto(newOrganizationDto()); - MetricDto conditionMetric = newMetricDto(); - MetricDto statusMetric = newMetricDto().setKey(CoreMetrics.ALERT_STATUS_KEY); - MetricDto detailsMetric = newMetricDto().setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY); - Condition condition = new Condition(conditionMetric.getKey(), Condition.Operator.GREATER_THAN, "10"); - QualityGate gate = new QualityGate("1", "foo", ImmutableSet.of(condition)); - MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(conditionMetric, statusMetric, detailsMetric), emptyList()); - - EvaluatedQualityGate result = underTest.refreshGateStatus(project, gate, matrix); - - QualityGateEvaluator.Measures measures = qualityGateEvaluator.getCalledMeasures(); - assertThat(measures.get(conditionMetric.getKey())).isEmpty(); - - assertThat(result.getStatus()).isEqualTo(Metric.Level.OK); - assertThat(result.getEvaluatedConditions()) - .extracting(EvaluatedCondition::getStatus) - .containsExactly(EvaluatedCondition.EvaluationStatus.OK); - assertThat(matrix.getMeasure(project, CoreMetrics.ALERT_STATUS_KEY).get().getDataAsString()).isEqualTo(Metric.Level.OK.name()); - assertThat(matrix.getMeasure(project, CoreMetrics.QUALITY_GATE_DETAILS_KEY).get().getDataAsString()) - .isNotEmpty() - // json format - .startsWith("{").endsWith("}"); - } - - @Test - public void refreshGateStatus_provides_measures_to_evaluator() { - ComponentDto project = ComponentTesting.newPublicProjectDto(newOrganizationDto()); - MetricDto numericMetric = newMetricDto().setValueType(Metric.ValueType.FLOAT.name()); - MetricDto numericNewMetric = newMetricDto().setValueType(Metric.ValueType.FLOAT.name()).setKey("new_metric"); - MetricDto stringMetric = newMetricDto().setValueType(Metric.ValueType.STRING.name()); - MetricDto statusMetric = newMetricDto().setKey(CoreMetrics.ALERT_STATUS_KEY); - MetricDto detailsMetric = newMetricDto().setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY); - QualityGate gate = new QualityGate("1", "foo", Collections.emptySet()); - LiveMeasureDto numericMeasure = new LiveMeasureDto().setMetricId(numericMetric.getId()).setValue(1.23).setVariation(4.56).setComponentUuid(project.uuid()); - LiveMeasureDto numericNewMeasure = new LiveMeasureDto().setMetricId(numericNewMetric.getId()).setValue(7.8).setVariation(8.9).setComponentUuid(project.uuid()); - LiveMeasureDto stringMeasure = new LiveMeasureDto().setMetricId(stringMetric.getId()).setData("bar").setComponentUuid(project.uuid()); - MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(statusMetric, detailsMetric, numericMetric, numericNewMetric, stringMetric), - asList(numericMeasure, numericNewMeasure, stringMeasure)); - - underTest.refreshGateStatus(project, gate, matrix); - - QualityGateEvaluator.Measures measures = qualityGateEvaluator.getCalledMeasures(); - - QualityGateEvaluator.Measure loadedStringMeasure = measures.get(stringMetric.getKey()).get(); - assertThat(loadedStringMeasure.getStringValue()).hasValue("bar"); - assertThat(loadedStringMeasure.getValue()).isEmpty(); - assertThat(loadedStringMeasure.getType()).isEqualTo(Metric.ValueType.STRING); - - QualityGateEvaluator.Measure loadedNumericMeasure = measures.get(numericMetric.getKey()).get(); - assertThat(loadedNumericMeasure.getStringValue()).isEmpty(); - assertThat(loadedNumericMeasure.getValue()).hasValue(1.23); - assertThat(loadedNumericMeasure.getType()).isEqualTo(Metric.ValueType.FLOAT); - - QualityGateEvaluator.Measure loadedNumericNewMeasure = measures.get(numericNewMetric.getKey()).get(); - assertThat(loadedNumericNewMeasure.getStringValue()).isEmpty(); - assertThat(loadedNumericNewMeasure.getNewMetricValue()).hasValue(8.9); - assertThat(loadedNumericNewMeasure.getType()).isEqualTo(Metric.ValueType.FLOAT); - } - - private static class TestQualityGateEvaluator implements QualityGateEvaluator { - private Measures measures; - - @Override - public EvaluatedQualityGate evaluate(QualityGate gate, Measures measures) { - checkState(this.measures == null); - this.measures = measures; - EvaluatedQualityGate.Builder builder = EvaluatedQualityGate.newBuilder().setQualityGate(gate).setStatus(Metric.Level.OK); - for (Condition condition : gate.getConditions()) { - builder.addEvaluatedCondition(condition, EvaluatedCondition.EvaluationStatus.OK, "bar"); - } - return builder.build(); - } - - private Measures getCalledMeasures() { - return measures; - } - - @Override - public Set<String> getMetricKeys(QualityGate gate) { - return gate.getConditions().stream().map(Condition::getMetricKey).collect(Collectors.toSet()); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/MeasureMatrixTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/MeasureMatrixTest.java deleted file mode 100644 index 35f25724504..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/MeasureMatrixTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Optional; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.measure.LiveMeasureDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.organization.OrganizationDto; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.db.metric.MetricTesting.newMetricDto; -import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; - -public class MeasureMatrixTest { - - private static final OrganizationDto ORGANIZATION = newOrganizationDto(); - private static final ComponentDto PROJECT = ComponentTesting.newPublicProjectDto(ORGANIZATION); - private static final ComponentDto FILE = ComponentTesting.newFileDto(PROJECT); - private static final MetricDto METRIC_1 = newMetricDto().setId(100); - private static final MetricDto METRIC_2 = newMetricDto().setId(200); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void getMetric() { - Collection<MetricDto> metrics = asList(METRIC_1, METRIC_2); - - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT, FILE), metrics, new ArrayList<>()); - - assertThat(underTest.getMetric(METRIC_2.getId())).isSameAs(METRIC_2); - } - - @Test - public void getMetric_fails_if_metric_is_not_registered() { - Collection<MetricDto> metrics = asList(METRIC_1); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT, FILE), metrics, new ArrayList<>()); - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("Metric with id " + METRIC_2.getId() + " not found"); - - underTest.getMetric(METRIC_2.getId()); - } - - @Test - public void getValue_returns_empty_if_measure_is_absent() { - MetricDto metric = newMetricDto(); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(null); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - assertThat(underTest.getMeasure(FILE, metric.getKey())).isEmpty(); - } - - @Test - public void getMeasure_throws_IAE_if_metric_is_not_registered() { - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(METRIC_1), emptyList()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Metric with key _missing_ is not registered"); - - underTest.getMeasure(PROJECT, "_missing_"); - } - - @Test - public void setValue_double_rounds_up_and_updates_value() { - MetricDto metric = newMetricDto().setDecimalScale(2); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(1.23); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - underTest.setValue(PROJECT, metric.getKey(), 3.14159); - - assertThat(underTest.getMeasure(PROJECT, metric.getKey()).get().getValue()).isEqualTo(3.14); - assertThat(underTest.getChanged()).hasSize(1); - - underTest.setValue(PROJECT, metric.getKey(), 3.148); - verifyValue(underTest, PROJECT, metric, 3.15); - verifyVariation(underTest, PROJECT, metric, null); - } - - private void verifyValue(MeasureMatrix underTest, ComponentDto component, MetricDto metric, @Nullable Double expectedValue) { - Optional<LiveMeasureDto> measure = underTest.getMeasure(component, metric.getKey()); - assertThat(measure).isPresent(); - assertThat(measure.get().getValue()).isEqualTo(expectedValue); - } - - private void verifyVariation(MeasureMatrix underTest, ComponentDto component, MetricDto metric, @Nullable Double expectedVariation) { - assertThat(underTest.getMeasure(component, metric.getKey()).get().getVariation()).isEqualTo(expectedVariation); - } - - @Test - public void setValue_double_does_nothing_if_value_is_unchanged() { - MetricDto metric = newMetricDto().setDecimalScale(2); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(3.14); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - underTest.setValue(PROJECT, metric.getKey(), 3.14159); - - assertThat(underTest.getChanged()).isEmpty(); - verifyValue(underTest, PROJECT, metric, 3.14); - } - - @Test - public void setValue_double_updates_variation() { - MetricDto metric = newMetricDto().setDecimalScale(2); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(3.14).setVariation(1.14); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - underTest.setValue(PROJECT, metric.getKey(), 3.56); - - assertThat(underTest.getChanged()).hasSize(1); - verifyValue(underTest, PROJECT, metric, 3.56); - verifyVariation(underTest, PROJECT, metric, 3.56 - (3.14 - 1.14)); - } - - @Test - public void setValue_double_rounds_up_variation() { - MetricDto metric = newMetricDto().setDecimalScale(2); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(3.14).setVariation(1.14); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - underTest.setValue(PROJECT, metric.getKey(), 3.569); - - assertThat(underTest.getChanged()).hasSize(1); - verifyValue(underTest, PROJECT, metric, 3.57); - verifyVariation(underTest, PROJECT, metric, 1.57); - } - - @Test - public void setValue_String_does_nothing_if_value_is_not_changed() { - LiveMeasureDto measure = newMeasure(METRIC_1, PROJECT).setData("foo"); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT, FILE), asList(METRIC_1), asList(measure)); - - underTest.setValue(PROJECT, METRIC_1.getKey(), "foo"); - - assertThat(underTest.getMeasure(PROJECT, METRIC_1.getKey()).get().getDataAsString()).isEqualTo("foo"); - assertThat(underTest.getChanged()).isEmpty(); - } - - @Test - public void setValue_String_updates_value() { - LiveMeasureDto measure = newMeasure(METRIC_1, PROJECT).setData("foo"); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT, FILE), asList(METRIC_1), asList(measure)); - - underTest.setValue(PROJECT, METRIC_1.getKey(), "bar"); - - assertThat(underTest.getMeasure(PROJECT, METRIC_1.getKey()).get().getDataAsString()).isEqualTo("bar"); - assertThat(underTest.getChanged()).extracting(LiveMeasureDto::getDataAsString).containsExactly("bar"); - } - - @Test - public void setLeakValue_rounds_up_and_updates_value() { - MetricDto metric = newMetricDto().setDecimalScale(2); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(null); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - underTest.setLeakValue(PROJECT, metric.getKey(), 3.14159); - verifyVariation(underTest, PROJECT, metric, 3.14); - // do not update value - verifyValue(underTest, PROJECT, metric, null); - - underTest.setLeakValue(PROJECT, metric.getKey(), 3.148); - verifyVariation(underTest, PROJECT, metric, 3.15); - // do not update value - verifyValue(underTest, PROJECT, metric, null); - } - - @Test - public void setLeakValue_double_does_nothing_if_value_is_unchanged() { - MetricDto metric = newMetricDto().setDecimalScale(2); - LiveMeasureDto measure = newMeasure(metric, PROJECT).setValue(null).setVariation(3.14); - MeasureMatrix underTest = new MeasureMatrix(asList(PROJECT), asList(metric), asList(measure)); - - underTest.setLeakValue(PROJECT, metric.getKey(), 3.14159); - - assertThat(underTest.getChanged()).isEmpty(); - verifyVariation(underTest, PROJECT, metric, 3.14); - } - - private LiveMeasureDto newMeasure(MetricDto metric, ComponentDto component) { - return new LiveMeasureDto().setMetricId(metric.getId()).setData("foo").setComponentUuid(component.uuid()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/TestIssueMetricFormulaFactory.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/TestIssueMetricFormulaFactory.java deleted file mode 100644 index 293e68e7072..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/TestIssueMetricFormulaFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.measure.live; - -import java.util.List; -import java.util.Set; -import org.sonar.api.measures.Metric; - -class TestIssueMetricFormulaFactory implements IssueMetricFormulaFactory { - - private final List<IssueMetricFormula> formulas; - - TestIssueMetricFormulaFactory(List<IssueMetricFormula> formulas) { - this.formulas = formulas; - } - - @Override - public List<IssueMetricFormula> getFormulas() { - return formulas; - } - - @Override - public Set<Metric> getFormulaMetrics() { - return IssueMetricFormulaFactory.extractMetrics(formulas); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ApplyPermissionTemplateQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ApplyPermissionTemplateQueryTest.java deleted file mode 100644 index afa4a39fd03..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/ApplyPermissionTemplateQueryTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.Collections; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.server.exceptions.BadRequestException; - -import static com.google.common.collect.Lists.newArrayList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.permission.ApplyPermissionTemplateQuery.create; - -public class ApplyPermissionTemplateQueryTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void should_populate_with_params() { - ApplyPermissionTemplateQuery query = create("my_template_key", newArrayList("1", "2", "3")); - - assertThat(query.getTemplateUuid()).isEqualTo("my_template_key"); - assertThat(query.getComponentKeys()).containsOnly("1", "2", "3"); - } - - @Test - public void should_invalidate_query_with_empty_name() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission template is mandatory"); - - ApplyPermissionTemplateQuery.create("", newArrayList("1", "2", "3")); - } - - @Test - public void should_invalidate_query_with_no_components() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("No project provided. Please provide at least one project."); - - ApplyPermissionTemplateQuery.create("my_template_key", Collections.emptyList()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/DefaultTemplatesResolverImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/DefaultTemplatesResolverImplTest.java deleted file mode 100644 index 76af5bbe7a2..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/DefaultTemplatesResolverImplTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.stream.Stream; -import org.junit.Test; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypeTree; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.db.organization.DefaultTemplates; - -import static org.assertj.core.api.Assertions.assertThat; - -public class DefaultTemplatesResolverImplTest { - - private static final ResourceTypes RESOURCE_TYPES_WITHOUT_VIEWS = new ResourceTypes(new ResourceTypeTree[] { - ResourceTypeTree.builder().addType(ResourceType.builder(Qualifiers.PROJECT).build()).build() - }); - private static final ResourceTypes RESOURCE_TYPES_WITH_VIEWS = new ResourceTypes(new ResourceTypeTree[] { - ResourceTypeTree.builder().addType(ResourceType.builder(Qualifiers.PROJECT).build()).build(), - ResourceTypeTree.builder().addType(ResourceType.builder(Qualifiers.VIEW).build()).build() - }); - private DefaultTemplatesResolverImpl underTestWithoutViews = new DefaultTemplatesResolverImpl(RESOURCE_TYPES_WITHOUT_VIEWS); - private DefaultTemplatesResolverImpl underTestWithViews = new DefaultTemplatesResolverImpl(RESOURCE_TYPES_WITH_VIEWS); - - @Test - public void project_is_project_of_DefaultTemplates_no_matter_if_views_is_installed() { - Stream.of( - new DefaultTemplates().setProjectUuid("foo").setApplicationsUuid(null), - new DefaultTemplates().setProjectUuid("foo").setApplicationsUuid("bar")).forEach( - defaultTemplates -> { - assertThat(underTestWithoutViews.resolve(defaultTemplates).getProject()).isEqualTo("foo"); - assertThat(underTestWithViews.resolve(defaultTemplates).getProject()).isEqualTo("foo"); - }); - } - - @Test - public void view_is_empty_no_matter_view_in_DefaultTemplates_if_views_is_not_installed() { - DefaultTemplates defaultTemplatesNoView = new DefaultTemplates().setProjectUuid("foo").setApplicationsUuid(null); - DefaultTemplates defaultTemplatesView = new DefaultTemplates().setProjectUuid("foo").setApplicationsUuid("bar"); - - assertThat(underTestWithoutViews.resolve(defaultTemplatesNoView).getApplication()).isEmpty(); - assertThat(underTestWithoutViews.resolve(defaultTemplatesView).getApplication()).isEmpty(); - } - - @Test - public void view_is_project_of_DefaultTemplates_if_view_in_DefaultTemplates_is_null_and_views_is_installed() { - DefaultTemplates defaultTemplates = new DefaultTemplates().setProjectUuid("foo").setApplicationsUuid(null); - - assertThat(underTestWithViews.resolve(defaultTemplates).getApplication()).contains("foo"); - } - - @Test - public void view_is_view_of_DefaultTemplates_if_view_in_DefaultTemplates_is_not_null_and_views_is_installed() { - DefaultTemplates defaultTemplates = new DefaultTemplates().setProjectUuid("foo").setApplicationsUuid("bar"); - - assertThat(underTestWithViews.resolve(defaultTemplates).getApplication()).contains("bar"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/DefaultTemplatesResolverRule.java b/server/sonar-server/src/test/java/org/sonar/server/permission/DefaultTemplatesResolverRule.java deleted file mode 100644 index 87b5529db46..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/DefaultTemplatesResolverRule.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import org.junit.rules.ExternalResource; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypeTree; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.db.organization.DefaultTemplates; - -import static org.sonar.api.resources.Qualifiers.APP; -import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.api.resources.Qualifiers.VIEW; - -public class DefaultTemplatesResolverRule extends ExternalResource implements DefaultTemplatesResolver { - private static final DefaultTemplatesResolver WITH_GOV = new DefaultTemplatesResolverImpl( - new ResourceTypes(new ResourceTypeTree[] { - ResourceTypeTree.builder() - .addType(ResourceType.builder(PROJECT).build()) - .build(), - ResourceTypeTree.builder() - .addType(ResourceType.builder(VIEW).build()) - .build(), - ResourceTypeTree.builder() - .addType(ResourceType.builder(APP).build()) - .build() - })); - private static final DefaultTemplatesResolver WITHOUT_GOV = new DefaultTemplatesResolverImpl( - new ResourceTypes(new ResourceTypeTree[] {ResourceTypeTree.builder() - .addType(ResourceType.builder(PROJECT).build()) - .build()})); - - private final boolean governanceInitiallyInstalled; - private boolean governanceInstalled; - - private DefaultTemplatesResolverRule(boolean governanceInitiallyInstalled) { - this.governanceInitiallyInstalled = governanceInitiallyInstalled; - this.governanceInstalled = governanceInitiallyInstalled; - } - - @Override - protected void before() { - this.governanceInstalled = governanceInitiallyInstalled; - } - - public void installGovernance() { - this.governanceInstalled = true; - } - - public void uninstallGovernance() { - this.governanceInstalled = false; - } - - public static DefaultTemplatesResolverRule withoutGovernance() { - return new DefaultTemplatesResolverRule(false); - } - - public static DefaultTemplatesResolverRule withGovernance() { - return new DefaultTemplatesResolverRule(true); - } - - @Override - public DefaultTemplatesResolverImpl.ResolvedDefaultTemplates resolve(DefaultTemplates defaultTemplates) { - if (governanceInstalled) { - return WITH_GOV.resolve(defaultTemplates); - } - return WITHOUT_GOV.resolve(defaultTemplates); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java deleted file mode 100644 index b6f9600af1a..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import org.apache.commons.lang.StringUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceTypes; -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.component.ComponentDto; -import org.sonar.db.component.ResourceTypesRule; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.GroupPermissionDto; -import org.sonar.db.permission.OrganizationPermission; -import org.sonar.db.user.GroupDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.exceptions.BadRequestException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; -import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; -import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; - -public class GroupPermissionChangerTest { - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT); - private PermissionService permissionService = new PermissionServiceImpl(resourceTypes); - private GroupPermissionChanger underTest = new GroupPermissionChanger(db.getDbClient()); - private OrganizationDto org; - private GroupDto group; - private ComponentDto privateProject; - private ComponentDto publicProject; - - @Before - public void setUp() throws Exception { - org = db.organizations().insert(); - group = db.users().insertGroup(org, "a-group"); - privateProject = db.components().insertPrivateProject(org); - publicProject = db.components().insertPublicProject(org); - } - - @Test - public void apply_adds_organization_permission_to_group() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN); - } - - @Test - public void apply_adds_organization_permission_to_group_AnyOne() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN); - } - - @Test - public void apply_fails_with_BadRequestException_when_adding_any_permission_to_group_AnyOne_on_private_project() { - GroupIdOrAnyone anyOneGroupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - permissionService.getAllProjectPermissions() - .forEach(perm -> { - try { - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, perm, new ProjectId(privateProject), anyOneGroupId, permissionService)); - fail("a BadRequestException should have been thrown"); - } catch (BadRequestException e) { - assertThat(e).hasMessage("No permission can be granted to Anyone on a private component"); - } - }); - } - - @Test - public void apply_has_no_effect_when_removing_any_permission_to_group_AnyOne_on_private_project() { - permissionService.getAllProjectPermissions() - .forEach(this::unsafeInsertProjectPermissionOnAnyone); - - GroupIdOrAnyone anyOneGroupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - permissionService.getAllProjectPermissions() - .forEach(perm -> { - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, perm, new ProjectId(privateProject), anyOneGroupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, privateProject)).contains(perm); - }); - } - - @Test - public void apply_adds_permission_USER_to_group_on_private_project() { - applyAddsPermissionToGroupOnPrivateProject(UserRole.USER); - } - - @Test - public void apply_adds_permission_CODEVIEWER_to_group_on_private_project() { - applyAddsPermissionToGroupOnPrivateProject(UserRole.CODEVIEWER); - } - - @Test - public void apply_adds_permission_ADMIN_to_group_on_private_project() { - applyAddsPermissionToGroupOnPrivateProject(UserRole.ADMIN); - } - - @Test - public void apply_adds_permission_ISSUE_ADMIN_to_group_on_private_project() { - applyAddsPermissionToGroupOnPrivateProject(UserRole.ISSUE_ADMIN); - } - - @Test - public void apply_adds_permission_SCAN_EXECUTION_to_group_on_private_project() { - applyAddsPermissionToGroupOnPrivateProject(GlobalPermissions.SCAN_EXECUTION); - } - - private void applyAddsPermissionToGroupOnPrivateProject(String permission) { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, new ProjectId(privateProject), groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).isEmpty(); - assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission); - } - - @Test - public void apply_removes_permission_USER_from_group_on_private_project() { - applyRemovesPermissionFromGroupOnPrivateProject(UserRole.USER); - } - - @Test - public void apply_removes_permission_CODEVIEWER_from_group_on_private_project() { - applyRemovesPermissionFromGroupOnPrivateProject(UserRole.CODEVIEWER); - } - - @Test - public void apply_removes_permission_ADMIN_from_on_private_project() { - applyRemovesPermissionFromGroupOnPrivateProject(UserRole.ADMIN); - } - - @Test - public void apply_removes_permission_ISSUE_ADMIN_from_on_private_project() { - applyRemovesPermissionFromGroupOnPrivateProject(UserRole.ISSUE_ADMIN); - } - - @Test - public void apply_removes_permission_SCAN_EXECUTION_from_on_private_project() { - applyRemovesPermissionFromGroupOnPrivateProject(GlobalPermissions.SCAN_EXECUTION); - } - - private void applyRemovesPermissionFromGroupOnPrivateProject(String permission) { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - db.users().insertProjectPermissionOnGroup(group, permission, privateProject); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, new ProjectId(privateProject), groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission); - } - - @Test - public void apply_has_no_effect_when_adding_USER_permission_to_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.USER, new ProjectId(publicProject), groupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, publicProject)).isEmpty(); - } - - @Test - public void apply_has_no_effect_when_adding_CODEVIEWER_permission_to_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.CODEVIEWER, new ProjectId(publicProject), groupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, publicProject)).isEmpty(); - } - - @Test - public void apply_fails_with_BadRequestException_when_adding_permission_ADMIN_to_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("It is not possible to add the 'admin' permission to group 'Anyone'"); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ADMIN, new ProjectId(publicProject), groupId, permissionService)); - } - - @Test - public void apply_adds_permission_ISSUE_ADMIN_to_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, new ProjectId(publicProject), groupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, publicProject)).containsOnly(UserRole.ISSUE_ADMIN); - } - - @Test - public void apply_adds_permission_SCAN_EXECUTION_to_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.SCAN_EXECUTION, new ProjectId(publicProject), groupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, publicProject)).containsOnly(GlobalPermissions.SCAN_EXECUTION); - } - - @Test - public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission user can't be removed from a public component"); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, new ProjectId(publicProject), groupId, permissionService)); - } - - @Test - public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_group_AnyOne_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission codeviewer can't be removed from a public component"); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, new ProjectId(publicProject), groupId, permissionService)); - } - - @Test - public void apply_removes_ADMIN_permission_from_group_AnyOne_on_a_public_project() { - applyRemovesPermissionFromGroupAnyOneOnAPublicProject(UserRole.ADMIN); - } - - @Test - public void apply_removes_ISSUE_ADMIN_permission_from_group_AnyOne_on_a_public_project() { - applyRemovesPermissionFromGroupAnyOneOnAPublicProject(UserRole.ISSUE_ADMIN); - } - - @Test - public void apply_removes_SCAN_EXECUTION_permission_from_group_AnyOne_on_a_public_project() { - applyRemovesPermissionFromGroupAnyOneOnAPublicProject(GlobalPermissions.SCAN_EXECUTION); - } - - private void applyRemovesPermissionFromGroupAnyOneOnAPublicProject(String permission) { - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(org.getUuid()); - db.users().insertProjectPermissionOnAnyone(permission, publicProject); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, permission, new ProjectId(publicProject), groupId, permissionService)); - - assertThat(db.users().selectAnyonePermissions(org, publicProject)).isEmpty(); - } - - @Test - public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_a_group_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission user can't be removed from a public component"); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, new ProjectId(publicProject), groupId, permissionService)); - } - - @Test - public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_a_group_on_a_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission codeviewer can't be removed from a public component"); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, new ProjectId(publicProject), groupId, permissionService)); - } - - @Test - public void add_permission_to_anyone() { - OrganizationDto defaultOrganization = db.getDefaultOrganization(); - GroupIdOrAnyone groupId = GroupIdOrAnyone.forAnyone(defaultOrganization.getUuid()); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).isEmpty(); - assertThat(db.users().selectAnyonePermissions(defaultOrganization, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN); - } - - @Test - public void do_nothing_when_adding_permission_that_already_exists() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES); - - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey()); - } - - @Test - public void fail_to_add_global_permission_but_SCAN_and_ADMIN_on_private_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - permissionService.getAllOrganizationPermissions().stream() - .map(OrganizationPermission::getKey) - .filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermissions.SCAN_EXECUTION.equals(perm)) - .forEach(perm -> { - try { - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, perm, new ProjectId(privateProject), groupId, permissionService)); - fail("a BadRequestException should have been thrown for permission " + perm); - } catch (BadRequestException e) { - assertThat(e).hasMessage("Invalid project permission '" + perm + - "'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]"); - } - }); - } - - @Test - public void fail_to_add_global_permission_but_SCAN_and_ADMIN_on_public_project() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - permissionService.getAllOrganizationPermissions().stream() - .map(OrganizationPermission::getKey) - .filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermissions.SCAN_EXECUTION.equals(perm)) - .forEach(perm -> { - try { - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, perm, new ProjectId(publicProject), groupId, permissionService)); - fail("a BadRequestException should have been thrown for permission " + perm); - } catch (BadRequestException e) { - assertThat(e).hasMessage("Invalid project permission '" + perm + - "'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]"); - } - }); - } - - @Test - public void fail_to_add_project_permission_but_SCAN_and_ADMIN_on_global_group() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - permissionService.getAllProjectPermissions() - .stream() - .filter(perm -> !GlobalPermissions.SCAN_EXECUTION.equals(perm) && !OrganizationPermission.ADMINISTER.getKey().equals(perm)) - .forEach(permission -> { - try { - apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, null, groupId, permissionService)); - fail("a BadRequestException should have been thrown for permission " + permission); - } catch (BadRequestException e) { - assertThat(e).hasMessage("Invalid global permission '" + permission + "'. Valid values are [admin, gateadmin, profileadmin, provisioning, scan]"); - } - }); - } - - @Test - public void remove_permission_from_group() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES); - db.users().insertPermissionOnGroup(group, PROVISION_PROJECTS); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER_QUALITY_GATES.getKey(), null, groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(PROVISION_PROJECTS.getKey()); - } - - @Test - public void remove_project_permission_from_group() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES); - db.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, privateProject); - db.users().insertProjectPermissionOnGroup(group, UserRole.CODEVIEWER, privateProject); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, new ProjectId(privateProject), groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey()); - assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(UserRole.CODEVIEWER); - } - - @Test - public void do_not_fail_if_removing_a_permission_that_does_not_exist() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, new ProjectId(privateProject), groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).isEmpty(); - assertThat(db.users().selectGroupPermissions(group, privateProject)).isEmpty(); - } - - @Test - public void fail_to_remove_admin_permission_if_no_more_admins() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - db.users().insertPermissionOnGroup(group, ADMINISTER); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Last group with permission 'admin'. Permission cannot be removed."); - - underTest.apply(db.getSession(), new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, groupId, permissionService)); - } - - @Test - public void remove_admin_group_if_still_other_admins() { - GroupIdOrAnyone groupId = GroupIdOrAnyone.from(group); - db.users().insertPermissionOnGroup(group, ADMINISTER); - UserDto admin = db.users().insertUser(); - db.users().insertPermissionOnUser(org, admin, ADMINISTER); - - apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, groupId, permissionService)); - - assertThat(db.users().selectGroupPermissions(group, null)).isEmpty(); - } - - private void apply(GroupPermissionChange change) { - underTest.apply(db.getSession(), change); - db.commit(); - } - - private void unsafeInsertProjectPermissionOnAnyone(String perm) { - GroupPermissionDto dto = new GroupPermissionDto() - .setOrganizationUuid(privateProject.getOrganizationUuid()) - .setGroupId(null) - .setRole(perm) - .setResourceId(privateProject.getId()); - db.getDbClient().groupPermissionDao().insert(db.getSession(), dto); - db.commit(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java deleted file mode 100644 index 2bc2f07606b..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import java.util.List; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.web.UserRole; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ResourceTypesRule; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.template.PermissionTemplateDbTester; -import org.sonar.db.permission.template.PermissionTemplateDto; -import org.sonar.db.user.GroupDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.es.ProjectIndexers; -import org.sonar.server.es.TestProjectIndexers; -import org.sonar.server.tester.UserSessionRule; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; -import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; -import static org.sonar.db.permission.OrganizationPermission.SCAN; - -public class PermissionTemplateServiceTest { - - @Rule - public ExpectedException throwable = ExpectedException.none(); - @Rule - public DbTester dbTester = DbTester.create(new AlwaysIncreasingSystem2()); - @Rule - public DefaultTemplatesResolverRule defaultTemplatesResolver = DefaultTemplatesResolverRule.withGovernance(); - - private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT); - private PermissionService permissionService = new PermissionServiceImpl(resourceTypes); - - private UserSessionRule userSession = UserSessionRule.standalone(); - private PermissionTemplateDbTester templateDb = dbTester.permissionTemplates(); - private DbSession session = dbTester.getSession(); - private ProjectIndexers projectIndexers = new TestProjectIndexers(); - - private PermissionTemplateService underTest = new PermissionTemplateService(dbTester.getDbClient(), projectIndexers, userSession, defaultTemplatesResolver); - - @Test - public void apply_does_not_insert_permission_to_group_AnyOne_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, "p1"); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(privateProject)); - - assertThat(selectProjectPermissionsOfGroup(organization, null, privateProject)).isEmpty(); - } - - @Test - public void apply_default_does_not_insert_permission_to_group_AnyOne_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - UserDto creator = dbTester.users().insertUser(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, privateProject, creator.getId()); - - assertThat(selectProjectPermissionsOfGroup(organization, null, privateProject)).isEmpty(); - } - - @Test - public void apply_inserts_permissions_to_group_AnyOne_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, perm)); - dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, "p1"); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(publicProject)); - - assertThat(selectProjectPermissionsOfGroup(organization, null, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_permissions_to_group_AnyOne_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, perm)); - dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, publicProject, null); - - assertThat(selectProjectPermissionsOfGroup(organization, null, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void apply_inserts_any_permissions_to_group_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - GroupDto group = dbTester.users().insertGroup(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, perm)); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, "p1"); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(privateProject)); - - assertThat(selectProjectPermissionsOfGroup(organization, group, privateProject)) - .containsOnly("p1", UserRole.CODEVIEWER, UserRole.USER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_any_permissions_to_group_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - GroupDto group = dbTester.users().insertGroup(organization); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, perm)); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, privateProject, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, privateProject)) - .containsOnly("p1", UserRole.CODEVIEWER, UserRole.USER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void apply_inserts_permissions_to_group_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - GroupDto group = dbTester.users().insertGroup(organization); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, perm)); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, "p1"); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(publicProject)); - - assertThat(selectProjectPermissionsOfGroup(organization, group, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_permissions_to_group_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - GroupDto group = dbTester.users().insertGroup(organization); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, perm)); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, publicProject, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void apply_inserts_permissions_to_user_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - UserDto user = dbTester.users().insertUser(); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, perm)); - dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, "p1"); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(publicProject)); - - assertThat(selectProjectPermissionsOfUser(user, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_permissions_to_user_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - UserDto user = dbTester.users().insertUser(); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, perm)); - dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, publicProject, null); - - assertThat(selectProjectPermissionsOfUser(user, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void apply_inserts_any_permissions_to_user_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - UserDto user = dbTester.users().insertUser(); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, perm)); - dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, "p1"); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(privateProject)); - - assertThat(selectProjectPermissionsOfUser(user, privateProject)) - .containsOnly("p1", UserRole.CODEVIEWER, UserRole.USER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_any_permissions_to_user_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - UserDto user = dbTester.users().insertUser(); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, perm)); - dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, privateProject, null); - - assertThat(selectProjectPermissionsOfUser(user, privateProject)) - .containsOnly("p1", UserRole.CODEVIEWER, UserRole.USER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_permissions_to_ProjectCreator_but_USER_and_CODEVIEWER_when_applying_template_on_public_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto publicProject = dbTester.components().insertPublicProject(organization); - UserDto user = dbTester.users().insertUser(); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addProjectCreatorToTemplate(permissionTemplate, perm)); - dbTester.permissionTemplates().addProjectCreatorToTemplate(permissionTemplate, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, publicProject, user.getId()); - - assertThat(selectProjectPermissionsOfUser(user, publicProject)) - .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void applyDefault_inserts_any_permissions_to_ProjectCreator_when_applying_template_on_private_project() { - OrganizationDto organization = dbTester.organizations().insert(); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - ComponentDto privateProject = dbTester.components().insertPrivateProject(organization); - UserDto user = dbTester.users().insertUser(); - permissionService.getAllProjectPermissions() - .forEach(perm -> dbTester.permissionTemplates().addProjectCreatorToTemplate(permissionTemplate, perm)); - dbTester.permissionTemplates().addProjectCreatorToTemplate(permissionTemplate, "p1"); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, privateProject, user.getId()); - - assertThat(selectProjectPermissionsOfUser(user, privateProject)) - .containsOnly("p1", UserRole.CODEVIEWER, UserRole.USER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, SCAN.getKey()); - } - - @Test - public void apply_template_on_view() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto view = dbTester.components().insertView(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, ADMINISTER.getKey()); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, view, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, view)) - .containsOnly(ADMINISTER.getKey(), PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_default_template_on_application() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto view = dbTester.components().insertPublicApplication(organization); - PermissionTemplateDto projectPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - PermissionTemplateDto appPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(appPermissionTemplate, group, ADMINISTER.getKey()); - dbTester.permissionTemplates().addGroupToTemplate(appPermissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, projectPermissionTemplate.getUuid(), appPermissionTemplate.getUuid(), null); - - underTest.applyDefault(session, view, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, view)) - .containsOnly(ADMINISTER.getKey(), PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_default_template_on_portfolio() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto view = dbTester.components().insertPublicPortfolio(organization); - PermissionTemplateDto projectPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - PermissionTemplateDto portPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(portPermissionTemplate, group, ADMINISTER.getKey()); - dbTester.permissionTemplates().addGroupToTemplate(portPermissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, projectPermissionTemplate.getUuid(), null, portPermissionTemplate.getUuid()); - - underTest.applyDefault(session, view, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, view)) - .containsOnly(ADMINISTER.getKey(), PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_project_default_template_on_view_when_no_view_default_template() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto view = dbTester.components().insertView(organization); - PermissionTemplateDto projectPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(projectPermissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, projectPermissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, view, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, view)).containsOnly(PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_template_on_applications() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto application = dbTester.components().insertApplication(organization); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, ADMINISTER.getKey()); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, permissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, application, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, application)) - .containsOnly(ADMINISTER.getKey(), PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_default_view_template_on_application() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto application = dbTester.components().insertApplication(organization); - PermissionTemplateDto projectPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - PermissionTemplateDto appPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - PermissionTemplateDto portPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(appPermissionTemplate, group, ADMINISTER.getKey()); - dbTester.permissionTemplates().addGroupToTemplate(appPermissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, projectPermissionTemplate.getUuid(), appPermissionTemplate.getUuid(), portPermissionTemplate.getUuid()); - - underTest.applyDefault(session, application, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, application)) - .containsOnly(ADMINISTER.getKey(), PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_project_default_template_on_application_when_no_application_default_template() { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto application = dbTester.components().insertApplication(organization); - PermissionTemplateDto projectPermissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - GroupDto group = dbTester.users().insertGroup(organization); - dbTester.permissionTemplates().addGroupToTemplate(projectPermissionTemplate, group, PROVISION_PROJECTS.getKey()); - dbTester.organizations().setDefaultTemplates(organization, projectPermissionTemplate.getUuid(), null, null); - - underTest.applyDefault(session, application, null); - - assertThat(selectProjectPermissionsOfGroup(organization, group, application)).containsOnly(PROVISION_PROJECTS.getKey()); - } - - @Test - public void apply_permission_template() { - OrganizationDto organization = dbTester.organizations().insert(); - UserDto user = dbTester.users().insertUser(); - ComponentDto project = dbTester.components().insertPrivateProject(organization); - GroupDto adminGroup = dbTester.users().insertGroup(organization); - GroupDto userGroup = dbTester.users().insertGroup(organization); - dbTester.users().insertPermissionOnGroup(adminGroup, "admin"); - dbTester.users().insertPermissionOnGroup(userGroup, "user"); - dbTester.users().insertPermissionOnUser(organization, user, "admin"); - PermissionTemplateDto permissionTemplate = dbTester.permissionTemplates().insertTemplate(organization); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, adminGroup, "admin"); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, adminGroup, "issueadmin"); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, userGroup, "user"); - dbTester.permissionTemplates().addGroupToTemplate(permissionTemplate, userGroup, "codeviewer"); - dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, "user"); - dbTester.permissionTemplates().addAnyoneToTemplate(permissionTemplate, "codeviewer"); - dbTester.permissionTemplates().addUserToTemplate(permissionTemplate, user, "admin"); - - assertThat(selectProjectPermissionsOfGroup(organization, adminGroup, project)).isEmpty(); - assertThat(selectProjectPermissionsOfGroup(organization, userGroup, project)).isEmpty(); - assertThat(selectProjectPermissionsOfGroup(organization, null, project)).isEmpty(); - assertThat(selectProjectPermissionsOfUser(user, project)).isEmpty(); - - underTest.applyAndCommit(session, permissionTemplate, singletonList(project)); - - assertThat(selectProjectPermissionsOfGroup(organization, adminGroup, project)).containsOnly("admin", "issueadmin"); - assertThat(selectProjectPermissionsOfGroup(organization, userGroup, project)).containsOnly("user", "codeviewer"); - assertThat(selectProjectPermissionsOfGroup(organization, null, project)).isEmpty(); - assertThat(selectProjectPermissionsOfUser(user, project)).containsOnly("admin"); - } - - private List<String> selectProjectPermissionsOfGroup(OrganizationDto organizationDto, @Nullable GroupDto groupDto, ComponentDto project) { - return dbTester.getDbClient().groupPermissionDao().selectProjectPermissionsOfGroup(session, - organizationDto.getUuid(), groupDto != null ? groupDto.getId() : null, project.getId()); - } - - private List<String> selectProjectPermissionsOfUser(UserDto userDto, ComponentDto project) { - return dbTester.getDbClient().userPermissionDao().selectProjectPermissionsOfUser(session, - userDto.getId(), project.getId()); - } - - @Test - public void would_user_have_scan_permission_with_default_permission_template() { - OrganizationDto organization = dbTester.organizations().insert(); - GroupDto group = dbTester.users().insertGroup(organization); - UserDto user = dbTester.users().insertUser(); - dbTester.users().insertMember(group, user); - PermissionTemplateDto template = templateDb.insertTemplate(organization); - dbTester.organizations().setDefaultTemplates(template, null, null); - templateDb.addProjectCreatorToTemplate(template.getId(), SCAN.getKey()); - templateDb.addUserToTemplate(template.getId(), user.getId(), UserRole.USER); - templateDb.addGroupToTemplate(template.getId(), group.getId(), UserRole.CODEVIEWER); - templateDb.addGroupToTemplate(template.getId(), null, UserRole.ISSUE_ADMIN); - - // authenticated user - checkWouldUserHaveScanPermission(organization, user.getId(), true); - - // anonymous user - checkWouldUserHaveScanPermission(organization, null, false); - } - - @Test - public void would_user_have_scan_permission_with_unknown_default_permission_template() { - dbTester.organizations().setDefaultTemplates(dbTester.getDefaultOrganization(), "UNKNOWN_TEMPLATE_UUID", null, null); - - checkWouldUserHaveScanPermission(dbTester.getDefaultOrganization(), null, false); - } - - @Test - public void would_user_have_scan_permission_with_empty_template() { - PermissionTemplateDto template = templateDb.insertTemplate(dbTester.getDefaultOrganization()); - dbTester.organizations().setDefaultTemplates(template, null, null); - - checkWouldUserHaveScanPermission(dbTester.getDefaultOrganization(), null, false); - } - - private void checkWouldUserHaveScanPermission(OrganizationDto organization, @Nullable Integer userId, boolean expectedResult) { - assertThat(underTest.wouldUserHaveScanPermissionWithDefaultTemplate(session, organization.getUuid(), userId, "PROJECT_KEY")) - .isEqualTo(expectedResult); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java deleted file mode 100644 index 41d48efd496..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.permission; - -import org.apache.commons.lang.StringUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ResourceTypesRule; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.OrganizationPermission; -import org.sonar.db.user.GroupDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.exceptions.BadRequestException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.web.UserRole.ADMIN; -import static org.sonar.api.web.UserRole.CODEVIEWER; -import static org.sonar.api.web.UserRole.ISSUE_ADMIN; -import static org.sonar.api.web.UserRole.USER; -import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN; -import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; -import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; -import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; -import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; -import static org.sonar.db.permission.OrganizationPermission.SCAN; -import static org.sonar.server.permission.PermissionChange.Operation.ADD; -import static org.sonar.server.permission.PermissionChange.Operation.REMOVE; - -public class UserPermissionChangerTest { - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT); - private PermissionService permissionService = new PermissionServiceImpl(resourceTypes); - private UserPermissionChanger underTest = new UserPermissionChanger(db.getDbClient()); - private OrganizationDto org1; - private OrganizationDto org2; - private UserDto user1; - private UserDto user2; - private ComponentDto privateProject; - private ComponentDto publicProject; - - @Before - public void setUp() throws Exception { - org1 = db.organizations().insert(); - org2 = db.organizations().insert(); - user1 = db.users().insertUser(); - user2 = db.users().insertUser(); - privateProject = db.components().insertPrivateProject(org1); - publicProject = db.components().insertPublicProject(org1); - } - - @Test - public void apply_adds_any_organization_permission_to_user() { - permissionService.getAllOrganizationPermissions().stream() - .forEach(perm -> { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), perm.getKey(), null, UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).contains(perm); - }); - } - - @Test - public void apply_removes_any_organization_permission_to_user() { - // give ADMIN perm to user2 so that user1 is not the only one with this permission and it can be removed from user1 - db.users().insertPermissionOnUser(org1, user2, OrganizationPermission.ADMINISTER); - permissionService.getAllOrganizationPermissions().stream() - .forEach(perm -> db.users().insertPermissionOnUser(org1, user1, perm)); - assertThat(db.users().selectPermissionsOfUser(user1, org1)) - .containsOnly(permissionService.getAllOrganizationPermissions().toArray(new OrganizationPermission[0])); - - permissionService.getAllOrganizationPermissions().stream() - .forEach(perm -> { - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), perm.getKey(), null, UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).doesNotContain(perm); - }); - } - - @Test - public void apply_has_no_effect_when_adding_permission_USER_on_a_public_project() { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), USER, new ProjectId(publicProject), UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, publicProject)).doesNotContain(USER); - } - - @Test - public void apply_has_no_effect_when_adding_permission_CODEVIEWER_on_a_public_project() { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), CODEVIEWER, new ProjectId(publicProject), UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, publicProject)).doesNotContain(CODEVIEWER); - } - - @Test - public void apply_adds_permission_ADMIN_on_a_public_project() { - applyAddsPermissionOnAPublicProject(ADMIN); - } - - @Test - public void apply_adds_permission_ISSUE_ADMIN_on_a_public_project() { - applyAddsPermissionOnAPublicProject(ISSUE_ADMIN); - } - - @Test - public void apply_adds_permission_SCAN_EXECUTION_on_a_public_project() { - applyAddsPermissionOnAPublicProject(SCAN_EXECUTION); - } - - private void applyAddsPermissionOnAPublicProject(String permission) { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), permission, new ProjectId(publicProject), UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, publicProject)).containsOnly(permission); - } - - @Test - public void apply_fails_with_BadRequestException_when_removing_permission_USER_from_a_public_project() { - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), USER, new ProjectId(publicProject), UserId.from(user1), permissionService); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission user can't be removed from a public component"); - - apply(change); - } - - @Test - public void apply_fails_with_BadRequestException_when_removing_permission_CODEVIEWER_from_a_public_project() { - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), CODEVIEWER, new ProjectId(publicProject), UserId.from(user1), permissionService); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Permission codeviewer can't be removed from a public component"); - - apply(change); - } - - @Test - public void apply_removes_permission_ADMIN_from_a_public_project() { - applyRemovesPermissionFromPublicProject(ADMIN); - } - - @Test - public void apply_removes_permission_ISSUE_ADMIN_from_a_public_project() { - applyRemovesPermissionFromPublicProject(ISSUE_ADMIN); - } - - @Test - public void apply_removes_permission_SCAN_EXECUTION_from_a_public_project() { - applyRemovesPermissionFromPublicProject(SCAN_EXECUTION); - } - - private void applyRemovesPermissionFromPublicProject(String permission) { - db.users().insertProjectPermissionOnUser(user1, permission, publicProject); - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), permission, new ProjectId(publicProject), UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, publicProject)).isEmpty(); - } - - @Test - public void apply_adds_any_permission_to_a_private_project() { - permissionService.getAllProjectPermissions() - .forEach(permission -> { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), permission, new ProjectId(privateProject), UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).contains(permission); - }); - } - - @Test - public void apply_removes_any_permission_from_a_private_project() { - permissionService.getAllProjectPermissions() - .forEach(permission -> db.users().insertProjectPermissionOnUser(user1, permission, privateProject)); - - permissionService.getAllProjectPermissions() - .forEach(permission -> { - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), permission, new ProjectId(privateProject), UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).doesNotContain(permission); - }); - } - - @Test - public void add_global_permission_to_user() { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), SCAN_EXECUTION, null, UserId.from(user1), permissionService); - - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).containsOnly(SCAN); - assertThat(db.users().selectPermissionsOfUser(user1, org2)).isEmpty(); - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).isEmpty(); - assertThat(db.users().selectPermissionsOfUser(user2, org1)).isEmpty(); - assertThat(db.users().selectProjectPermissionsOfUser(user2, privateProject)).isEmpty(); - } - - @Test - public void add_project_permission_to_user() { - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), ISSUE_ADMIN, new ProjectId(privateProject), UserId.from(user1), permissionService); - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).isEmpty(); - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).contains(ISSUE_ADMIN); - assertThat(db.users().selectPermissionsOfUser(user2, org1)).isEmpty(); - assertThat(db.users().selectProjectPermissionsOfUser(user2, privateProject)).isEmpty(); - } - - @Test - public void do_nothing_when_adding_global_permission_that_already_exists() { - db.users().insertPermissionOnUser(org1, user1, ADMINISTER_QUALITY_GATES); - - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), QUALITY_GATE_ADMIN, null, UserId.from(user1), permissionService); - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).containsOnly(ADMINISTER_QUALITY_GATES); - } - - @Test - public void fail_to_add_global_permission_on_project() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Invalid project permission 'gateadmin'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]"); - - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), QUALITY_GATE_ADMIN, new ProjectId(privateProject), UserId.from(user1), permissionService); - apply(change); - } - - @Test - public void fail_to_add_project_permission_on_organization() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Invalid global permission 'issueadmin'. Valid values are [admin, gateadmin, profileadmin, provisioning, scan]"); - - UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), ISSUE_ADMIN, null, UserId.from(user1), permissionService); - apply(change); - } - - @Test - public void remove_global_permission_from_user() { - db.users().insertPermissionOnUser(org1, user1, QUALITY_GATE_ADMIN); - db.users().insertPermissionOnUser(org1, user1, SCAN_EXECUTION); - db.users().insertPermissionOnUser(org2, user1, QUALITY_GATE_ADMIN); - db.users().insertPermissionOnUser(org1, user2, QUALITY_GATE_ADMIN); - db.users().insertProjectPermissionOnUser(user1, ISSUE_ADMIN, privateProject); - - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), QUALITY_GATE_ADMIN, null, UserId.from(user1), permissionService); - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).containsOnly(SCAN); - assertThat(db.users().selectPermissionsOfUser(user1, org2)).containsOnly(ADMINISTER_QUALITY_GATES); - assertThat(db.users().selectPermissionsOfUser(user2, org1)).containsOnly(ADMINISTER_QUALITY_GATES); - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).containsOnly(ISSUE_ADMIN); - } - - @Test - public void remove_project_permission_from_user() { - ComponentDto project2 = db.components().insertPrivateProject(org1); - db.users().insertPermissionOnUser(user1, ADMINISTER_QUALITY_GATES); - db.users().insertProjectPermissionOnUser(user1, ISSUE_ADMIN, privateProject); - db.users().insertProjectPermissionOnUser(user1, USER, privateProject); - db.users().insertProjectPermissionOnUser(user2, ISSUE_ADMIN, privateProject); - db.users().insertProjectPermissionOnUser(user1, ISSUE_ADMIN, project2); - - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), ISSUE_ADMIN, new ProjectId(privateProject), UserId.from(user1), permissionService); - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).containsOnly(USER); - assertThat(db.users().selectProjectPermissionsOfUser(user2, privateProject)).containsOnly(ISSUE_ADMIN); - assertThat(db.users().selectProjectPermissionsOfUser(user1, project2)).containsOnly(ISSUE_ADMIN); - } - - @Test - public void do_not_fail_if_removing_a_global_permission_that_does_not_exist() { - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), QUALITY_GATE_ADMIN, null, UserId.from(user1), permissionService); - apply(change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).isEmpty(); - } - - @Test - public void do_not_fail_if_removing_a_project_permission_that_does_not_exist() { - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), ISSUE_ADMIN, new ProjectId(privateProject), UserId.from(user1), permissionService); - apply(change); - - assertThat(db.users().selectProjectPermissionsOfUser(user1, privateProject)).isEmpty(); - } - - @Test - public void fail_to_remove_admin_global_permission_if_no_more_admins() { - db.users().insertPermissionOnUser(org1, user1, SYSTEM_ADMIN); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Last user with permission 'admin'. Permission cannot be removed."); - - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), SYSTEM_ADMIN, null, UserId.from(user1), permissionService); - underTest.apply(db.getSession(), change); - } - - @Test - public void remove_admin_user_if_still_other_admins() { - db.users().insertPermissionOnUser(org1, user1, ADMINISTER); - GroupDto admins = db.users().insertGroup(org1, "admins"); - db.users().insertMember(admins, user2); - db.users().insertPermissionOnGroup(admins, ADMINISTER); - - UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), ADMINISTER.getKey(), null, UserId.from(user1), permissionService); - underTest.apply(db.getSession(), change); - - assertThat(db.users().selectPermissionsOfUser(user1, org1)).isEmpty(); - } - - private void apply(UserPermissionChange change) { - underTest.apply(db.getSession(), change); - db.commit(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java index 812b3d9254b..884c7d343de 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java @@ -25,6 +25,7 @@ import org.sonar.api.config.Settings; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.server.setting.SettingsChangeNotifier; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/SettingsChangeNotifierTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/SettingsChangeNotifierTest.java deleted file mode 100644 index 973f8e73d64..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/SettingsChangeNotifierTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.platform; - -import org.junit.Test; -import org.sonar.api.config.GlobalPropertyChangeHandler; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class SettingsChangeNotifierTest { - @Test - public void onGlobalPropertyChange() { - GlobalPropertyChangeHandler handler = mock(GlobalPropertyChangeHandler.class); - SettingsChangeNotifier notifier = new SettingsChangeNotifier(new GlobalPropertyChangeHandler[] {handler}); - - notifier.onGlobalPropertyChange("foo", "bar"); - - verify(handler).onChange(argThat(change -> change.getKey().equals("foo") && change.getNewValue().equals("bar"))); - } - - @Test - public void no_handlers() { - SettingsChangeNotifier notifier = new SettingsChangeNotifier(); - - assertThat(notifier.changeHandlers).isEmpty(); - - // does not fail - notifier.onGlobalPropertyChange("foo", "bar"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java deleted file mode 100644 index f984cd9bd1e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.base.Optional; -import java.io.File; -import java.net.URI; -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.mockito.ArgumentMatcher; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.sonar.api.utils.HttpDownloader; -import org.sonar.core.platform.PluginInfo; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.platform.ServerFileSystem; -import org.sonar.updatecenter.common.Plugin; -import org.sonar.updatecenter.common.Release; -import org.sonar.updatecenter.common.UpdateCenter; -import org.sonar.updatecenter.common.Version; - -import static com.google.common.collect.Lists.newArrayList; -import static org.apache.commons.io.FileUtils.copyFileToDirectory; -import static org.apache.commons.io.FileUtils.touch; -import static org.apache.commons.io.FilenameUtils.separatorsToUnix; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.updatecenter.common.Version.create; - -public class PluginDownloaderTest { - - @Rule - public TemporaryFolder testFolder = new TemporaryFolder(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - private File downloadDir; - private UpdateCenterMatrixFactory updateCenterMatrixFactory; - private UpdateCenter updateCenter; - private HttpDownloader httpDownloader; - private PluginDownloader pluginDownloader; - - @Before - public void before() throws Exception { - updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class); - updateCenter = mock(UpdateCenter.class); - when(updateCenterMatrixFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.of(updateCenter)); - - httpDownloader = mock(HttpDownloader.class); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock inv) throws Throwable { - File toFile = (File) inv.getArguments()[1]; - touch(toFile); - return null; - } - }).when(httpDownloader).download(any(URI.class), any(File.class)); - - ServerFileSystem fs = mock(ServerFileSystem.class); - downloadDir = testFolder.newFolder("downloads"); - when(fs.getDownloadedPluginsDir()).thenReturn(downloadDir); - - pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, fs); - } - - @After - public void stop() { - pluginDownloader.stop(); - } - - @Test - public void clean_temporary_files_at_startup() throws Exception { - touch(new File(downloadDir, "sonar-php.jar")); - touch(new File(downloadDir, "sonar-js.jar.tmp")); - assertThat(downloadDir.listFiles()).hasSize(2); - pluginDownloader.start(); - - File[] files = downloadDir.listFiles(); - assertThat(files).hasSize(1); - assertThat(files[0].getName()).isEqualTo("sonar-php.jar"); - } - - @Test - public void download_from_url() { - Plugin test = Plugin.factory("test"); - Release test10 = new Release(test, "1.0").setDownloadUrl("http://server/test-1.0.jar"); - test.addRelease(test10); - - when(updateCenter.findInstallablePlugins("foo", create("1.0"))).thenReturn(newArrayList(test10)); - - pluginDownloader.start(); - pluginDownloader.download("foo", create("1.0")); - - // SONAR-4523: do not corrupt JAR files when restarting the server while a plugin is being downloaded. - // The JAR file is downloaded in a temp file - verify(httpDownloader).download(any(URI.class), argThat(new HasFileName("test-1.0.jar.tmp"))); - assertThat(new File(downloadDir, "test-1.0.jar")).exists(); - assertThat(new File(downloadDir, "test-1.0.jar.tmp")).doesNotExist(); - } - - @Test - public void download_when_update_center_is_unavailable_with_no_exception_thrown() { - when(updateCenterMatrixFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); - - Plugin test = Plugin.factory("test"); - Release test10 = new Release(test, "1.0").setDownloadUrl("http://server/test-1.0.jar"); - test.addRelease(test10); - - pluginDownloader.start(); - pluginDownloader.download("foo", create("1.0")); - } - - /** - * SONAR-4685 - */ - @Test - public void download_from_redirect_url() { - Plugin test = Plugin.factory("plugintest"); - Release test10 = new Release(test, "1.0").setDownloadUrl("http://server/redirect?r=release&g=test&a=test&v=1.0&e=jar"); - test.addRelease(test10); - - when(updateCenter.findInstallablePlugins("foo", create("1.0"))).thenReturn(newArrayList(test10)); - - pluginDownloader.start(); - pluginDownloader.download("foo", create("1.0")); - - // SONAR-4523: do not corrupt JAR files when restarting the server while a plugin is being downloaded. - // The JAR file is downloaded in a temp file - verify(httpDownloader).download(any(URI.class), argThat(new HasFileName("plugintest-1.0.jar.tmp"))); - assertThat(new File(downloadDir, "plugintest-1.0.jar")).exists(); - assertThat(new File(downloadDir, "plugintest-1.0.jar.tmp")).doesNotExist(); - } - - @Test - public void throw_exception_if_download_dir_is_invalid() throws Exception { - ServerFileSystem fs = mock(ServerFileSystem.class); - // download dir is a file instead of being a directory - File downloadDir = testFolder.newFile(); - when(fs.getDownloadedPluginsDir()).thenReturn(downloadDir); - - pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, fs); - try { - pluginDownloader.start(); - fail(); - } catch (IllegalStateException e) { - // ok - } - } - - @Test - public void fail_if_no_compatible_plugin_found() { - expectedException.expect(BadRequestException.class); - - pluginDownloader.download("foo", create("1.0")); - } - - @Test - public void download_from_file() throws Exception { - Plugin test = Plugin.factory("test"); - File file = testFolder.newFile("test-1.0.jar"); - file.createNewFile(); - Release test10 = new Release(test, "1.0").setDownloadUrl("file://" + separatorsToUnix(file.getCanonicalPath())); - test.addRelease(test10); - - when(updateCenter.findInstallablePlugins("foo", create("1.0"))).thenReturn(newArrayList(test10)); - - pluginDownloader.start(); - pluginDownloader.download("foo", create("1.0")); - verify(httpDownloader, never()).download(any(URI.class), any(File.class)); - assertThat(noDownloadedFiles()).isGreaterThan(0); - } - - @Test - public void throw_exception_if_could_not_download() { - Plugin test = Plugin.factory("test"); - Release test10 = new Release(test, "1.0").setDownloadUrl("file://not_found"); - test.addRelease(test10); - - when(updateCenter.findInstallablePlugins("foo", create("1.0"))).thenReturn(newArrayList(test10)); - - pluginDownloader.start(); - try { - pluginDownloader.download("foo", create("1.0")); - fail(); - } catch (IllegalStateException e) { - // ok - } - } - - @Test - public void throw_exception_if_download_fail() { - Plugin test = Plugin.factory("test"); - Release test10 = new Release(test, "1.0").setDownloadUrl("http://server/test-1.0.jar"); - test.addRelease(test10); - when(updateCenter.findInstallablePlugins("foo", create("1.0"))).thenReturn(newArrayList(test10)); - - doThrow(new RuntimeException()).when(httpDownloader).download(any(URI.class), any(File.class)); - - pluginDownloader.start(); - try { - pluginDownloader.download("foo", create("1.0")); - fail(); - } catch (IllegalStateException e) { - // ok - } - } - - @Test - public void read_download_folder() throws Exception { - pluginDownloader.start(); - assertThat(noDownloadedFiles()).isZero(); - - copyFileToDirectory(TestProjectUtils.jarOf("test-base-plugin"), downloadDir); - - assertThat(pluginDownloader.getDownloadedPlugins()).hasSize(1); - PluginInfo info = pluginDownloader.getDownloadedPlugins().iterator().next(); - assertThat(info.getKey()).isEqualTo("testbase"); - assertThat(info.getName()).isEqualTo("Base Plugin"); - assertThat(info.getVersion()).isEqualTo(Version.create("0.1-SNAPSHOT")); - assertThat(info.getMainClass()).isEqualTo("BasePlugin"); - } - - @Test - public void getDownloadedPluginFilenames_reads_plugin_info_of_files_in_download_folder() throws Exception { - pluginDownloader.start(); - assertThat(pluginDownloader.getDownloadedPlugins()).hasSize(0); - - File file1 = new File(downloadDir, "file1.jar"); - file1.createNewFile(); - File file2 = new File(downloadDir, "file2.jar"); - file2.createNewFile(); - - assertThat(noDownloadedFiles()).isEqualTo(2); - } - - @Test - public void cancel_downloads() throws Exception { - File file1 = new File(downloadDir, "file1.jar"); - file1.createNewFile(); - File file2 = new File(downloadDir, "file2.jar"); - file2.createNewFile(); - - pluginDownloader.start(); - assertThat(noDownloadedFiles()).isGreaterThan(0); - pluginDownloader.cancelDownloads(); - assertThat(noDownloadedFiles()).isZero(); - } - - private int noDownloadedFiles() { - return downloadDir.listFiles((file, name) -> name.endsWith(".jar")).length; - } - - // SONAR-5011 - @Test - public void download_common_transitive_dependency() { - Plugin test1 = Plugin.factory("test1"); - Release test1R = new Release(test1, "1.0").setDownloadUrl("http://server/test1-1.0.jar"); - test1.addRelease(test1R); - - Plugin test2 = Plugin.factory("test2"); - Release test2R = new Release(test2, "1.0").setDownloadUrl("http://server/test2-1.0.jar"); - test2.addRelease(test2R); - - Plugin testDep = Plugin.factory("testdep"); - Release testDepR = new Release(testDep, "1.0").setDownloadUrl("http://server/testdep-1.0.jar"); - testDep.addRelease(testDepR); - - when(updateCenter.findInstallablePlugins("test1", create("1.0"))).thenReturn(newArrayList(test1R, testDepR)); - when(updateCenter.findInstallablePlugins("test2", create("1.0"))).thenReturn(newArrayList(test2R, testDepR)); - - pluginDownloader.start(); - pluginDownloader.download("test1", create("1.0")); - pluginDownloader.download("test2", create("1.0")); - - assertThat(new File(downloadDir, "test1-1.0.jar")).exists(); - assertThat(new File(downloadDir, "test2-1.0.jar")).exists(); - assertThat(new File(downloadDir, "testdep-1.0.jar")).exists(); - } - - class HasFileName implements ArgumentMatcher<File> { - private final String name; - - HasFileName(String name) { - this.name = name; - } - - @Override - public boolean matches(File file) { - return file.getName().equals(name); - } - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginFileSystemTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginFileSystemTest.java deleted file mode 100644 index bc353f99778..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginFileSystemTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.core.platform.PluginInfo; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.plugins.PluginFileSystem.PROPERTY_PLUGIN_COMPRESSION_ENABLE; - -public class PluginFileSystemTest { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - private MapSettings settings = new MapSettings(); - private Path targetJarPath; - private Path targetFolder; - private Path sourceFolder; - - @Before - public void setUp() throws IOException { - sourceFolder = temp.newFolder("source").toPath(); - targetFolder = temp.newFolder("target").toPath(); - targetJarPath = targetFolder.resolve("test.jar"); - Files.createFile(targetJarPath); - } - - @Test - public void add_plugin_to_list_of_installed_plugins() throws IOException { - File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - PluginInfo info = new PluginInfo("foo"); - - PluginFileSystem underTest = new PluginFileSystem(settings.asConfig()); - underTest.addInstalledPlugin(info, jar); - - assertThat(underTest.getInstalledFiles()).hasSize(1); - InstalledPlugin installedPlugin = underTest.getInstalledPlugin("foo").get(); - assertThat(installedPlugin.getCompressedJar()).isNull(); - assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(jar.toPath()); - assertThat(installedPlugin.getPluginInfo()).isSameAs(info); - } - - @Test - public void compress_jar_if_compression_enabled() throws IOException { - File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - PluginInfo info = new PluginInfo("foo").setJarFile(jar); - // the JAR is copied somewhere else in order to be loaded by classloaders - File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - - settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true); - PluginFileSystem underTest = new PluginFileSystem(settings.asConfig()); - underTest.addInstalledPlugin(info, loadedJar); - - assertThat(underTest.getInstalledFiles()).hasSize(1); - - InstalledPlugin installedPlugin = underTest.getInstalledPlugin("foo").get(); - assertThat(installedPlugin.getPluginInfo()).isSameAs(info); - assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath()); - assertThat(installedPlugin.getCompressedJar().getFile()) - .exists() - .isFile() - .hasName("sonar-foo-plugin.pack.gz") - .hasParent(loadedJar.getParentFile()); - } - - @Test - public void copy_and_use_existing_packed_jar_if_compression_enabled() throws IOException { - File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - File packedJar = touch(jar.getParentFile(), "sonar-foo-plugin.pack.gz"); - PluginInfo info = new PluginInfo("foo").setJarFile(jar); - // the JAR is copied somewhere else in order to be loaded by classloaders - File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar"); - - settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true); - PluginFileSystem underTest = new PluginFileSystem(settings.asConfig()); - underTest.addInstalledPlugin(info, loadedJar); - - assertThat(underTest.getInstalledFiles()).hasSize(1); - - InstalledPlugin installedPlugin = underTest.getInstalledPlugin("foo").get(); - assertThat(installedPlugin.getPluginInfo()).isSameAs(info); - assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath()); - assertThat(installedPlugin.getCompressedJar().getFile()) - .exists() - .isFile() - .hasName(packedJar.getName()) - .hasParent(loadedJar.getParentFile()) - .hasSameContentAs(packedJar); - } - - private static File touch(File dir, String filename) throws IOException { - File file = new File(dir, filename); - FileUtils.write(file, RandomStringUtils.random(10)); - return file; - } - - // - // @Test - // public void should_use_deployed_packed_file() throws IOException { - // Path packedPath = sourceFolder.resolve("test.pack.gz"); - // Files.write(packedPath, new byte[] {1, 2, 3}); - // - // settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true); - // underTest = new PluginFileSystem(settings.asConfig()); - // underTest.compressJar("key", sourceFolder, targetJarPath); - // - // assertThat(Files.list(targetFolder)).containsOnly(targetJarPath, targetFolder.resolve("test.pack.gz")); - // assertThat(underTest.getPlugins()).hasSize(1); - // assertThat(underTest.getPlugins().get("key").getFilename()).isEqualTo("test.pack.gz"); - // - // // check that the file was copied, not generated - // assertThat(targetFolder.resolve("test.pack.gz")).hasSameContentAs(packedPath); - // } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java deleted file mode 100644 index 20eae5f2781..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginUninstallerTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.File; -import java.io.IOException; -import org.apache.commons.io.FileUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.server.platform.ServerFileSystem; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class PluginUninstallerTest { - @Rule - public TemporaryFolder testFolder = new TemporaryFolder(); - - @Rule - public ExpectedException exception = ExpectedException.none(); - - private File uninstallDir; - private PluginUninstaller underTest; - private ServerPluginRepository serverPluginRepository; - private ServerFileSystem fs; - - @Before - public void setUp() throws IOException { - serverPluginRepository = mock(ServerPluginRepository.class); - uninstallDir = testFolder.newFolder("uninstall"); - fs = mock(ServerFileSystem.class); - when(fs.getUninstalledPluginsDir()).thenReturn(uninstallDir); - underTest = new PluginUninstaller(serverPluginRepository, fs); - } - - @Test - public void uninstall() { - when(serverPluginRepository.hasPlugin("plugin")).thenReturn(true); - underTest.uninstall("plugin"); - verify(serverPluginRepository).uninstall("plugin", uninstallDir); - } - - @Test - public void fail_uninstall_if_plugin_not_installed() { - when(serverPluginRepository.hasPlugin("plugin")).thenReturn(false); - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Plugin [plugin] is not installed"); - underTest.uninstall("plugin"); - verifyZeroInteractions(serverPluginRepository); - } - - @Test - public void create_uninstall_dir() { - File dir = new File(testFolder.getRoot(), "dir"); - when(fs.getUninstalledPluginsDir()).thenReturn(dir); - underTest = new PluginUninstaller(serverPluginRepository, fs); - underTest.start(); - assertThat(dir).isDirectory(); - } - - @Test - public void cancel() { - underTest.cancelUninstalls(); - verify(serverPluginRepository).cancelUninstalls(uninstallDir); - verifyNoMoreInteractions(serverPluginRepository); - } - - @Test - public void list_uninstalled_plugins() throws IOException { - new File(uninstallDir, "file1").createNewFile(); - copyTestPluginTo("test-base-plugin", uninstallDir); - assertThat(underTest.getUninstalledPlugins()).extracting("key").containsOnly("testbase"); - } - - private File copyTestPluginTo(String testPluginName, File toDir) throws IOException { - File jar = TestProjectUtils.jarOf(testPluginName); - // file is copied because it's supposed to be moved by the test - FileUtils.copyFileToDirectory(jar, toDir); - return new File(toDir, jar.getName()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarExploderTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarExploderTest.java deleted file mode 100644 index 8f4d928cd4c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarExploderTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.io.File; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.core.platform.ExplodedPlugin; -import org.sonar.core.platform.PluginInfo; -import org.sonar.server.platform.ServerFileSystem; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ServerPluginJarExploderTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - private ServerFileSystem fs = mock(ServerFileSystem.class); - private PluginFileSystem pluginFileSystem = mock(PluginFileSystem.class); - private ServerPluginJarExploder underTest = new ServerPluginJarExploder(fs, pluginFileSystem); - - @Test - public void copy_all_classloader_files_to_dedicated_directory() throws Exception { - File deployDir = temp.newFolder(); - when(fs.getDeployedPluginsDir()).thenReturn(deployDir); - File sourceJar = TestProjectUtils.jarOf("test-libs-plugin"); - PluginInfo info = PluginInfo.create(sourceJar); - - ExplodedPlugin exploded = underTest.explode(info); - - // all the files loaded by classloaders (JAR + META-INF/libs/*.jar) are copied to the dedicated directory - // web/deploy/{pluginKey} - File pluginDeployDir = new File(deployDir, "testlibs"); - - assertThat(exploded.getKey()).isEqualTo("testlibs"); - assertThat(exploded.getMain()).isFile().exists().hasParent(pluginDeployDir); - assertThat(exploded.getLibs()).extracting("name").containsOnly("commons-daemon-1.0.15.jar", "commons-email-20030310.165926.jar"); - for (File lib : exploded.getLibs()) { - assertThat(lib).exists().isFile(); - assertThat(lib.getCanonicalPath()).startsWith(pluginDeployDir.getCanonicalPath()); - } - File targetJar = new File(fs.getDeployedPluginsDir(), "testlibs/test-libs-plugin-0.1-SNAPSHOT.jar"); - verify(pluginFileSystem).addInstalledPlugin(info, targetJar); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java deleted file mode 100644 index e426c9ebfea..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -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.mockito.Mockito; -import org.sonar.api.SonarRuntime; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.log.LogTester; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.platform.PluginLoader; -import org.sonar.server.platform.ServerFileSystem; -import org.sonar.updatecenter.common.Version; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ServerPluginRepositoryTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Rule - public LogTester logs = new LogTester(); - - private SonarRuntime runtime = mock(SonarRuntime.class); - private ServerFileSystem fs = mock(ServerFileSystem.class, Mockito.RETURNS_DEEP_STUBS); - private PluginLoader pluginLoader = mock(PluginLoader.class); - private ServerPluginRepository underTest = new ServerPluginRepository(runtime, fs, pluginLoader); - - @Before - public void setUp() throws IOException { - when(fs.getDeployedPluginsDir()).thenReturn(temp.newFolder()); - when(fs.getDownloadedPluginsDir()).thenReturn(temp.newFolder()); - when(fs.getHomeDir()).thenReturn(temp.newFolder()); - when(fs.getInstalledPluginsDir()).thenReturn(temp.newFolder()); - when(fs.getTempDir()).thenReturn(temp.newFolder()); - when(runtime.getApiVersion()).thenReturn(org.sonar.api.utils.Version.parse("5.2")); - } - - @After - public void tearDown() { - underTest.stop(); - } - - @Test - public void standard_startup_loads_installed_plugins() throws Exception { - copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase"); - } - - @Test - public void no_plugins_at_all_on_startup() { - underTest.start(); - - assertThat(underTest.getPluginInfos()).isEmpty(); - assertThat(underTest.getPluginInfosByKeys()).isEmpty(); - assertThat(underTest.hasPlugin("testbase")).isFalse(); - } - - @Test - public void fail_if_multiple_jars_for_same_installed_plugin_on_startup() throws Exception { - copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - copyTestPluginTo("test-base-plugin-v2", fs.getInstalledPluginsDir()); - - try { - underTest.start(); - fail(); - } catch (MessageException e) { - assertThat(e) - .hasMessageStartingWith("Found two versions of the plugin Base Plugin [testbase] in the directory extensions/plugins. Please remove one of ") - // order is not guaranteed, so assertion is split - .hasMessageContaining("test-base-plugin-0.1-SNAPSHOT.jar") - .hasMessageContaining("test-base-plugin-0.2-SNAPSHOT.jar"); - } - } - - @Test - public void install_downloaded_plugins_on_startup() throws Exception { - File downloadedJar = copyTestPluginTo("test-base-plugin", fs.getDownloadedPluginsDir()); - - underTest.start(); - - // plugin is moved to extensions/plugins then loaded - assertThat(downloadedJar).doesNotExist(); - assertThat(new File(fs.getInstalledPluginsDir(), downloadedJar.getName())).isFile().exists(); - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase"); - } - - @Test - public void downloaded_file_overrides_existing_installed_file_on_startup() throws Exception { - File installedV1 = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - File downloadedV2 = copyTestPluginTo("test-base-plugin-v2", fs.getDownloadedPluginsDir()); - - underTest.start(); - - // plugin is moved to extensions/plugins and replaces v1 - assertThat(downloadedV2).doesNotExist(); - assertThat(installedV1).doesNotExist(); - assertThat(new File(fs.getInstalledPluginsDir(), downloadedV2.getName())).exists(); - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase"); - assertThat(underTest.getPluginInfo("testbase").getVersion()).isEqualTo(Version.create("0.2-SNAPSHOT")); - } - - @Test - public void blacklisted_plugin_is_automatically_uninstalled_on_startup() throws Exception { - underTest.setBlacklistedPluginKeys(ImmutableSet.of("testbase", "issuesreport")); - File jar = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - // plugin is not installed and file is deleted - assertThat(underTest.getPluginInfos()).isEmpty(); - assertThat(jar).doesNotExist(); - } - - @Test - public void test_plugin_requirements_at_startup() throws Exception { - copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - // both plugins are installed - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase", "testrequire"); - } - - @Test - public void plugin_is_ignored_if_required_plugin_is_missing_at_startup() throws Exception { - copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - // plugin is not installed as test-base-plugin is missing - assertThat(underTest.getPluginInfosByKeys()).isEmpty(); - } - - @Test - public void plugin_is_ignored_if_required_plugin_is_too_old_at_startup() throws Exception { - copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - copyTestPluginTo("test-requirenew-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - // the plugin "requirenew" is not installed as it requires base 0.2+ to be installed. - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase"); - } - - @Test - public void fail_if_plugin_does_not_support_sq_version() throws Exception { - when(runtime.getApiVersion()).thenReturn(org.sonar.api.utils.Version.parse("1.0")); - copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - - try { - underTest.start(); - fail(); - } catch (MessageException e) { - assertThat(e).hasMessage("Plugin Base Plugin [testbase] requires at least SonarQube 4.5.4"); - } - } - - @Test - public void uninstall() throws Exception { - File installedJar = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - File uninstallDir = temp.newFolder("uninstallDir"); - - underTest.start(); - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase"); - underTest.uninstall("testbase", uninstallDir); - - assertThat(installedJar).doesNotExist(); - // still up. Will be dropped after next startup - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase"); - assertThat(uninstallDir.list()).containsOnly(installedJar.getName()); - } - - @Test - public void uninstall_dependents() throws Exception { - File base = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - File extension = copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir()); - File uninstallDir = temp.newFolder("uninstallDir"); - - underTest.start(); - assertThat(underTest.getPluginInfos()).hasSize(2); - underTest.uninstall("testbase", uninstallDir); - assertThat(base).doesNotExist(); - assertThat(extension).doesNotExist(); - assertThat(uninstallDir.list()).containsOnly(base.getName(), extension.getName()); - } - - @Test - public void dont_uninstall_non_existing_dependents() throws IOException { - File base = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - File extension = copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir()); - File uninstallDir = temp.newFolder("uninstallDir"); - - underTest.start(); - assertThat(underTest.getPluginInfos()).hasSize(2); - underTest.uninstall("testrequire", uninstallDir); - assertThat(underTest.getPluginInfos()).hasSize(2); - - underTest.uninstall("testbase", uninstallDir); - assertThat(base).doesNotExist(); - assertThat(extension).doesNotExist(); - assertThat(uninstallDir.list()).containsOnly(base.getName(), extension.getName()); - } - - @Test - public void dont_uninstall_non_existing_files() throws IOException { - File base = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - File extension = copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir()); - File uninstallDir = temp.newFolder("uninstallDir"); - - underTest.start(); - assertThat(underTest.getPluginInfos()).hasSize(2); - underTest.uninstall("testbase", uninstallDir); - assertThat(underTest.getPluginInfos()).hasSize(2); - - underTest.uninstall("testbase", uninstallDir); - assertThat(base).doesNotExist(); - assertThat(extension).doesNotExist(); - assertThat(uninstallDir.list()).containsOnly(base.getName(), extension.getName()); - } - - @Test - public void install_plugin_and_its_extension_plugins_at_startup() throws Exception { - copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir()); - copyTestPluginTo("test-extend-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - // both plugins are installed - assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase", "testextend"); - } - - @Test - public void extension_plugin_is_ignored_if_base_plugin_is_missing_at_startup() throws Exception { - copyTestPluginTo("test-extend-plugin", fs.getInstalledPluginsDir()); - - underTest.start(); - - // plugin is not installed as its base plugin is not installed - assertThat(underTest.getPluginInfos()).isEmpty(); - } - - @Test - public void fail_to_get_missing_plugins() { - underTest.start(); - try { - underTest.getPluginInfo("unknown"); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Plugin [unknown] does not exist"); - } - - try { - underTest.getPluginInstance("unknown"); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Plugin [unknown] does not exist"); - } - } - - @Test - public void plugin_is_incompatible_if_no_entry_point_class() { - PluginInfo plugin = new PluginInfo("foo").setName("Foo"); - assertThat(ServerPluginRepository.isCompatible(plugin, runtime, Collections.emptyMap())).isFalse(); - assertThat(logs.logs()).contains("Plugin Foo [foo] is ignored because entry point class is not defined"); - } - - @Test - public void fail_when_views_is_installed() throws Exception { - copyTestPluginTo("fake-views-plugin", fs.getInstalledPluginsDir()); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Plugin 'views' is no longer compatible with this version of SonarQube"); - underTest.start(); - } - - @Test - public void fail_when_sqale_plugin_is_installed() throws Exception { - copyTestPluginTo("fake-sqale-plugin", fs.getInstalledPluginsDir()); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Plugin 'sqale' is no longer compatible with this version of SonarQube"); - underTest.start(); - } - - @Test - public void fail_when_report_is_installed() throws Exception { - copyTestPluginTo("fake-report-plugin", fs.getInstalledPluginsDir()); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Plugin 'report' is no longer compatible with this version of SonarQube"); - underTest.start(); - } - - /** - * Some plugins can only extend the classloader of base plugin, without declaring new extensions. - */ - @Test - public void plugin_is_compatible_if_no_entry_point_class_but_extend_other_plugin() { - PluginInfo basePlugin = new PluginInfo("base").setMainClass("org.bar.Bar"); - PluginInfo plugin = new PluginInfo("foo").setBasePlugin("base"); - Map<String, PluginInfo> plugins = ImmutableMap.of("base", basePlugin, "foo", plugin); - - assertThat(ServerPluginRepository.isCompatible(plugin, runtime, plugins)).isTrue(); - } - - @Test - public void getPluginInstance_throws_ISE_if_repo_is_not_started() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("not started yet"); - - underTest.getPluginInstance("foo"); - } - - @Test - public void getPluginInfo_throws_ISE_if_repo_is_not_started() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("not started yet"); - - underTest.getPluginInfo("foo"); - } - - @Test - public void hasPlugin_throws_ISE_if_repo_is_not_started() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("not started yet"); - - underTest.hasPlugin("foo"); - } - - @Test - public void getPluginInfos_throws_ISE_if_repo_is_not_started() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("not started yet"); - - underTest.getPluginInfos(); - } - - private File copyTestPluginTo(String testPluginName, File toDir) throws IOException { - File jar = TestProjectUtils.jarOf(testPluginName); - // file is copied because it's supposed to be moved by the test - FileUtils.copyFileToDirectory(jar, toDir); - return new File(toDir, jar.getName()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/TestPluginA.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/TestPluginA.java deleted file mode 100644 index 7952eb5799c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/TestPluginA.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import org.sonar.api.Plugin; - -public class TestPluginA implements Plugin { - @Override - public void define(Context context) { - - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/TestProjectUtils.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/TestProjectUtils.java deleted file mode 100644 index 9710a8689e4..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/TestProjectUtils.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.util.Collection; - -public class TestProjectUtils { - - /** - * Get the artifact of plugins stored in src/test/projects - */ - public static File jarOf(String dirName) { - File target = FileUtils.toFile(TestProjectUtils.class.getResource(String.format("/%s/target/", dirName))); - Collection<File> jars = FileUtils.listFiles(target, new String[] {"jar"}, false); - if (jars == null || jars.size() != 1) { - throw new IllegalArgumentException("Test project is badly defined: " + dirName); - } - return jars.iterator().next(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java deleted file mode 100644 index b1e50cba77c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.utils.SonarException; -import org.sonar.api.utils.UriReader; -import org.sonar.process.ProcessProperties; -import org.sonar.updatecenter.common.UpdateCenter; -import org.sonar.updatecenter.common.Version; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.guava.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class UpdateCenterClientTest { - - private static final String BASE_URL = "https://update.sonarsource.org"; - private UriReader reader = mock(UriReader.class); - private MapSettings settings = new MapSettings(); - private UpdateCenterClient underTest; - - @Before - public void startServer() throws Exception { - reader = mock(UriReader.class); - settings.setProperty(UpdateCenterClient.URL_PROPERTY, BASE_URL); - settings.setProperty(ProcessProperties.Property.SONAR_UPDATECENTER_ACTIVATE.getKey(), true); - underTest = new UpdateCenterClient(reader, settings.asConfig()); - } - - @Test - public void downloadUpdateCenter() throws URISyntaxException { - when(reader.readString(new URI(BASE_URL), StandardCharsets.UTF_8)).thenReturn("publicVersions=2.2,2.3"); - UpdateCenter plugins = underTest.getUpdateCenter().get(); - verify(reader, times(1)).readString(new URI(BASE_URL), StandardCharsets.UTF_8); - assertThat(plugins.getSonar().getVersions()).containsOnly(Version.create("2.2"), Version.create("2.3")); - assertThat(underTest.getLastRefreshDate()).isNotNull(); - } - - @Test - public void not_available_before_initialization() { - assertThat(underTest.getLastRefreshDate()).isNull(); - } - - @Test - public void ignore_connection_errors() { - when(reader.readString(any(URI.class), eq(StandardCharsets.UTF_8))).thenThrow(new SonarException()); - assertThat(underTest.getUpdateCenter()).isAbsent(); - } - - @Test - public void cache_data() throws Exception { - when(reader.readString(new URI(BASE_URL), StandardCharsets.UTF_8)).thenReturn("sonar.versions=2.2,2.3"); - - underTest.getUpdateCenter(); - underTest.getUpdateCenter(); - - verify(reader, times(1)).readString(new URI(BASE_URL), StandardCharsets.UTF_8); - } - - @Test - public void forceRefresh() throws Exception { - when(reader.readString(new URI(BASE_URL), StandardCharsets.UTF_8)).thenReturn("sonar.versions=2.2,2.3"); - - underTest.getUpdateCenter(); - underTest.getUpdateCenter(true); - - verify(reader, times(2)).readString(new URI(BASE_URL), StandardCharsets.UTF_8); - } - - @Test - public void update_center_is_null_when_property_is_false() { - settings.setProperty(ProcessProperties.Property.SONAR_UPDATECENTER_ACTIVATE.getKey(), false); - - assertThat(underTest.getUpdateCenter()).isAbsent(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterMatrixFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterMatrixFactoryTest.java deleted file mode 100644 index a71522a77d5..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterMatrixFactoryTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import com.google.common.base.Optional; -import org.junit.Test; -import org.sonar.api.SonarRuntime; -import org.sonar.updatecenter.common.UpdateCenter; - -import static org.assertj.guava.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class UpdateCenterMatrixFactoryTest { - - private UpdateCenterMatrixFactory underTest; - - @Test - public void return_absent_update_center() { - UpdateCenterClient updateCenterClient = mock(UpdateCenterClient.class); - when(updateCenterClient.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); - - underTest = new UpdateCenterMatrixFactory(updateCenterClient, mock(SonarRuntime.class), mock(InstalledPluginReferentialFactory.class)); - - Optional<UpdateCenter> updateCenter = underTest.getUpdateCenter(false); - - assertThat(updateCenter).isAbsent(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterServlet.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterServlet.java deleted file mode 100644 index d6d9904452d..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterServlet.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins; - -import javax.servlet.GenericServlet; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.util.Properties; - -public class UpdateCenterServlet extends GenericServlet { - - int count = 0; - - @Override - public void service(ServletRequest request, ServletResponse response) throws IOException { - count++; - Properties props = new Properties(); - props.setProperty("count", String.valueOf(count)); - props.setProperty("agent", ((HttpServletRequest)request).getHeader("User-Agent")); - props.store(response.getOutputStream(), null); - } -} - diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/edition/EditionBundledPluginsTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/edition/EditionBundledPluginsTest.java deleted file mode 100644 index 907768f56fa..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/edition/EditionBundledPluginsTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.edition; - -import java.util.Random; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.core.platform.PluginInfo; -import org.sonar.updatecenter.common.Plugin; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; - -public class EditionBundledPluginsTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private final Random random = new Random(); - - @Test - public void isEditionBundled_on_Plugin_fails_with_NPE_if_arg_is_null() { - expectedException.expect(NullPointerException.class); - - EditionBundledPlugins.isEditionBundled((Plugin) null); - } - - @Test - public void isEditionBundled_on_Plugin_returns_false_for_SonarSource_and_non_commercial_license() { - Plugin plugin = newPlugin(randomizeCase("SonarSource"), randomAlphanumeric(3)); - - assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isFalse(); - } - - @Test - public void isEditionBundled_on_Plugin_returns_false_for_license_SonarSource_and_non_SonarSource_organization() { - Plugin plugin = newPlugin(randomAlphanumeric(3), randomizeCase("SonarSource")); - - assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isFalse(); - } - - @Test - public void isEditionBundled_on_Plugin_returns_false_for_license_Commercial_and_non_SonarSource_organization() { - Plugin plugin = newPlugin(randomAlphanumeric(3), randomizeCase("Commercial")); - - assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isFalse(); - } - - @Test - public void isEditionBundled_on_Plugin_returns_true_for_organization_SonarSource_and_license_SonarSource_case_insensitive() { - Plugin plugin = newPlugin(randomizeCase("SonarSource"), randomizeCase("SonarSource")); - - assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isTrue(); - } - - @Test - public void isEditionBundled_on_Plugin_returns_true_for_organization_SonarSource_and_license_Commercial_case_insensitive() { - Plugin plugin = newPlugin(randomizeCase("SonarSource"), randomizeCase("Commercial")); - - assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isTrue(); - } - - @Test - public void isEditionBundled_on_PluginInfo_fails_with_NPE_if_arg_is_null() { - expectedException.expect(NullPointerException.class); - - EditionBundledPlugins.isEditionBundled((PluginInfo) null); - } - - @Test - public void isEditionBundled_on_PluginInfo_returns_false_for_SonarSource_and_non_commercial_license() { - PluginInfo pluginInfo = newPluginInfo(randomizeCase("SonarSource"), randomAlphanumeric(3)); - - assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isFalse(); - } - - @Test - public void isEditionBundled_on_PluginInfo_returns_false_for_license_SonarSource_and_non_SonarSource_organization() { - PluginInfo pluginInfo = newPluginInfo(randomAlphanumeric(3), randomizeCase("SonarSource")); - - assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isFalse(); - } - - @Test - public void isEditionBundled_on_PluginInfo_returns_false_for_license_Commercial_and_non_SonarSource_organization() { - PluginInfo pluginInfo = newPluginInfo(randomAlphanumeric(3), randomizeCase("Commercial")); - - assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isFalse(); - } - - @Test - public void isEditionBundled_on_PluginInfo_returns_true_for_organization_SonarSource_and_license_SonarSource_case_insensitive() { - PluginInfo pluginInfo = newPluginInfo(randomizeCase("SonarSource"), randomizeCase("SonarSource")); - - assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isTrue(); - } - - @Test - public void isEditionBundled_on_PluginINfo_returns_true_for_organization_SonarSource_and_license_Commercial_case_insensitive() { - PluginInfo pluginInfo = newPluginInfo(randomizeCase("SonarSource"), randomizeCase("Commercial")); - - assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isTrue(); - } - - private String randomizeCase(String s) { - return s.chars() - .map(c -> random.nextBoolean() ? Character.toUpperCase(c) : Character.toLowerCase(c)) - .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) - .toString(); - } - - private PluginInfo newPluginInfo(String organization, String license) { - PluginInfo pluginInfo = new PluginInfo(randomAlphanumeric(2)); - if (random.nextBoolean()) { - pluginInfo.setName(randomAlphanumeric(3)); - } - if (random.nextBoolean()) { - pluginInfo.setOrganizationUrl(randomAlphanumeric(4)); - } - if (random.nextBoolean()) { - pluginInfo.setIssueTrackerUrl(randomAlphanumeric(5)); - } - if (random.nextBoolean()) { - pluginInfo.setIssueTrackerUrl(randomAlphanumeric(6)); - } - if (random.nextBoolean()) { - pluginInfo.setBasePlugin(randomAlphanumeric(7)); - } - if (random.nextBoolean()) { - pluginInfo.setHomepageUrl(randomAlphanumeric(8)); - } - return pluginInfo - .setOrganizationName(organization) - .setLicense(license); - } - - private Plugin newPlugin(String organization, String license) { - Plugin plugin = Plugin.factory(randomAlphanumeric(2)); - if (random.nextBoolean()) { - plugin.setName(randomAlphanumeric(3)); - } - if (random.nextBoolean()) { - plugin.setOrganizationUrl(randomAlphanumeric(4)); - } - if (random.nextBoolean()) { - plugin.setTermsConditionsUrl(randomAlphanumeric(5)); - } - if (random.nextBoolean()) { - plugin.setIssueTrackerUrl(randomAlphanumeric(6)); - } - if (random.nextBoolean()) { - plugin.setCategory(randomAlphanumeric(7)); - } - if (random.nextBoolean()) { - plugin.setHomepageUrl(randomAlphanumeric(8)); - } - return plugin - .setLicense(license) - .setOrganization(organization); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java deleted file mode 100644 index 8085b643ede..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.Collections; -import java.util.Random; -import java.util.Set; -import java.util.stream.IntStream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mockito; -import org.sonar.core.util.stream.MoreCollectors; - -import static java.util.Collections.singleton; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; -import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; - -@RunWith(DataProviderRunner.class) -public class ProjectLifeCycleListenersImplTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ProjectLifeCycleListener listener1 = mock(ProjectLifeCycleListener.class); - private ProjectLifeCycleListener listener2 = mock(ProjectLifeCycleListener.class); - private ProjectLifeCycleListener listener3 = mock(ProjectLifeCycleListener.class); - private ProjectLifeCycleListenersImpl underTestNoListeners = new ProjectLifeCycleListenersImpl(); - private ProjectLifeCycleListenersImpl underTestWithListeners = new ProjectLifeCycleListenersImpl( - new ProjectLifeCycleListener[] {listener1, listener2, listener3}); - - @Test - public void onProjectsDeleted_throws_NPE_if_set_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("projects can't be null"); - - underTestWithListeners.onProjectsDeleted(null); - } - - @Test - public void onProjectsDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("projects can't be null"); - - underTestNoListeners.onProjectsDeleted(null); - } - - @Test - public void onProjectsDeleted_has_no_effect_if_set_is_empty() { - underTestNoListeners.onProjectsDeleted(Collections.emptySet()); - - underTestWithListeners.onProjectsDeleted(Collections.emptySet()); - verifyZeroInteractions(listener1, listener2, listener3); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_does_not_fail_if_there_is_no_listener(Set<Project> projects) { - underTestNoListeners.onProjectsDeleted(projects); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<Project> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - - underTestWithListeners.onProjectsDeleted(projects); - - inOrder.verify(listener1).onProjectsDeleted(same(projects)); - inOrder.verify(listener2).onProjectsDeleted(same(projects)); - inOrder.verify(listener3).onProjectsDeleted(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<Project> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - doThrow(new RuntimeException("Faking listener2 throwing an exception")) - .when(listener2) - .onProjectsDeleted(any()); - - underTestWithListeners.onProjectsDeleted(projects); - - inOrder.verify(listener1).onProjectsDeleted(same(projects)); - inOrder.verify(listener2).onProjectsDeleted(same(projects)); - inOrder.verify(listener3).onProjectsDeleted(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<Project> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - doThrow(new Error("Faking listener2 throwing an Error")) - .when(listener2) - .onProjectsDeleted(any()); - - underTestWithListeners.onProjectsDeleted(projects); - - inOrder.verify(listener1).onProjectsDeleted(same(projects)); - inOrder.verify(listener2).onProjectsDeleted(same(projects)); - inOrder.verify(listener3).onProjectsDeleted(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void onProjectBranchesDeleted_throws_NPE_if_set_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("projects can't be null"); - - underTestWithListeners.onProjectBranchesDeleted(null); - } - - @Test - public void onProjectBranchesDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("projects can't be null"); - - underTestNoListeners.onProjectBranchesDeleted(null); - } - - @Test - public void onProjectBranchesDeleted_has_no_effect_if_set_is_empty() { - underTestNoListeners.onProjectBranchesDeleted(Collections.emptySet()); - - underTestWithListeners.onProjectBranchesDeleted(Collections.emptySet()); - verifyZeroInteractions(listener1, listener2, listener3); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectBranchesDeleted_does_not_fail_if_there_is_no_listener(Set<Project> projects) { - underTestNoListeners.onProjectBranchesDeleted(projects); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectBranchesDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<Project> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - - underTestWithListeners.onProjectBranchesDeleted(projects); - - inOrder.verify(listener1).onProjectBranchesDeleted(same(projects)); - inOrder.verify(listener2).onProjectBranchesDeleted(same(projects)); - inOrder.verify(listener3).onProjectBranchesDeleted(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<Project> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - doThrow(new RuntimeException("Faking listener2 throwing an exception")) - .when(listener2) - .onProjectBranchesDeleted(any()); - - underTestWithListeners.onProjectBranchesDeleted(projects); - - inOrder.verify(listener1).onProjectBranchesDeleted(same(projects)); - inOrder.verify(listener2).onProjectBranchesDeleted(same(projects)); - inOrder.verify(listener3).onProjectBranchesDeleted(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<Project> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - doThrow(new Error("Faking listener2 throwing an Error")) - .when(listener2) - .onProjectBranchesDeleted(any()); - - underTestWithListeners.onProjectBranchesDeleted(projects); - - inOrder.verify(listener1).onProjectBranchesDeleted(same(projects)); - inOrder.verify(listener2).onProjectBranchesDeleted(same(projects)); - inOrder.verify(listener3).onProjectBranchesDeleted(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @DataProvider - public static Object[][] oneOrManyProjects() { - return new Object[][] { - {singleton(newUniqueProject())}, - {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueProject()).collect(MoreCollectors.toSet())} - }; - } - // SDSDS - - @Test - public void onProjectsRekeyed_throws_NPE_if_set_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("rekeyedProjects can't be null"); - - underTestWithListeners.onProjectsRekeyed(null); - } - - @Test - public void onProjectsRekeyed_throws_NPE_if_set_is_null_even_if_no_listeners() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("rekeyedProjects can't be null"); - - underTestNoListeners.onProjectsRekeyed(null); - } - - @Test - public void onProjectsRekeyed_has_no_effect_if_set_is_empty() { - underTestNoListeners.onProjectsRekeyed(Collections.emptySet()); - - underTestWithListeners.onProjectsRekeyed(Collections.emptySet()); - verifyZeroInteractions(listener1, listener2, listener3); - } - - @Test - @UseDataProvider("oneOrManyRekeyedProjects") - public void onProjectsRekeyed_does_not_fail_if_there_is_no_listener(Set<RekeyedProject> projects) { - underTestNoListeners.onProjectsRekeyed(projects); - } - - @Test - @UseDataProvider("oneOrManyRekeyedProjects") - public void onProjectsRekeyed_calls_all_listeners_in_order_of_addition_to_constructor(Set<RekeyedProject> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - - underTestWithListeners.onProjectsRekeyed(projects); - - inOrder.verify(listener1).onProjectsRekeyed(same(projects)); - inOrder.verify(listener2).onProjectsRekeyed(same(projects)); - inOrder.verify(listener3).onProjectsRekeyed(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - @UseDataProvider("oneOrManyRekeyedProjects") - public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Exception(Set<RekeyedProject> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - doThrow(new RuntimeException("Faking listener2 throwing an exception")) - .when(listener2) - .onProjectsRekeyed(any()); - - underTestWithListeners.onProjectsRekeyed(projects); - - inOrder.verify(listener1).onProjectsRekeyed(same(projects)); - inOrder.verify(listener2).onProjectsRekeyed(same(projects)); - inOrder.verify(listener3).onProjectsRekeyed(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - @UseDataProvider("oneOrManyRekeyedProjects") - public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Error(Set<RekeyedProject> projects) { - InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - doThrow(new Error("Faking listener2 throwing an Error")) - .when(listener2) - .onProjectsRekeyed(any()); - - underTestWithListeners.onProjectsRekeyed(projects); - - inOrder.verify(listener1).onProjectsRekeyed(same(projects)); - inOrder.verify(listener2).onProjectsRekeyed(same(projects)); - inOrder.verify(listener3).onProjectsRekeyed(same(projects)); - inOrder.verifyNoMoreInteractions(); - } - - @DataProvider - public static Object[][] oneOrManyRekeyedProjects() { - return new Object[][] { - {singleton(newUniqueRekeyedProject())}, - {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueRekeyedProject()).collect(MoreCollectors.toSet())} - }; - } - - private static Project newUniqueProject() { - return Project.from(newPrivateProjectDto(newOrganizationDto())); - } - - private static int counter = 3_989; - - private static RekeyedProject newUniqueRekeyedProject() { - int base = counter++; - Project project = Project.from(newPrivateProjectDto(newOrganizationDto())); - return new RekeyedProject(project, base + "_old_key"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/RekeyedProjectTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/RekeyedProjectTest.java deleted file mode 100644 index a847d91d0d8..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/project/RekeyedProjectTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.project; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static java.util.Collections.emptyList; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; -import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; - -public class RekeyedProjectTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void constructor_throws_NPE_if_project_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("project can't be null"); - - new RekeyedProject(null, randomAlphanumeric(3)); - } - - @Test - public void constructor_throws_NPE_if_previousKey_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("previousKey can't be null"); - - new RekeyedProject(newRandomProject(), null); - } - - @Test - public void verify_getters() { - Project project = newRandomProject(); - String previousKey = randomAlphanumeric(6); - RekeyedProject underTest = new RekeyedProject(project, previousKey); - - assertThat(underTest.getProject()).isSameAs(project); - assertThat(underTest.getPreviousKey()).isEqualTo(previousKey); - } - - @Test - public void equals_is_based_on_project_and_previousKey() { - Project project = newRandomProject(); - String previousKey = randomAlphanumeric(6); - RekeyedProject underTest = new RekeyedProject(project, previousKey); - - assertThat(underTest).isEqualTo(underTest); - assertThat(underTest).isEqualTo(new RekeyedProject(project, previousKey)); - assertThat(underTest).isNotEqualTo(new RekeyedProject(project, randomAlphanumeric(11))); - assertThat(underTest).isNotEqualTo(new RekeyedProject(newRandomProject(), previousKey)); - assertThat(underTest).isNotEqualTo(new Object()); - assertThat(underTest).isNotEqualTo(null); - } - - @Test - public void hashCode_is_based_on_project_and_previousKey() { - Project project = newRandomProject(); - String previousKey = randomAlphanumeric(6); - RekeyedProject underTest = new RekeyedProject(project, previousKey); - - assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode()); - assertThat(underTest.hashCode()).isEqualTo(new RekeyedProject(project, previousKey).hashCode()); - assertThat(underTest.hashCode()).isNotEqualTo(new RekeyedProject(project, randomAlphanumeric(11)).hashCode()); - assertThat(underTest.hashCode()).isNotEqualTo(new RekeyedProject(newRandomProject(), previousKey).hashCode()); - assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode()); - assertThat(underTest.hashCode()).isNotEqualTo(null); - } - - @Test - public void verify_toString() { - Project project = new Project("A", "B", "C", "D", emptyList()); - String previousKey = "E"; - RekeyedProject underTest = new RekeyedProject(project, previousKey); - - assertThat(underTest.toString()).isEqualTo("RekeyedProject{project=Project{uuid='A', key='B', name='C', description='D'}, previousKey='E'}"); - } - - private static Project newRandomProject() { - return Project.from(newPrivateProjectDto(newOrganizationDto())); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ProjectsInWarningDaemonTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ProjectsInWarningDaemonTest.java deleted file mode 100644 index ba56ae7b267..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ProjectsInWarningDaemonTest.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.metric.MetricDto; -import org.sonar.server.es.EsTester; -import org.sonar.server.measure.index.ProjectMeasuresIndex; -import org.sonar.server.measure.index.ProjectMeasuresIndexer; -import org.sonar.server.permission.index.PermissionIndexerTester; -import org.sonar.server.permission.index.WebAuthorizationTypeSupport; -import org.sonar.server.util.GlobalLockManager; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.api.measures.Metric.Level.WARN; -import static org.sonar.db.measure.MeasureTesting.newLiveMeasure; -import static org.sonar.server.qualitygate.ProjectsInWarningDaemon.PROJECTS_IN_WARNING_INTERNAL_PROPERTY; - -public class ProjectsInWarningDaemonTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(); - @Rule - public EsTester es = EsTester.create(); - @Rule - public LogTester logger = new LogTester().setLevel(LoggerLevel.DEBUG); - - private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, new ProjectMeasuresIndexer(db.getDbClient(), es.client())); - private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client()); - private ProjectMeasuresIndex projectMeasuresIndex = new ProjectMeasuresIndex(es.client(), new WebAuthorizationTypeSupport(null), System2.INSTANCE); - - private MapSettings settings = new MapSettings(); - private GlobalLockManager lockManager = mock(GlobalLockManager.class); - private ProjectsInWarning projectsInWarning = new ProjectsInWarning(); - - private ProjectsInWarningDaemon underTest = new ProjectsInWarningDaemon(db.getDbClient(), projectMeasuresIndex, settings.asConfig(), lockManager, projectsInWarning); - - @Before - public void setUp() throws Exception { - settings.setProperty("sonar.projectsInWarning.frequencyInMilliseconds", "100"); - } - - @After - public void tearDown() { - underTest.stop(); - } - - @Test - public void store_projects_in_warning() throws InterruptedException { - allowLockToBeAcquired(); - MetricDto qualityGateStatus = insertQualityGateStatusMetric(); - insertProjectInWarning(qualityGateStatus); - insertProjectInWarning(qualityGateStatus); - // Setting does not exist - assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)).isEmpty(); - - underTest.notifyStart(); - - assertProjectsInWarningValue(2L); - assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled."); - } - - @Test - public void update_projects_in_warning_when_new_project_in_warning() throws InterruptedException { - allowLockToBeAcquired(); - MetricDto qualityGateStatus = insertQualityGateStatusMetric(); - ; - insertProjectInWarning(qualityGateStatus); - insertProjectInWarning(qualityGateStatus); - // Setting does not exist - assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)).isEmpty(); - - underTest.notifyStart(); - // Add a project in warning after the start in order to let the thread do his job - insertProjectInWarning(qualityGateStatus); - - assertProjectsInWarningValue(3L); - assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled."); - } - - @Test - public void stop_thread_when_number_of_projects_in_warning_reach_zero() throws InterruptedException { - allowLockToBeAcquired(); - MetricDto qualityGateStatus = insertQualityGateStatusMetric(); - ; - ComponentDto project = insertProjectInWarning(qualityGateStatus); - - underTest.notifyStart(); - assertProjectsInWarningValue(1L); - // Set quality gate status of the project to OK => No more projects in warning - db.getDbClient().liveMeasureDao().insertOrUpdate(db.getSession(), - newLiveMeasure(project, qualityGateStatus).setData(Metric.Level.OK.name()).setValue(null)); - db.commit(); - projectMeasuresIndexer.indexOnAnalysis(project.uuid()); - - assertProjectsInWarningValue(0L); - assertThat(logger.logs(LoggerLevel.INFO)) - .contains( - "Counting number of projects in warning is enabled.", - "Counting number of projects in warning will be disabled as there are no more projects in warning."); - } - - @Test - public void update_internal_properties_when_already_exits_and_projects_in_warnings_more_than_zero() throws InterruptedException { - allowLockToBeAcquired(); - MetricDto qualityGateStatus = insertQualityGateStatusMetric(); - insertProjectInWarning(qualityGateStatus); - insertProjectInWarning(qualityGateStatus); - // Setting contains 10, it should be updated with new value - db.getDbClient().internalPropertiesDao().save(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY, "10"); - db.commit(); - - underTest.notifyStart(); - - assertProjectsInWarningValue(2L); - assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled."); - } - - @Test - public void store_zero_projects_in_warning_when_no_projects() throws InterruptedException { - allowLockToBeAcquired(); - assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)).isEmpty(); - - underTest.notifyStart(); - - assertProjectsInWarningValue(0L); - assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled."); - } - - @Test - public void do_not_compute_projects_in_warning_when_internal_property_is_zero() throws InterruptedException { - allowLockToBeAcquired(); - MetricDto qualityGateStatus = insertQualityGateStatusMetric(); - ; - insertProjectInWarning(qualityGateStatus); - // Setting contains 0, even if there are projects in warning it will stay 0 (as it's not possible to have new projects in warning) - db.getDbClient().internalPropertiesDao().save(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY, "0"); - db.commit(); - - underTest.notifyStart(); - - assertProjectsInWarningValue(0L); - assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is not started as there are no projects in this situation."); - } - - @Test - public void do_not_store_projects_in_warning_in_db_when_cannot_acquire_lock() throws InterruptedException { - when(lockManager.tryLock(any(), anyInt())).thenReturn(false); - MetricDto qualityGateStatus = insertQualityGateStatusMetric(); - ; - insertProjectInWarning(qualityGateStatus); - - underTest.notifyStart(); - - waitForValueToBeComputed(1L); - assertThat(projectsInWarning.count()).isEqualTo(1L); - assertThat(countNumberOfProjectsInWarning()).isEqualTo(0L); - } - - private void waitForValueToBeComputed(long expectedValue) throws InterruptedException { - for (int i = 0; i < 1000; i++) { - if (projectsInWarning.isInitialized() && projectsInWarning.count() == expectedValue) { - break; - } - Thread.sleep(100); - } - } - - private void assertProjectsInWarningValue(long expectedValue) throws InterruptedException { - waitForValueToBeComputed(expectedValue); - assertThat(projectsInWarning.count()).isEqualTo(expectedValue); - assertThat(countNumberOfProjectsInWarning()).isEqualTo(expectedValue); - } - - private long countNumberOfProjectsInWarning() { - return db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY) - .map(Long::valueOf) - .orElse(0L); - } - - private ComponentDto insertProjectInWarning(MetricDto qualityGateStatus) { - ComponentDto project = db.components().insertPrivateProject(); - db.measures().insertLiveMeasure(project, qualityGateStatus, lm -> lm.setData(WARN.name()).setValue(null)); - authorizationIndexerTester.allowOnlyAnyone(project); - projectMeasuresIndexer.indexOnAnalysis(project.uuid()); - return project; - } - - private MetricDto insertQualityGateStatusMetric() { - return db.measures().insertMetric(m -> m.setKey(CoreMetrics.ALERT_STATUS_KEY).setValueType(Metric.ValueType.LEVEL.name())); - } - - private void allowLockToBeAcquired() { - when(lockManager.tryLock(any(), anyInt())).thenReturn(true); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java deleted file mode 100644 index a3da151ae34..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.sonar.api.measures.Metric; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.db.qualitygate.QualityGateDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; - -import static java.lang.String.format; -import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; -import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY; -import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY; -import static org.sonar.api.measures.Metric.ValueType.BOOL; -import static org.sonar.api.measures.Metric.ValueType.DATA; -import static org.sonar.api.measures.Metric.ValueType.DISTRIB; -import static org.sonar.api.measures.Metric.ValueType.FLOAT; -import static org.sonar.api.measures.Metric.ValueType.INT; -import static org.sonar.api.measures.Metric.ValueType.MILLISEC; -import static org.sonar.api.measures.Metric.ValueType.PERCENT; -import static org.sonar.api.measures.Metric.ValueType.RATING; -import static org.sonar.api.measures.Metric.ValueType.STRING; -import static org.sonar.api.measures.Metric.ValueType.WORK_DUR; - -@RunWith(DataProviderRunner.class) -public class QualityGateConditionsUpdaterTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - private QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(db.getDbClient()); - - @Test - public void create_error_condition() { - MetricDto metric = insertMetric(INT, "new_coverage"); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "80"); - - verifyCondition(result, qualityGate, metric, "LT", "80"); - } - - @Test - @UseDataProvider("valid_operators_and_direction") - public void create_condition_with_valid_operators_and_direction(String operator, int direction) { - MetricDto metric = db.measures().insertMetric(m -> m.setKey("key").setValueType(INT.name()).setHidden(false).setDirection(direction)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), operator, "80"); - - verifyCondition(result, qualityGate, metric, operator, "80"); - } - - @Test - public void create_condition_throws_NPE_if_errorThreshold_is_null() { - MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("errorThreshold can not be null"); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null); - } - - @Test - public void fail_to_create_condition_when_condition_on_same_metric_already_exist() { - MetricDto metric = insertMetric(PERCENT); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - db.qualityGates().addCondition(qualityGate, metric); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Condition on metric '%s' already exists.", metric.getShortName())); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "80"); - } - - @Test - public void fail_to_create_condition_on_missing_metric() { - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("There is no metric with key=new_coverage"); - - underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", "80"); - } - - @Test - @UseDataProvider("invalid_metrics") - public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) { - MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden).setDirection(0)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition", metric.getKey())); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "80"); - } - - @Test - @UseDataProvider("invalid_operators_and_direction") - public void fail_to_create_condition_on_not_allowed_operator_for_metric_direction(String operator, int direction) { - MetricDto metric = db.measures().insertMetric(m -> m.setKey("key").setValueType(INT.name()).setHidden(false).setDirection(direction)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Operator %s is not allowed for this metric.", operator)); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), operator, "90"); - } - - @Test - public void create_condition_on_rating_metric() { - MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "3"); - - verifyCondition(result, qualityGate, metric, "GT", "3"); - } - - @Test - public void fail_to_create_error_condition_on_invalid_rating_metric() { - MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("'80' is not a valid rating"); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "80"); - } - - @Test - public void fail_to_create_condition_on_rating_greater_than_E() { - MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("There's no worse rating than E (5)"); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "5"); - } - - @Test - @UseDataProvider("valid_values") - public void create_error_condition(Metric.ValueType valueType, String value) { - MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", value); - - verifyCondition(result, qualityGate, metric, "LT", value); - } - - @Test - @UseDataProvider("invalid_values") - public void fail_to_create_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) { - MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName())); - - underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", value); - } - - @Test - public void update_condition() { - MetricDto metric = insertMetric(PERCENT); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("80")); - - QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", "80"); - - verifyCondition(result, qualityGate, metric, "LT", "80"); - } - - @Test - public void update_condition_throws_NPE_if_errorThreshold_is_null() { - MetricDto metric = insertMetric(PERCENT); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("80")); - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("errorThreshold can not be null"); - - underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", null); - } - - @Test - public void update_condition_on_rating_metric() { - MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("80")); - - QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4"); - - verifyCondition(result, qualityGate, metric, "GT", "4"); - } - - @Test - @UseDataProvider("update_invalid_operators_and_direction") - public void fail_to_update_condition_on_not_allowed_operator_for_metric_direction(String validOperator, String updatedOperator, int direction) { - MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false).setDirection(direction)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator(validOperator).setErrorThreshold("80")); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Operator %s is not allowed for this metric", updatedOperator)); - - underTest.updateCondition(db.getSession(), condition, metric.getKey(), updatedOperator, "70"); - } - - @Test - public void fail_to_update_condition_on_rating_metric_on_leak_period() { - MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("3")); - - QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4"); - - verifyCondition(result, qualityGate, metric, "GT", "4"); - } - - @Test - public void fail_to_update_condition_on_rating_metric_on_not_core_rating_metric() { - MetricDto metric = insertMetric(RATING, "not_core_rating_metric"); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("3")); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("The metric '%s' cannot be used", metric.getShortName())); - - underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4"); - } - - @Test - @UseDataProvider("invalid_metrics") - public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) { - MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("80")); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition", metric.getKey())); - - underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60"); - } - - @Test - @UseDataProvider("valid_values") - public void update_error_condition(Metric.ValueType valueType, String value) { - MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("80")); - - QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", value); - - verifyCondition(result, qualityGate, metric, "LT", value); - } - - @Test - @UseDataProvider("invalid_values") - public void fail_to_update_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) { - MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0)); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization()); - QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric, - c -> c.setOperator("LT").setErrorThreshold("80")); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName())); - - underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", value); - } - - @DataProvider - public static Object[][] invalid_metrics() { - return new Object[][] { - {ALERT_STATUS_KEY, INT, false}, - {SECURITY_REVIEW_RATING_KEY, RATING, false}, - {"boolean", BOOL, false}, - {"string", STRING, false}, - {"data_metric", DATA, false}, - {"distrib", DISTRIB, false}, - {"hidden", INT, true} - }; - } - - @DataProvider - public static Object[][] valid_values() { - return new Object[][] { - {INT, "10"}, - {MILLISEC, "1000"}, - {WORK_DUR, "1000"}, - {FLOAT, "5.12"}, - {PERCENT, "10.30"}, - }; - } - - @DataProvider - public static Object[][] invalid_values() { - return new Object[][] { - {INT, "ABCD"}, - {MILLISEC, "ABCD"}, - {WORK_DUR, "ABCD"}, - {FLOAT, "ABCD"}, - {PERCENT, "ABCD"}, - }; - } - - @DataProvider - public static Object[][] invalid_operators_and_direction() { - return new Object[][] { - {"EQ", 0}, - {"NE", 0}, - {"LT", -1}, - {"GT", 1}, - }; - } - - @DataProvider - public static Object[][] update_invalid_operators_and_direction() { - return new Object[][] { - {"LT", "EQ", 0}, - {"LT", "NE", 0}, - {"GT", "LT", -1}, - {"LT", "GT", 1}, - }; - } - - @DataProvider - public static Object[][] valid_operators_and_direction() { - return new Object[][] { - {"LT", 0}, - {"GT", 0}, - {"GT", -1}, - {"LT", 1}, - }; - } - - private MetricDto insertMetric(Metric.ValueType type) { - return insertMetric(type, "key"); - } - - private MetricDto insertMetric(Metric.ValueType type, String key) { - return db.measures().insertMetric(m -> m - .setKey(key) - .setValueType(type.name()) - .setHidden(false) - .setDirection(0)); - } - - private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, String error) { - QualityGateConditionDto reloaded = db.getDbClient().gateConditionDao().selectById(dto.getId(), db.getSession()); - assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGate.getId()); - assertThat(reloaded.getMetricId()).isEqualTo(metric.getId().longValue()); - assertThat(reloaded.getOperator()).isEqualTo(operator); - assertThat(reloaded.getErrorThreshold()).isEqualTo(error); - - assertThat(dto.getQualityGateId()).isEqualTo(qualityGate.getId()); - assertThat(dto.getMetricId()).isEqualTo(metric.getId().longValue()); - assertThat(dto.getOperator()).isEqualTo(operator); - assertThat(dto.getErrorThreshold()).isEqualTo(error); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConverterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConverterTest.java deleted file mode 100644 index c956b400763..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConverterTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import org.junit.Test; - -public class QualityGateConverterTest { - - @Test - public void test_ToJson() { - // FIXME - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java deleted file mode 100644 index db4417f0247..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import org.junit.Test; -import org.sonar.core.platform.ComponentContainer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; - -public class QualityGateModuleTest { - @Test - public void verify_count_of_added_components() { - ComponentContainer container = new ComponentContainer(); - new QualityGateModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 6); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java deleted file mode 100644 index 574903dd0e5..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateUpdaterTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.System2; -import org.sonar.core.util.UuidFactoryFast; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualitygate.QualityGateDto; - -public class QualityGateUpdaterTest { - - static final String QGATE_NAME = "Default"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - private DbClient dbClient = db.getDbClient(); - private DbSession dbSession = db.getSession(); - private QualityGateUpdater underTest = new QualityGateUpdater(dbClient, UuidFactoryFast.getInstance()); - - @Test - public void create_quality_gate() { - OrganizationDto organization = db.organizations().insert(); - - QualityGateDto result = underTest.create(dbSession, organization, QGATE_NAME); - - assertThat(result).isNotNull(); - assertThat(result.getName()).isEqualTo(QGATE_NAME); - assertThat(result.getCreatedAt()).isNotNull(); - assertThat(result.isBuiltIn()).isFalse(); - QualityGateDto reloaded = dbClient.qualityGateDao().selectByName(dbSession, QGATE_NAME); - assertThat(reloaded).isNotNull(); - } - - @Test - public void fail_to_create_when_name_already_exists() { - OrganizationDto org = db.organizations().insert(); - underTest.create(dbSession, org, QGATE_NAME); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Name has already been taken"); - - underTest.create(dbSession, org, QGATE_NAME); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java deleted file mode 100644 index 176e7f3e623..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Random; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.core.util.UuidFactoryFast; -import org.sonar.core.util.Uuids; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.metric.MetricDao; -import org.sonar.db.metric.MetricDto; -import org.sonar.db.qualitygate.QualityGateConditionDao; -import org.sonar.db.qualitygate.QualityGateConditionDto; -import org.sonar.db.qualitygate.QualityGateDao; -import org.sonar.db.qualitygate.QualityGateDto; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY; -import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT_KEY; -import static org.sonar.api.measures.Metric.ValueType.INT; -import static org.sonar.api.measures.Metric.ValueType.PERCENT; -import static org.sonar.db.metric.MetricTesting.newMetricDto; -import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN; -import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN; - -public class RegisterQualityGatesTest { - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - @Rule - public LogTester logTester = new LogTester(); - - private static final String BUILT_IN_NAME = "Sonar way"; - - private DbClient dbClient = db.getDbClient(); - private DbSession dbSession = db.getSession(); - - private QualityGateDao qualityGateDao = dbClient.qualityGateDao(); - private QualityGateConditionDao gateConditionDao = dbClient.gateConditionDao(); - private MetricDao metricDao = dbClient.metricDao(); - private QualityGateConditionsUpdater qualityGateConditionsUpdater = new QualityGateConditionsUpdater(dbClient); - private QualityGateFinder qualityGateFinder = new QualityGateFinder(dbClient); - - private RegisterQualityGates underTest = new RegisterQualityGates(dbClient, qualityGateConditionsUpdater, - UuidFactoryFast.getInstance(), System2.INSTANCE); - - @Test - public void register_default_gate() { - insertMetrics(); - - underTest.start(); - - verifyCorrectBuiltInQualityGate(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")).isTrue(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue(); - } - - @Test - public void upgrade_empty_quality_gate() { - insertMetrics(); - - underTest.start(); - - assertThat(db.countRowsOfTable("quality_gates")).isEqualTo(1); - verifyCorrectBuiltInQualityGate(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue(); - } - - @Test - public void upgrade_should_remove_deleted_condition() { - insertMetrics(); - QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate(); - createBuiltInConditions(builtInQualityGate); - // Add another condition - qualityGateConditionsUpdater.createCondition(dbSession, builtInQualityGate, - NEW_SECURITY_REMEDIATION_EFFORT_KEY, OPERATOR_GREATER_THAN, "5"); - dbSession.commit(); - - underTest.start(); - - assertThat(db.countRowsOfTable("quality_gates")).isEqualTo(1); - verifyCorrectBuiltInQualityGate(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue(); - } - - @Test - public void upgrade_should_add_missing_condition() { - insertMetrics(); - QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate(); - List<QualityGateConditionDto> builtInConditions = createBuiltInConditions(builtInQualityGate); - // Remove a condition - QualityGateConditionDto conditionToBeDeleted = builtInConditions.get(new Random().nextInt(builtInConditions.size())); - gateConditionDao.delete(conditionToBeDeleted, dbSession); - dbSession.commit(); - - underTest.start(); - - assertThat(db.countRowsOfTable("quality_gates")).isEqualTo(1); - verifyCorrectBuiltInQualityGate(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue(); - } - - @Test - public void should_set_SonarWay_as_builtin_when_not_set() { - insertMetrics(); - QualityGateDto qualityGate = dbClient.qualityGateDao().insert(dbSession, new QualityGateDto() - .setName("Sonar way") - .setUuid(Uuids.createFast()) - .setBuiltIn(false) - .setCreatedAt(new Date())); - dbSession.commit(); - createBuiltInConditions(qualityGate); - dbSession.commit(); - - underTest.start(); - - assertThat(db.countRowsOfTable("quality_gates")).isEqualTo(1); - verifyCorrectBuiltInQualityGate(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Quality gate [Sonar way] has been set as built-in")).isTrue(); - } - - @Test - public void should_not_update_builtin_quality_gate_if_already_uptodate() { - insertMetrics(); - QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate(); - createBuiltInConditions(builtInQualityGate); - dbSession.commit(); - - underTest.start(); - - assertThat(db.countRowsOfTable("quality_gates")).isEqualTo(1); - verifyCorrectBuiltInQualityGate(); - // Log must not be present - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Quality gate [Sonar way] has been set as built-in")).isFalse(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")).isFalse(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isFalse(); - } - - @Test - public void ensure_only_one_built_in_quality_gate() { - insertMetrics(); - String qualityGateName = "IncorrectQualityGate"; - QualityGateDto builtin = new QualityGateDto().setName(qualityGateName).setBuiltIn(true).setUuid(Uuids.createFast()); - qualityGateDao.insert(dbSession, builtin); - dbSession.commit(); - - underTest.start(); - - QualityGateDto oldQualityGate = qualityGateDao.selectByName(dbSession, qualityGateName); - assertThat(oldQualityGate).isNotNull(); - assertThat(oldQualityGate.isBuiltIn()).isFalse(); - assertThat(db.select("select name as \"name\" from quality_gates where is_built_in is true")) - .extracting(column -> column.get("name")) - .containsExactly(BUILT_IN_NAME); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")).isTrue(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue(); - } - - @Test - public void ensure_only_that_builtin_is_set_as_default_when_no_default_quality_gate() { - insertMetrics(); - QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate(); - - underTest.start(); - - assertThat(qualityGateFinder.getBuiltInQualityGate(dbSession)).isNotNull(); - assertThat(qualityGateFinder.getBuiltInQualityGate(dbSession).getId()).isEqualTo(builtInQualityGate.getId()); - } - - @Test - public void builtin_quality_gate_with_incorrect_metricId_should_not_throw_an_exception() { - insertMetrics(); - QualityGateConditionDto conditionDto = new QualityGateConditionDto() - .setMetricId(-1) // This Id does not exist - .setOperator(OPERATOR_GREATER_THAN) - .setErrorThreshold("1"); - gateConditionDao.insert(conditionDto, dbSession); - dbSession.commit(); - - underTest.start(); - - // No exception thrown - verifyCorrectBuiltInQualityGate(); - assertThat( - logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue(); - } - - private void insertMetrics() { - dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_RELIABILITY_RATING_KEY).setValueType(INT.name()).setHidden(false).setDirection(0)); - dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_RATING_KEY).setValueType(INT.name()).setHidden(false).setDirection(0)); - dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_REMEDIATION_EFFORT_KEY).setValueType(INT.name()).setHidden(false).setDirection(0)); - dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_MAINTAINABILITY_RATING_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0)); - dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_COVERAGE_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0)); - dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0)); - dbSession.commit(); - } - - private void verifyCorrectBuiltInQualityGate() { - MetricDto newReliability = metricDao.selectByKey(dbSession, NEW_RELIABILITY_RATING_KEY); - MetricDto newSecurity = metricDao.selectByKey(dbSession, NEW_SECURITY_RATING_KEY); - MetricDto newMaintainability = metricDao.selectByKey(dbSession, NEW_MAINTAINABILITY_RATING_KEY); - MetricDto newCoverage = metricDao.selectByKey(dbSession, NEW_COVERAGE_KEY); - MetricDto newDuplication = metricDao.selectByKey(dbSession, NEW_DUPLICATED_LINES_DENSITY_KEY); - - QualityGateDto qualityGateDto = qualityGateDao.selectByName(dbSession, BUILT_IN_NAME); - assertThat(qualityGateDto).isNotNull(); - assertThat(qualityGateDto.getCreatedAt()).isNotNull(); - assertThat(qualityGateDto.isBuiltIn()).isTrue(); - assertThat(gateConditionDao.selectForQualityGate(dbSession, qualityGateDto.getId())) - .extracting(QualityGateConditionDto::getMetricId, QualityGateConditionDto::getOperator, - QualityGateConditionDto::getErrorThreshold) - .containsOnly( - tuple(newReliability.getId().longValue(), OPERATOR_GREATER_THAN, "1"), - tuple(newSecurity.getId().longValue(), OPERATOR_GREATER_THAN, "1"), - tuple(newMaintainability.getId().longValue(), OPERATOR_GREATER_THAN, "1"), - tuple(newCoverage.getId().longValue(), OPERATOR_LESS_THAN, "80"), - tuple(newDuplication.getId().longValue(), OPERATOR_GREATER_THAN, "3")); - } - - private List<QualityGateConditionDto> createBuiltInConditions(QualityGateDto qg) { - List<QualityGateConditionDto> conditions = new ArrayList<>(); - - conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg, - NEW_SECURITY_RATING_KEY, OPERATOR_GREATER_THAN, "1")); - conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg, - NEW_RELIABILITY_RATING_KEY, OPERATOR_GREATER_THAN, "1")); - conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg, - NEW_MAINTAINABILITY_RATING_KEY, OPERATOR_GREATER_THAN, "1")); - conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg, - NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, "80")); - conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg, - NEW_DUPLICATED_LINES_DENSITY_KEY, OPERATOR_GREATER_THAN, "3")); - - return conditions; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java deleted file mode 100644 index 964637487fb..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.commons.lang.RandomStringUtils; -import org.assertj.core.groups.Tuple; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.InOrder; -import org.mockito.Mockito; -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.RuleType; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.qualitygate.changeevent.QGChangeEventListener.ChangedIssue; -import org.sonar.server.qualitygate.changeevent.QGChangeEventListenersImpl.ChangedIssueImpl; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptySet; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class QGChangeEventListenersImplTest { - @Rule - public LogTester logTester = new LogTester(); - - private QGChangeEventListener listener1 = mock(QGChangeEventListener.class); - private QGChangeEventListener listener2 = mock(QGChangeEventListener.class); - private QGChangeEventListener listener3 = mock(QGChangeEventListener.class); - private List<QGChangeEventListener> listeners = Arrays.asList(listener1, listener2, listener3); - - private String component1Uuid = RandomStringUtils.randomAlphabetic(6); - private ComponentDto component1 = newComponentDto(component1Uuid); - private DefaultIssue component1Issue = newDefaultIssue(component1Uuid); - private List<DefaultIssue> oneIssueOnComponent1 = singletonList(component1Issue); - private QGChangeEvent component1QGChangeEvent = newQGChangeEvent(component1); - - private InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); - - private QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl(new QGChangeEventListener[] {listener1, listener2, listener3}); - - @Test - public void broadcastOnIssueChange_has_no_effect_when_issues_are_empty() { - underTest.broadcastOnIssueChange(emptyList(), singletonList(component1QGChangeEvent)); - - verifyZeroInteractions(listener1, listener2, listener3); - } - - @Test - public void broadcastOnIssueChange_has_no_effect_when_no_changeEvent() { - underTest.broadcastOnIssueChange(oneIssueOnComponent1, emptySet()); - - verifyZeroInteractions(listener1, listener2, listener3); - } - - @Test - public void broadcastOnIssueChange_passes_same_arguments_to_all_listeners_in_order_of_addition_to_constructor() { - underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent)); - - ArgumentCaptor<Set<ChangedIssue>> changedIssuesCaptor = newSetCaptor(); - inOrder.verify(listener1).onIssueChanges(same(component1QGChangeEvent), changedIssuesCaptor.capture()); - Set<ChangedIssue> changedIssues = changedIssuesCaptor.getValue(); - inOrder.verify(listener2).onIssueChanges(same(component1QGChangeEvent), same(changedIssues)); - inOrder.verify(listener3).onIssueChanges(same(component1QGChangeEvent), same(changedIssues)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void broadcastOnIssueChange_calls_all_listeners_even_if_one_throws_an_exception() { - QGChangeEventListener failingListener = new QGChangeEventListener[] {listener1, listener2, listener3}[new Random().nextInt(3)]; - doThrow(new RuntimeException("Faking an exception thrown by onChanges")) - .when(failingListener) - .onIssueChanges(any(), any()); - - underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent)); - - ArgumentCaptor<Set<ChangedIssue>> changedIssuesCaptor = newSetCaptor(); - inOrder.verify(listener1).onIssueChanges(same(component1QGChangeEvent), changedIssuesCaptor.capture()); - Set<ChangedIssue> changedIssues = changedIssuesCaptor.getValue(); - inOrder.verify(listener2).onIssueChanges(same(component1QGChangeEvent), same(changedIssues)); - inOrder.verify(listener3).onIssueChanges(same(component1QGChangeEvent), same(changedIssues)); - inOrder.verifyNoMoreInteractions(); - assertThat(logTester.logs()).hasSize(4); - assertThat(logTester.logs(LoggerLevel.WARN)).hasSize(1); - } - - @Test - public void broadcastOnIssueChange_stops_calling_listeners_when_one_throws_an_ERROR() { - doThrow(new Error("Faking an error thrown by a listener")) - .when(listener2) - .onIssueChanges(any(), any()); - - underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent)); - - ArgumentCaptor<Set<ChangedIssue>> changedIssuesCaptor = newSetCaptor(); - inOrder.verify(listener1).onIssueChanges(same(component1QGChangeEvent), changedIssuesCaptor.capture()); - Set<ChangedIssue> changedIssues = changedIssuesCaptor.getValue(); - inOrder.verify(listener2).onIssueChanges(same(component1QGChangeEvent), same(changedIssues)); - inOrder.verifyNoMoreInteractions(); - assertThat(logTester.logs()).hasSize(3); - assertThat(logTester.logs(LoggerLevel.WARN)).hasSize(1); - } - - @Test - public void broadcastOnIssueChange_logs_each_listener_call_at_TRACE_level() { - underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent)); - - assertThat(logTester.logs()).hasSize(3); - List<String> traceLogs = logTester.logs(LoggerLevel.TRACE); - assertThat(traceLogs).hasSize(3) - .containsOnly( - "calling onChange() on listener " + listener1.getClass().getName() + " for events " + component1QGChangeEvent.toString() + "...", - "calling onChange() on listener " + listener2.getClass().getName() + " for events " + component1QGChangeEvent.toString() + "...", - "calling onChange() on listener " + listener3.getClass().getName() + " for events " + component1QGChangeEvent.toString() + "..."); - } - - @Test - public void broadcastOnIssueChange_passes_immutable_set_of_ChangedIssues() { - QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl(new QGChangeEventListener[] {listener1}); - - underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent)); - - ArgumentCaptor<Set<ChangedIssue>> changedIssuesCaptor = newSetCaptor(); - inOrder.verify(listener1).onIssueChanges(same(component1QGChangeEvent), changedIssuesCaptor.capture()); - assertThat(changedIssuesCaptor.getValue()).isInstanceOf(ImmutableSet.class); - } - - @Test - public void broadcastOnIssueChange_has_no_effect_when_no_listener() { - QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl(); - - underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent)); - - verifyZeroInteractions(listener1, listener2, listener3); - } - - @Test - public void broadcastOnIssueChange_calls_listener_for_each_component_uuid_with_at_least_one_QGChangeEvent() { - // component2 has multiple issues - ComponentDto component2 = newComponentDto(component1Uuid + "2"); - DefaultIssue[] component2Issues = {newDefaultIssue(component2.uuid()), newDefaultIssue(component2.uuid())}; - QGChangeEvent component2QGChangeEvent = newQGChangeEvent(component2); - - // component 3 has multiple QGChangeEvent and only one issue - ComponentDto component3 = newComponentDto(component1Uuid + "3"); - DefaultIssue component3Issue = newDefaultIssue(component3.uuid()); - QGChangeEvent[] component3QGChangeEvents = {newQGChangeEvent(component3), newQGChangeEvent(component3)}; - - // component 4 has multiple QGChangeEvent and multiples issues - ComponentDto component4 = newComponentDto(component1Uuid + "4"); - DefaultIssue[] component4Issues = {newDefaultIssue(component4.uuid()), newDefaultIssue(component4.uuid())}; - QGChangeEvent[] component4QGChangeEvents = {newQGChangeEvent(component4), newQGChangeEvent(component4)}; - - // component 5 has no QGChangeEvent but one issue - ComponentDto component5 = newComponentDto(component1Uuid + "5"); - DefaultIssue component5Issue = newDefaultIssue(component5.uuid()); - - List<DefaultIssue> issues = Stream.of( - Stream.of(component1Issue), - Arrays.stream(component2Issues), - Stream.of(component3Issue), - Arrays.stream(component4Issues), - Stream.of(component5Issue)) - .flatMap(s -> s) - .collect(Collectors.toList()); - - List<DefaultIssue> changedIssues = randomizedList(issues); - List<QGChangeEvent> qgChangeEvents = Stream.of( - Stream.of(component1QGChangeEvent), - Stream.of(component2QGChangeEvent), - Arrays.stream(component3QGChangeEvents), - Arrays.stream(component4QGChangeEvents)) - .flatMap(s -> s) - .collect(Collectors.toList()); - - underTest.broadcastOnIssueChange(changedIssues, randomizedList(qgChangeEvents)); - - listeners.forEach(listener -> { - verifyListenerCalled(listener, component1QGChangeEvent, component1Issue); - verifyListenerCalled(listener, component2QGChangeEvent, component2Issues); - Arrays.stream(component3QGChangeEvents) - .forEach(component3QGChangeEvent -> verifyListenerCalled(listener, component3QGChangeEvent, component3Issue)); - Arrays.stream(component4QGChangeEvents) - .forEach(component4QGChangeEvent -> verifyListenerCalled(listener, component4QGChangeEvent, component4Issues)); - }); - verifyNoMoreInteractions(listener1, listener2, listener3); - } - - @Test - public void isNotClosed_returns_true_if_issue_in_one_of_opened_states() { - DefaultIssue defaultIssue = new DefaultIssue(); - defaultIssue.setStatus(Issue.STATUS_REOPENED); - defaultIssue.setKey("abc"); - defaultIssue.setType(RuleType.BUG); - defaultIssue.setSeverity("BLOCKER"); - - ChangedIssue changedIssue = new ChangedIssueImpl(defaultIssue); - - assertThat(changedIssue.isNotClosed()).isTrue(); - } - - @Test - public void isNotClosed_returns_false_if_issue_in_one_of_closed_states() { - DefaultIssue defaultIssue = new DefaultIssue(); - defaultIssue.setStatus(Issue.STATUS_CONFIRMED); - defaultIssue.setKey("abc"); - defaultIssue.setType(RuleType.BUG); - defaultIssue.setSeverity("BLOCKER"); - - ChangedIssue changedIssue = new ChangedIssueImpl(defaultIssue); - - assertThat(changedIssue.isNotClosed()).isFalse(); - } - - @Test - public void test_status_mapping() { - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_OPEN))).isEqualTo(QGChangeEventListener.Status.OPEN); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_REOPENED))).isEqualTo(QGChangeEventListener.Status.REOPENED); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_CONFIRMED))).isEqualTo(QGChangeEventListener.Status.CONFIRMED); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE))) - .isEqualTo(QGChangeEventListener.Status.RESOLVED_FP); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX))) - .isEqualTo(QGChangeEventListener.Status.RESOLVED_WF); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FIXED))) - .isEqualTo(QGChangeEventListener.Status.RESOLVED_FIXED); - try { - ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_CLOSED)); - fail("Expected exception"); - } catch (Exception e) { - assertThat(e).hasMessage("Unexpected status: CLOSED"); - } - try { - ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_RESOLVED)); - fail("Expected exception"); - } catch (Exception e) { - assertThat(e).hasMessage("A resolved issue should have a resolution"); - } - try { - ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_REMOVED)); - fail("Expected exception"); - } catch (Exception e) { - assertThat(e).hasMessage("Unexpected resolution for a resolved issue: REMOVED"); - } - } - - @Test - public void test_status_mapping_on_security_hotspots() { - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW))) - .isEqualTo(QGChangeEventListener.Status.TO_REVIEW); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_IN_REVIEW))) - .isEqualTo(QGChangeEventListener.Status.IN_REVIEW); - assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED))) - .isEqualTo(QGChangeEventListener.Status.REVIEWED); - } - - private void verifyListenerCalled(QGChangeEventListener listener, QGChangeEvent changeEvent, DefaultIssue... issues) { - ArgumentCaptor<Set<ChangedIssue>> changedIssuesCaptor = newSetCaptor(); - verify(listener).onIssueChanges(same(changeEvent), changedIssuesCaptor.capture()); - Set<ChangedIssue> changedIssues = changedIssuesCaptor.getValue(); - Tuple[] expected = Arrays.stream(issues) - .map(issue -> tuple(issue.key(), ChangedIssueImpl.statusOf(issue), issue.type())) - .toArray(Tuple[]::new); - assertThat(changedIssues) - .hasSize(issues.length) - .extracting(ChangedIssue::getKey, ChangedIssue::getStatus, ChangedIssue::getType) - .containsOnly(expected); - } - - private static final String[] POSSIBLE_STATUSES = asList(Issue.STATUS_CONFIRMED, Issue.STATUS_REOPENED, Issue.STATUS_RESOLVED).stream().toArray(String[]::new); - private static int issueIdCounter = 0; - - private static DefaultIssue newDefaultIssue(String projectUuid) { - DefaultIssue defaultIssue = new DefaultIssue(); - defaultIssue.setKey("issue_" + issueIdCounter++); - defaultIssue.setProjectUuid(projectUuid); - defaultIssue.setType(RuleType.values()[new Random().nextInt(RuleType.values().length)]); - defaultIssue.setStatus(POSSIBLE_STATUSES[new Random().nextInt(POSSIBLE_STATUSES.length)]); - String[] possibleResolutions = possibleResolutions(defaultIssue.getStatus()); - if (possibleResolutions.length > 0) { - defaultIssue.setResolution(possibleResolutions[new Random().nextInt(possibleResolutions.length)]); - } - return defaultIssue; - } - - private static String[] possibleResolutions(String status) { - switch (status) { - case Issue.STATUS_RESOLVED: - return new String[] {Issue.RESOLUTION_FALSE_POSITIVE, Issue.RESOLUTION_WONT_FIX}; - default: - return new String[0]; - } - } - - private static ComponentDto newComponentDto(String uuid) { - ComponentDto componentDto = new ComponentDto(); - componentDto.setUuid(uuid); - return componentDto; - } - - private static QGChangeEvent newQGChangeEvent(ComponentDto componentDto) { - QGChangeEvent res = mock(QGChangeEvent.class); - when(res.getProject()).thenReturn(componentDto); - return res; - } - - private static <T> ArgumentCaptor<Set<T>> newSetCaptor() { - Class<Set<T>> clazz = (Class<Set<T>>) (Class) Set.class; - return ArgumentCaptor.forClass(clazz); - } - - private static <T> List<T> randomizedList(List<T> issues) { - ArrayList<T> res = new ArrayList<>(issues); - Collections.shuffle(res); - return ImmutableList.copyOf(res); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventTest.java deleted file mode 100644 index eb4ce5d6c60..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualitygate.changeevent; - -import java.util.Optional; -import java.util.Random; -import java.util.function.Supplier; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.api.config.Configuration; -import org.sonar.api.measures.Metric; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.server.qualitygate.EvaluatedQualityGate; - -import static org.assertj.core.api.Assertions.assertThat; - -public class QGChangeEventTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ComponentDto project = new ComponentDto() - .setDbKey("foo") - .setUuid("bar"); - private BranchDto branch = new BranchDto() - .setBranchType(BranchType.SHORT) - .setUuid("bar") - .setProjectUuid("doh") - .setMergeBranchUuid("zop"); - private SnapshotDto analysis = new SnapshotDto() - .setUuid("pto") - .setCreatedAt(8_999_999_765L); - private Configuration configuration = Mockito.mock(Configuration.class); - private Metric.Level previousStatus = Metric.Level.values()[new Random().nextInt(Metric.Level.values().length)]; - private Supplier<Optional<EvaluatedQualityGate>> supplier = Optional::empty; - - @Test - public void constructor_fails_with_NPE_if_project_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("project can't be null"); - - new QGChangeEvent(null, branch, analysis, configuration, previousStatus, supplier); - } - - @Test - public void constructor_fails_with_NPE_if_branch_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("branch can't be null"); - - new QGChangeEvent(project, null, analysis, configuration, previousStatus, supplier); - } - - @Test - public void constructor_fails_with_NPE_if_analysis_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("analysis can't be null"); - - new QGChangeEvent(project, branch, null, configuration, previousStatus, supplier); - } - - @Test - public void constructor_fails_with_NPE_if_configuration_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("projectConfiguration can't be null"); - - new QGChangeEvent(project, branch, analysis, null, previousStatus, supplier); - } - - @Test - public void constructor_does_not_fail_with_NPE_if_previousStatus_is_null() { - new QGChangeEvent(project, branch, analysis, configuration, null, supplier); - } - - @Test - public void constructor_fails_with_NPE_if_supplier_is_null() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("qualityGateSupplier can't be null"); - - new QGChangeEvent(project, branch, analysis, configuration, previousStatus, null); - } - - @Test - public void verify_getters() { - QGChangeEvent underTest = new QGChangeEvent(project, branch, analysis, configuration, previousStatus, supplier); - - assertThat(underTest.getProject()).isSameAs(project); - assertThat(underTest.getBranch()).isSameAs(branch); - assertThat(underTest.getAnalysis()).isSameAs(analysis); - assertThat(underTest.getProjectConfiguration()).isSameAs(configuration); - assertThat(underTest.getPreviousStatus()).contains(previousStatus); - assertThat(underTest.getQualityGateSupplier()).isSameAs(supplier); - } - - @Test - public void getPreviousStatus_returns_empty_when_previousStatus_is_null() { - QGChangeEvent underTest = new QGChangeEvent(project, branch, analysis, configuration, previousStatus, supplier); - - assertThat(underTest.getPreviousStatus()).contains(previousStatus); - } - - @Test - public void overrides_toString() { - QGChangeEvent underTest = new QGChangeEvent(project, branch, analysis, configuration, previousStatus, supplier); - - assertThat(underTest.toString()) - .isEqualTo("QGChangeEvent{project=bar:foo, branch=SHORT:bar:doh:zop, analysis=pto:8999999765" + - ", projectConfiguration=" + configuration.toString() + - ", previousStatus=" + previousStatus + - ", qualityGateSupplier=" + supplier + "}"); - - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java deleted file mode 100644 index 6bf85ee8932..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.io.Resources; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.QualityProfileTesting; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleParamDto; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.junit.rules.ExpectedException.none; - -public class QProfileBackuperImplTest { - - private static final String EMPTY_BACKUP = "<?xml version='1.0' encoding='UTF-8'?>" + - "<profile><name>foo</name>" + - "<language>js</language>" + - "<rules/>" + - "</profile>"; - - private System2 system2 = new AlwaysIncreasingSystem2(); - - @Rule - public ExpectedException expectedException = none(); - @Rule - public DbTester db = DbTester.create(system2); - - private DummyReset reset = new DummyReset(); - private QProfileFactory profileFactory = new DummyProfileFactory(); - private QProfileBackuper underTest = new QProfileBackuperImpl(db.getDbClient(), reset, profileFactory); - - @Test - public void backup_generates_xml_file() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - ActiveRuleDto activeRule = activate(profile, rule); - - StringWriter writer = new StringWriter(); - underTest.backup(db.getSession(), profile, writer); - - assertThat(writer.toString()).isEqualTo("<?xml version='1.0' encoding='UTF-8'?>" + - "<profile><name>" + profile.getName() + "</name>" + - "<language>" + profile.getLanguage() + "</language>" + - "<rules>" + - "<rule>" + - "<repositoryKey>" + rule.getRepositoryKey() + "</repositoryKey>" + - "<key>" + rule.getRuleKey() + "</key>" + - "<priority>" + activeRule.getSeverityString() + "</priority>" + - "<parameters/>" + - "</rule>" + - "</rules>" + - "</profile>"); - } - - @Test - public void backup_rules_having_parameters() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto profile = createProfile(rule); - ActiveRuleDto activeRule = activate(profile, rule, param); - - StringWriter writer = new StringWriter(); - underTest.backup(db.getSession(), profile, writer); - - assertThat(writer.toString()).contains( - "<rule>" + - "<repositoryKey>" + rule.getRepositoryKey() + "</repositoryKey>" + - "<key>" + rule.getRuleKey() + "</key>" + - "<priority>" + activeRule.getSeverityString() + "</priority>" + - "<parameters><parameter>" + - "<key>" + param.getName() + "</key>" + - "<value>20</value>" + - "</parameter></parameters>" + - "</rule>"); - } - - @Test - public void backup_empty_profile() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - - StringWriter writer = new StringWriter(); - underTest.backup(db.getSession(), profile, writer); - - assertThat(writer.toString()).isEqualTo("<?xml version='1.0' encoding='UTF-8'?>" + - "<profile><name>" + profile.getName() + "</name>" + - "<language>" + profile.getLanguage() + "</language>" + - "<rules/>" + - "</profile>"); - } - - @Test - public void restore_backup_on_the_profile_specified_in_backup() { - OrganizationDto organization = db.organizations().insert(); - Reader backup = new StringReader(EMPTY_BACKUP); - - QProfileRestoreSummary summary = underTest.restore(db.getSession(), backup, organization, null); - - assertThat(summary.getProfile().getName()).isEqualTo("foo"); - assertThat(summary.getProfile().getLanguage()).isEqualTo("js"); - - assertThat(reset.calledProfile.getKee()).isEqualTo(summary.getProfile().getKee()); - assertThat(reset.calledActivations).isEmpty(); - } - - @Test - public void restore_backup_on_profile_having_different_name() { - OrganizationDto organization = db.organizations().insert(); - Reader backup = new StringReader(EMPTY_BACKUP); - - QProfileRestoreSummary summary = underTest.restore(db.getSession(), backup, organization, "bar"); - - assertThat(summary.getProfile().getName()).isEqualTo("bar"); - assertThat(summary.getProfile().getLanguage()).isEqualTo("js"); - - assertThat(reset.calledProfile.getKee()).isEqualTo(summary.getProfile().getKee()); - assertThat(reset.calledActivations).isEmpty(); - } - - @Test - public void restore_resets_the_activated_rules() { - Integer ruleId = db.rules().insert(RuleKey.of("sonarjs", "s001")).getId(); - OrganizationDto organization = db.organizations().insert(); - Reader backup = new StringReader("<?xml version='1.0' encoding='UTF-8'?>" + - "<profile><name>foo</name>" + - "<language>js</language>" + - "<rules>" + - "<rule>" + - "<repositoryKey>sonarjs</repositoryKey>" + - "<key>s001</key>" + - "<priority>BLOCKER</priority>" + - "<parameters>" + - "<parameter><key>bar</key><value>baz</value></parameter>" + - "</parameters>" + - "</rule>" + - "</rules>" + - "</profile>"); - - underTest.restore(db.getSession(), backup, organization, null); - - assertThat(reset.calledActivations).hasSize(1); - RuleActivation activation = reset.calledActivations.get(0); - assertThat(activation.getSeverity()).isEqualTo("BLOCKER"); - assertThat(activation.getRuleId()).isEqualTo(ruleId); - assertThat(activation.getParameter("bar")).isEqualTo("baz"); - } - - @Test - public void fail_to_restore_if_bad_xml_format() { - OrganizationDto organization = db.organizations().insert(); - try { - underTest.restore(db.getSession(), new StringReader("<rules><rule></rules>"), organization, null); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Backup XML is not valid. Root element must be <profile>."); - assertThat(reset.calledProfile).isNull(); - } - } - - @Test - public void fail_to_restore_if_not_xml_backup() { - OrganizationDto organization = db.organizations().insert(); - try { - underTest.restore(db.getSession(), new StringReader("foo"), organization, null); - fail(); - } catch (IllegalArgumentException e) { - assertThat(reset.calledProfile).isNull(); - } - } - - @Test - public void fail_to_restore_if_xml_is_not_well_formed() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Fail to restore Quality profile backup, XML document is not well formed"); - OrganizationDto organization = db.organizations().insert(); - String notWellFormedXml = "<?xml version='1.0' encoding='UTF-8'?><profile><name>\"profil\"</name><language>\"language\"</language><rules/></profile"; - - underTest.restore(db.getSession(), new StringReader(notWellFormedXml), organization, null); - } - - @Test - public void fail_to_restore_if_duplicate_rule() throws Exception { - OrganizationDto organization = db.organizations().insert(); - try { - String xml = Resources.toString(getClass().getResource("QProfileBackuperMediumTest/duplicates-xml-backup.xml"), UTF_8); - underTest.restore(db.getSession(), new StringReader(xml), organization, null); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("The quality profile cannot be restored as it contains duplicates for the following rules: xoo:x1, xoo:x2"); - assertThat(reset.calledProfile).isNull(); - } - } - - @Test - public void fail_to_restore_external_rule() { - db.rules().insert(RuleKey.of("sonarjs", "s001"), r -> r.setIsExternal(true)).getId(); - OrganizationDto organization = db.organizations().insert(); - Reader backup = new StringReader("<?xml version='1.0' encoding='UTF-8'?>" + - "<profile><name>foo</name>" + - "<language>js</language>" + - "<rules>" + - "<rule>" + - "<repositoryKey>sonarjs</repositoryKey>" + - "<key>s001</key>" + - "<priority>BLOCKER</priority>" + - "<parameters>" + - "<parameter><key>bar</key><value>baz</value></parameter>" + - "</parameters>" + - "</rule>" + - "</rules>" + - "</profile>"); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The quality profile cannot be restored as it contains rules from external rule engines: sonarjs:s001"); - underTest.restore(db.getSession(), backup, organization, null); - } - - private RuleDefinitionDto createRule() { - return db.rules().insert(); - } - - private QProfileDto createProfile(RuleDefinitionDto rule) { - return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage())); - } - - private ActiveRuleDto activate(QProfileDto profile, RuleDefinitionDto rule) { - return db.qualityProfiles().activateRule(profile, rule); - } - - private ActiveRuleDto activate(QProfileDto profile, RuleDefinitionDto rule, RuleParamDto param) { - ActiveRuleDto activeRule = db.qualityProfiles().activateRule(profile, rule); - ActiveRuleParamDto dto = ActiveRuleParamDto.createFor(param) - .setValue("20") - .setActiveRuleId(activeRule.getId()); - db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRule, dto); - return activeRule; - } - - private static class DummyReset implements QProfileReset { - private QProfileDto calledProfile; - private List<RuleActivation> calledActivations; - - @Override - public BulkChangeResult reset(DbSession dbSession, QProfileDto profile, Collection<RuleActivation> activations) { - this.calledProfile = profile; - this.calledActivations = new ArrayList<>(activations); - return new BulkChangeResult(); - } - } - private static class DummyProfileFactory implements QProfileFactory { - @Override - public QProfileDto getOrCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName key) { - return QualityProfileTesting.newQualityProfileDto() - .setOrganizationUuid(organization.getUuid()) - .setLanguage(key.getLanguage()) - .setName(key.getName()); - } - - @Override - public QProfileDto checkAndCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name) { - throw new UnsupportedOperationException(); - } - - @Override - public void delete(DbSession dbSession, Collection<QProfileDto> profiles) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileComparisonTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileComparisonTest.java deleted file mode 100644 index 81ce2e33ef6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileComparisonTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.MapDifference.ValueDifference; -import org.assertj.core.data.MapEntry; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.rule.Severity; -import org.sonar.api.server.rule.RuleParamType; -import org.sonar.api.utils.System2; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.db.rule.RuleTesting; -import org.sonar.server.es.EsTester; -import org.sonar.server.qualityprofile.QProfileComparison.ActiveRuleDiff; -import org.sonar.server.qualityprofile.QProfileComparison.QProfileComparisonResult; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.util.IntegerTypeValidation; -import org.sonar.server.util.TypeValidations; - -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; - -public class QProfileComparisonTest { - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone().anonymous(); - @Rule - public DbTester dbTester = DbTester.create(); - @Rule - public EsTester es = EsTester.create(); - - private DbClient db; - private DbSession dbSession; - private QProfileRules qProfileRules; - private QProfileComparison comparison; - - private RuleDefinitionDto xooRule1; - private RuleDefinitionDto xooRule2; - private QProfileDto left; - private QProfileDto right; - - @Before - public void before() { - db = dbTester.getDbClient(); - dbSession = db.openSession(false); - RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE); - ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db, es.client()); - RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db, new TypeValidations(singletonList(new IntegerTypeValidation())), userSession); - qProfileRules = new QProfileRulesImpl(db, ruleActivator, ruleIndex, activeRuleIndexer); - comparison = new QProfileComparison(db); - - xooRule1 = RuleTesting.newXooX1().setSeverity("MINOR").getDefinition(); - xooRule2 = RuleTesting.newXooX2().setSeverity("MAJOR").getDefinition(); - db.ruleDao().insert(dbSession, xooRule1); - db.ruleDao().insert(dbSession, xooRule2); - db.ruleDao().insertRuleParam(dbSession, xooRule1, RuleParamDto.createFor(xooRule1) - .setName("max").setType(RuleParamType.INTEGER.type())); - db.ruleDao().insertRuleParam(dbSession, xooRule1, RuleParamDto.createFor(xooRule1) - .setName("min").setType(RuleParamType.INTEGER.type())); - - left = QProfileTesting.newXooP1("org-123"); - right = QProfileTesting.newXooP2("org-123"); - db.qualityProfileDao().insert(dbSession, left, right); - - dbSession.commit(); - } - - @After - public void after() { - dbSession.close(); - } - - @Test - public void compare_empty_profiles() { - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isEmpty(); - assertThat(result.inRight()).isEmpty(); - assertThat(result.modified()).isEmpty(); - assertThat(result.collectRuleKeys()).isEmpty(); - } - - @Test - public void compare_same() { - RuleActivation commonActivation = RuleActivation.create(xooRule1.getId(), Severity.CRITICAL, - ImmutableMap.of("min", "7", "max", "42")); - qProfileRules.activateAndCommit(dbSession, left, singleton(commonActivation)); - qProfileRules.activateAndCommit(dbSession, right, singleton(commonActivation)); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.inLeft()).isEmpty(); - assertThat(result.inRight()).isEmpty(); - assertThat(result.modified()).isEmpty(); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey()); - } - - @Test - public void compare_only_left() { - RuleActivation activation = RuleActivation.create(xooRule1.getId()); - qProfileRules.activateAndCommit(dbSession, left, singleton(activation)); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.inRight()).isEmpty(); - assertThat(result.modified()).isEmpty(); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey()); - } - - @Test - public void compare_only_right() { - qProfileRules.activateAndCommit(dbSession, right, singleton(RuleActivation.create(xooRule1.getId()))); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isEmpty(); - assertThat(result.inRight()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.modified()).isEmpty(); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey()); - } - - @Test - public void compare_disjoint() { - qProfileRules.activateAndCommit(dbSession, left, singleton(RuleActivation.create(xooRule1.getId()))); - qProfileRules.activateAndCommit(dbSession, right, singleton(RuleActivation.create(xooRule2.getId()))); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.inRight()).isNotEmpty().containsOnlyKeys(xooRule2.getKey()); - assertThat(result.modified()).isEmpty(); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey(), xooRule2.getKey()); - } - - @Test - public void compare_modified_severity() { - qProfileRules.activateAndCommit(dbSession, left, singleton(RuleActivation.create(xooRule1.getId(), Severity.CRITICAL, null))); - qProfileRules.activateAndCommit(dbSession, right, singleton(RuleActivation.create(xooRule1.getId(), Severity.BLOCKER, null))); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isEmpty(); - assertThat(result.inRight()).isEmpty(); - assertThat(result.modified()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey()); - - ActiveRuleDiff activeRuleDiff = result.modified().get(xooRule1.getKey()); - assertThat(activeRuleDiff.leftSeverity()).isEqualTo(Severity.CRITICAL); - assertThat(activeRuleDiff.rightSeverity()).isEqualTo(Severity.BLOCKER); - assertThat(activeRuleDiff.paramDifference().areEqual()).isTrue(); - } - - @Test - public void compare_modified_param() { - qProfileRules.activateAndCommit(dbSession, left, singleton(RuleActivation.create(xooRule1.getId(), null, ImmutableMap.of("max", "20")))); - qProfileRules.activateAndCommit(dbSession, right, singleton(RuleActivation.create(xooRule1.getId(), null, ImmutableMap.of("max", "30")))); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isEmpty(); - assertThat(result.inRight()).isEmpty(); - assertThat(result.modified()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey()); - - ActiveRuleDiff activeRuleDiff = result.modified().get(xooRule1.getKey()); - assertThat(activeRuleDiff.leftSeverity()).isEqualTo(activeRuleDiff.rightSeverity()).isEqualTo(xooRule1.getSeverityString()); - assertThat(activeRuleDiff.paramDifference().areEqual()).isFalse(); - assertThat(activeRuleDiff.paramDifference().entriesDiffering()).isNotEmpty(); - ValueDifference<String> paramDiff = activeRuleDiff.paramDifference().entriesDiffering().get("max"); - assertThat(paramDiff.leftValue()).isEqualTo("20"); - assertThat(paramDiff.rightValue()).isEqualTo("30"); - } - - @Test - public void compare_different_params() { - qProfileRules.activateAndCommit(dbSession, left, singleton(RuleActivation.create(xooRule1.getId(), null, ImmutableMap.of("max", "20")))); - qProfileRules.activateAndCommit(dbSession, right, singleton(RuleActivation.create(xooRule1.getId(), null, ImmutableMap.of("min", "5")))); - - QProfileComparisonResult result = comparison.compare(dbSession, left, right); - assertThat(result.left().getKee()).isEqualTo(left.getKee()); - assertThat(result.right().getKee()).isEqualTo(right.getKee()); - assertThat(result.same()).isEmpty(); - assertThat(result.inLeft()).isEmpty(); - assertThat(result.inRight()).isEmpty(); - assertThat(result.modified()).isNotEmpty().containsOnlyKeys(xooRule1.getKey()); - assertThat(result.collectRuleKeys()).containsOnly(xooRule1.getKey()); - - ActiveRuleDiff activeRuleDiff = result.modified().get(xooRule1.getKey()); - assertThat(activeRuleDiff.leftSeverity()).isEqualTo(activeRuleDiff.rightSeverity()).isEqualTo(xooRule1.getSeverityString()); - assertThat(activeRuleDiff.paramDifference().areEqual()).isFalse(); - assertThat(activeRuleDiff.paramDifference().entriesDiffering()).isEmpty(); - assertThat(activeRuleDiff.paramDifference().entriesOnlyOnLeft()).containsExactly(MapEntry.entry("max", "20")); - assertThat(activeRuleDiff.paramDifference().entriesOnlyOnRight()).containsExactly(MapEntry.entry("min", "5")); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileCopierTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileCopierTest.java deleted file mode 100644 index a084f72f5b6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileCopierTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; -import java.util.Collection; -import javax.annotation.Nullable; -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.impl.utils.JUnitTempFolder; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.QualityProfileTesting; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -public class QProfileCopierTest { - - private static final String BACKUP = "<backup/>"; - private System2 system2 = new AlwaysIncreasingSystem2(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(system2); - @Rule - public JUnitTempFolder temp = new JUnitTempFolder(); - - private DummyProfileFactory profileFactory = new DummyProfileFactory(); - private DummyBackuper backuper = new DummyBackuper(); - private QProfileCopier underTest = new QProfileCopier(db.getDbClient(), profileFactory, backuper, temp); - - @Test - public void create_target_profile_and_copy_rules() { - OrganizationDto organization = db.organizations().insert(); - QProfileDto source = db.qualityProfiles().insert(organization); - - QProfileDto target = underTest.copyToName(db.getSession(), source, "foo"); - - assertThat(target.getLanguage()).isEqualTo(source.getLanguage()); - assertThat(target.getName()).isEqualTo("foo"); - assertThat(target.getParentKee()).isNull(); - assertThat(backuper.backuped).isSameAs(source); - assertThat(backuper.restored.getName()).isEqualTo("foo"); - assertThat(backuper.restoredBackup).isEqualTo(BACKUP); - } - - @Test - public void create_target_profile_with_same_parent_than_source_profile() { - OrganizationDto organization = db.organizations().insert(); - QProfileDto parent = db.qualityProfiles().insert(organization); - QProfileDto source = db.qualityProfiles().insert(organization, p -> p.setParentKee(parent.getKee())); - - QProfileDto target = underTest.copyToName(db.getSession(), source, "foo"); - - assertThat(target.getLanguage()).isEqualTo(source.getLanguage()); - assertThat(target.getName()).isEqualTo("foo"); - assertThat(target.getParentKee()).isEqualTo(parent.getKee()); - } - - @Test - public void fail_to_copy_on_self() { - OrganizationDto organization = db.organizations().insert(); - QProfileDto source = db.qualityProfiles().insert(organization); - - try { - underTest.copyToName(db.getSession(), source, source.getName()); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Source and target profiles are equal: " + source.getName()); - assertThat(backuper.backuped).isNull(); - assertThat(backuper.restored).isNull(); - } - } - - @Test - public void copy_to_existing_profile() { - OrganizationDto organization = db.organizations().insert(); - QProfileDto profile1 = db.qualityProfiles().insert(organization); - QProfileDto profile2 = db.qualityProfiles().insert(organization, p -> p.setLanguage(profile1.getLanguage())); - - QProfileDto target = underTest.copyToName(db.getSession(), profile1, profile2.getName()); - - assertThat(profileFactory.createdProfile).isNull(); - assertThat(target.getLanguage()).isEqualTo(profile2.getLanguage()); - assertThat(target.getName()).isEqualTo(profile2.getName()); - assertThat(backuper.backuped).isSameAs(profile1); - assertThat(backuper.restored.getName()).isEqualTo(profile2.getName()); - assertThat(backuper.restoredBackup).isEqualTo(BACKUP); - } - - private static class DummyProfileFactory implements QProfileFactory { - private QProfileDto createdProfile; - - @Override - public QProfileDto getOrCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName key) { - throw new UnsupportedOperationException(); - } - - @Override - public QProfileDto checkAndCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName key) { - createdProfile = QualityProfileTesting.newQualityProfileDto() - .setOrganizationUuid(organization.getUuid()) - .setLanguage(key.getLanguage()) - .setName(key.getName()); - return createdProfile; - } - - @Override - public void delete(DbSession dbSession, Collection<QProfileDto> profiles) { - throw new UnsupportedOperationException(); - } - } - - private static class DummyBackuper implements QProfileBackuper { - private QProfileDto backuped; - private String restoredBackup; - private QProfileDto restored; - - @Override - public void backup(DbSession dbSession, QProfileDto profile, Writer backupWriter) { - this.backuped = profile; - try { - backupWriter.write(BACKUP); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @Override - public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) { - throw new UnsupportedOperationException(); - } - - @Override - public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QProfileDto profile) { - try { - this.restoredBackup = IOUtils.toString(backup); - this.restored = profile; - return null; - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java deleted file mode 100644 index dd57f191db2..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Collection; -import org.junit.Before; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.profiles.ProfileExporter; -import org.sonar.api.profiles.ProfileImporter; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.organization.DefaultOrganizationProvider; -import org.sonar.server.organization.TestDefaultOrganizationProvider; -import org.sonar.server.rule.DefaultRuleFinder; -import org.sonar.server.tester.UserSessionRule; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.commons.io.IOUtils.toInputStream; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class QProfileExportersTest { - - @org.junit.Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone(); - - private System2 system2 = new AlwaysIncreasingSystem2(); - - @org.junit.Rule - public ExpectedException expectedException = ExpectedException.none(); - @org.junit.Rule - public DbTester db = DbTester.create(system2); - - public DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - private RuleFinder ruleFinder = new DefaultRuleFinder(db.getDbClient(), defaultOrganizationProvider); - private ProfileExporter[] exporters = new ProfileExporter[] { - new StandardExporter(), new XooExporter()}; - private ProfileImporter[] importers = new ProfileImporter[] { - new XooProfileImporter(), new XooProfileImporterWithMessages(), new XooProfileImporterWithError()}; - private RuleDefinitionDto rule; - private QProfileRules qProfileRules = mock(QProfileRules.class); - private QProfileExporters underTest = new QProfileExporters(db.getDbClient(), ruleFinder, qProfileRules, exporters, importers); - - @Before - public void setUp() { - rule = db.rules().insert(r -> r.setLanguage("xoo").setRepositoryKey("SonarXoo").setRuleKey("R1")); - } - - @Test - public void exportersForLanguage() { - assertThat(underTest.exportersForLanguage("xoo")).hasSize(2); - assertThat(underTest.exportersForLanguage("java")).hasSize(1); - assertThat(underTest.exportersForLanguage("java").get(0)).isInstanceOf(StandardExporter.class); - } - - @Test - public void mimeType() { - assertThat(underTest.mimeType("xootool")).isEqualTo("plain/custom"); - - // default mime type - assertThat(underTest.mimeType("standard")).isEqualTo("text/plain"); - } - - @Test - public void import_xml() { - QProfileDto profile = createProfile(); - - - underTest.importXml(profile, "XooProfileImporter", toInputStream("<xml/>", UTF_8), db.getSession()); - - ArgumentCaptor<QProfileDto> profileCapture = ArgumentCaptor.forClass(QProfileDto.class); - Class<Collection<RuleActivation>> collectionClass = (Class<Collection<RuleActivation>>) (Class) Collection.class; - ArgumentCaptor<Collection<RuleActivation>> activationCapture = ArgumentCaptor.forClass(collectionClass); - verify(qProfileRules).activateAndCommit(any(DbSession.class), profileCapture.capture(), activationCapture.capture()); - - assertThat(profileCapture.getValue().getKee()).isEqualTo(profile.getKee()); - Collection<RuleActivation> activations = activationCapture.getValue(); - assertThat(activations).hasSize(1); - RuleActivation activation = activations.iterator().next(); - assertThat(activation.getRuleId()).isEqualTo(rule.getId()); - assertThat(activation.getSeverity()).isEqualTo("CRITICAL"); - } - - @Test - public void import_xml_return_messages() { - QProfileDto profile = createProfile(); - - QProfileResult result = underTest.importXml(profile, "XooProfileImporterWithMessages", toInputStream("<xml/>", UTF_8), db.getSession()); - - assertThat(result.infos()).containsOnly("an info"); - assertThat(result.warnings()).containsOnly("a warning"); - } - - @Test - public void fail_to_import_xml_when_error_in_importer() { - try { - underTest.importXml(QProfileTesting.newXooP1("org-123"), "XooProfileImporterWithError", toInputStream("<xml/>", UTF_8), db.getSession()); - fail(); - } catch (BadRequestException e) { - assertThat(e).hasMessage("error!"); - } - } - - @Test - public void fail_to_import_xml_on_unknown_importer() { - try { - underTest.importXml(QProfileTesting.newXooP1("org-123"), "Unknown", toInputStream("<xml/>", UTF_8), db.getSession()); - fail(); - } catch (BadRequestException e) { - assertThat(e).hasMessage("No such importer : Unknown"); - } - } - - @Test - public void export_empty_profile() { - QProfileDto profile = createProfile(); - - StringWriter writer = new StringWriter(); - underTest.export(db.getSession(), profile, "standard", writer); - assertThat(writer.toString()).isEqualTo("standard -> " + profile.getName() + " -> 0"); - - writer = new StringWriter(); - underTest.export(db.getSession(), profile, "xootool", writer); - assertThat(writer.toString()).isEqualTo("xoo -> " + profile.getName() + " -> 0"); - } - - @Test - public void export_profile() { - QProfileDto profile = createProfile(); - db.qualityProfiles().activateRule(profile, rule); - - StringWriter writer = new StringWriter(); - underTest.export(db.getSession(), profile, "standard", writer); - assertThat(writer.toString()).isEqualTo("standard -> " + profile.getName() + " -> 1"); - - writer = new StringWriter(); - underTest.export(db.getSession(), profile, "xootool", writer); - assertThat(writer.toString()).isEqualTo("xoo -> " + profile.getName() + " -> 1"); - } - - @Test - public void export_throws_NotFoundException_if_exporter_does_not_exist() { - QProfileDto profile = createProfile(); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Unknown quality profile exporter: does_not_exist"); - - underTest.export(db.getSession(), profile, "does_not_exist", new StringWriter()); - - } - - private QProfileDto createProfile() { - return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage())); - } - - public static class XooExporter extends ProfileExporter { - public XooExporter() { - super("xootool", "Xoo Tool"); - } - - @Override - public String[] getSupportedLanguages() { - return new String[] {"xoo"}; - } - - @Override - public String getMimeType() { - return "plain/custom"; - } - - @Override - public void exportProfile(RulesProfile profile, Writer writer) { - try { - writer.write("xoo -> " + profile.getName() + " -> " + profile.getActiveRules().size()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - } - - public static class StandardExporter extends ProfileExporter { - public StandardExporter() { - super("standard", "Standard"); - } - - @Override - public void exportProfile(RulesProfile profile, Writer writer) { - try { - writer.write("standard -> " + profile.getName() + " -> " + profile.getActiveRules().size()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - } - - public class XooProfileImporter extends ProfileImporter { - public XooProfileImporter() { - super("XooProfileImporter", "Xoo Profile Importer"); - } - - @Override - public String[] getSupportedLanguages() { - return new String[] {"xoo"}; - } - - @Override - public RulesProfile importProfile(Reader reader, ValidationMessages messages) { - RulesProfile rulesProfile = RulesProfile.create(); - rulesProfile.activateRule(Rule.create(rule.getRepositoryKey(), rule.getRuleKey()), RulePriority.CRITICAL); - return rulesProfile; - } - } - - public static class XooProfileImporterWithMessages extends ProfileImporter { - public XooProfileImporterWithMessages() { - super("XooProfileImporterWithMessages", "Xoo Profile Importer With Message"); - } - - @Override - public String[] getSupportedLanguages() { - return new String[] {}; - } - - @Override - public RulesProfile importProfile(Reader reader, ValidationMessages messages) { - messages.addWarningText("a warning"); - messages.addInfoText("an info"); - return RulesProfile.create(); - } - } - - public static class XooProfileImporterWithError extends ProfileImporter { - public XooProfileImporterWithError() { - super("XooProfileImporterWithError", "Xoo Profile Importer With Error"); - } - - @Override - public RulesProfile importProfile(Reader reader, ValidationMessages messages) { - messages.addErrorText("error!"); - return RulesProfile.create(); - } - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryImplTest.java deleted file mode 100644 index 176bddc24c6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryImplTest.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.Collections; -import java.util.Set; -import org.assertj.core.api.AbstractObjectAssert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.rule.Severity; -import org.sonar.api.utils.System2; -import org.sonar.core.util.SequenceUuidFactory; -import org.sonar.core.util.Uuids; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgQProfileDto; -import org.sonar.db.qualityprofile.QProfileChangeDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.RulesProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.db.user.GroupDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; - -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -public class QProfileFactoryImplTest { - - private System2 system2 = new AlwaysIncreasingSystem2(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(system2); - - private DbSession dbSession = db.getSession(); - private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); - private QProfileFactory underTest = new QProfileFactoryImpl(db.getDbClient(), new SequenceUuidFactory(), system2, activeRuleIndexer); - private RuleDefinitionDto rule; - private RuleParamDto ruleParam; - - @Before - public void setUp() { - rule = db.rules().insert(); - ruleParam = db.rules().insertRuleParam(rule); - } - - @Test - public void checkAndCreateCustom() { - OrganizationDto organization = db.organizations().insert(); - - QProfileDto profile = underTest.checkAndCreateCustom(dbSession, organization, new QProfileName("xoo", "P1")); - - assertThat(profile.getOrganizationUuid()).isEqualTo(organization.getUuid()); - assertThat(profile.getKee()).isNotEmpty(); - assertThat(profile.getName()).isEqualTo("P1"); - assertThat(profile.getLanguage()).isEqualTo("xoo"); - assertThat(profile.getId()).isNotNull(); - assertThat(profile.isBuiltIn()).isFalse(); - - QProfileDto reloaded = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(dbSession, organization, profile.getName(), profile.getLanguage()); - assertEqual(profile, reloaded); - assertThat(db.getDbClient().qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, organization)).extracting(QProfileDto::getKee).containsExactly(profile.getKee()); - } - - @Test - public void checkAndCreateCustom_throws_BadRequestException_if_name_null() { - QProfileName name = new QProfileName("xoo", null); - OrganizationDto organization = db.organizations().insert(); - - expectBadRequestException("quality_profiles.profile_name_cant_be_blank"); - - underTest.checkAndCreateCustom(dbSession, organization, name); - } - - @Test - public void checkAndCreateCustom_throws_BadRequestException_if_name_empty() { - QProfileName name = new QProfileName("xoo", ""); - OrganizationDto organization = db.organizations().insert(); - - expectBadRequestException("quality_profiles.profile_name_cant_be_blank"); - - underTest.checkAndCreateCustom(dbSession, organization, name); - } - - @Test - public void checkAndCreateCustom_throws_BadRequestException_if_already_exists() { - QProfileName name = new QProfileName("xoo", "P1"); - OrganizationDto organization = db.organizations().insert(); - - underTest.checkAndCreateCustom(dbSession, organization, name); - dbSession.commit(); - - expectBadRequestException("Quality profile already exists: xoo/P1"); - - underTest.checkAndCreateCustom(dbSession, organization, name); - } - - @Test - public void delete_custom_profiles() { - OrganizationDto org = db.organizations().insert(); - QProfileDto profile1 = createCustomProfile(org); - QProfileDto profile2 = createCustomProfile(org); - QProfileDto profile3 = createCustomProfile(org); - - underTest.delete(dbSession, asList(profile1, profile2)); - - verifyCallActiveRuleIndexerDelete(profile1.getKee(), profile2.getKee()); - assertThatCustomProfileDoesNotExist(profile1); - assertThatCustomProfileDoesNotExist(profile2); - assertThatCustomProfileExists(profile3); - } - - @Test - public void delete_removes_custom_profile_marked_as_default() { - OrganizationDto org = db.organizations().insert(); - QProfileDto profile = createCustomProfile(org); - db.qualityProfiles().setAsDefault(profile); - - underTest.delete(dbSession, asList(profile)); - - assertThatCustomProfileDoesNotExist(profile); - } - - @Test - public void delete_removes_custom_profile_from_project_associations() { - OrganizationDto org = db.organizations().insert(); - QProfileDto profile = createCustomProfile(org); - ComponentDto project = db.components().insertPrivateProject(org); - db.qualityProfiles().associateWithProject(project, profile); - - underTest.delete(dbSession, asList(profile)); - - assertThatCustomProfileDoesNotExist(profile); - } - - @Test - public void delete_builtin_profile() { - RulesProfileDto builtInProfile = createBuiltInProfile(); - OrganizationDto org = db.organizations().insert(); - QProfileDto profile = associateBuiltInProfileToOrganization(builtInProfile, org); - - underTest.delete(dbSession, asList(profile)); - - verifyNoCallsActiveRuleIndexerDelete(); - - // remove only from org_qprofiles - assertThat(db.getDbClient().qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, org)).isEmpty(); - - assertThatRulesProfileExists(builtInProfile); - } - - @Test - public void delete_builtin_profile_associated_to_project() { - RulesProfileDto builtInProfile = createBuiltInProfile(); - OrganizationDto org = db.organizations().insert(); - ComponentDto project = db.components().insertPrivateProject(org); - QProfileDto profile = associateBuiltInProfileToOrganization(builtInProfile, org); - db.qualityProfiles().associateWithProject(project, profile); - assertThat(db.getDbClient().qualityProfileDao().selectAssociatedToProjectAndLanguage(dbSession, project, profile.getLanguage())).isNotNull(); - - underTest.delete(dbSession, asList(profile)); - - verifyNoCallsActiveRuleIndexerDelete(); - - // remove only from org_qprofiles and project_qprofiles - assertThat(db.getDbClient().qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, org)).isEmpty(); - assertThat(db.getDbClient().qualityProfileDao().selectAssociatedToProjectAndLanguage(dbSession, project, profile.getLanguage())).isNull(); - assertThatRulesProfileExists(builtInProfile); - } - - @Test - public void delete_builtin_profile_marked_as_default_on_organization() { - RulesProfileDto builtInProfile = createBuiltInProfile(); - OrganizationDto org = db.organizations().insert(); - QProfileDto profile = associateBuiltInProfileToOrganization(builtInProfile, org); - db.qualityProfiles().setAsDefault(profile); - - underTest.delete(dbSession, asList(profile)); - - verifyNoCallsActiveRuleIndexerDelete(); - - // remove only from org_qprofiles and default_qprofiles - assertThat(db.getDbClient().qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, org)).isEmpty(); - assertThat(db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, org, profile.getLanguage())).isNull(); - assertThatRulesProfileExists(builtInProfile); - } - - @Test - public void delete_accepts_empty_list_of_keys() { - OrganizationDto org = db.organizations().insert(); - QProfileDto profile = createCustomProfile(org); - - underTest.delete(dbSession, Collections.emptyList()); - - verifyZeroInteractions(activeRuleIndexer); - assertQualityProfileFromDb(profile).isNotNull(); - } - - @Test - public void delete_removes_qprofile_edit_permissions() { - OrganizationDto organization = db.organizations().insert(); - QProfileDto profile = db.qualityProfiles().insert(organization); - UserDto user = db.users().insertUser(); - db.qualityProfiles().addUserPermission(profile, user); - GroupDto group = db.users().insertGroup(organization); - db.qualityProfiles().addGroupPermission(profile, group); - - underTest.delete(dbSession, asList(profile)); - - assertThat(db.countRowsOfTable(dbSession, "qprofile_edit_users")).isZero(); - assertThat(db.countRowsOfTable(dbSession, "qprofile_edit_groups")).isZero(); - } - - private QProfileDto createCustomProfile(OrganizationDto org) { - QProfileDto profile = db.qualityProfiles().insert(org, p -> p.setLanguage("xoo").setIsBuiltIn(false)); - ActiveRuleDto activeRuleDto = db.qualityProfiles().activateRule(profile, rule); - - ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto() - .setRulesParameterId(ruleParam.getId()) - .setKey("foo") - .setValue("bar"); - db.getDbClient().activeRuleDao().insertParam(dbSession, activeRuleDto, activeRuleParam); - - db.getDbClient().qProfileChangeDao().insert(dbSession, new QProfileChangeDto() - .setChangeType(ActiveRuleChange.Type.ACTIVATED.name()) - .setRulesProfileUuid(profile.getRulesProfileUuid())); - db.commit(); - return profile; - } - - private RulesProfileDto createBuiltInProfile() { - RulesProfileDto rulesProfileDto = new RulesProfileDto() - .setIsBuiltIn(true) - .setKee(Uuids.createFast()) - .setLanguage("xoo") - .setName("Sonar way"); - db.getDbClient().qualityProfileDao().insert(dbSession, rulesProfileDto); - ActiveRuleDto activeRuleDto = new ActiveRuleDto() - .setProfileId(rulesProfileDto.getId()) - .setRuleId(rule.getId()) - .setSeverity(Severity.BLOCKER); - db.getDbClient().activeRuleDao().insert(dbSession, activeRuleDto); - - ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto() - .setRulesParameterId(ruleParam.getId()) - .setKey("foo") - .setValue("bar"); - db.getDbClient().activeRuleDao().insertParam(dbSession, activeRuleDto, activeRuleParam); - - db.getDbClient().qProfileChangeDao().insert(dbSession, new QProfileChangeDto() - .setChangeType(ActiveRuleChange.Type.ACTIVATED.name()) - .setRulesProfileUuid(rulesProfileDto.getKee())); - - db.commit(); - return rulesProfileDto; - } - - private QProfileDto associateBuiltInProfileToOrganization(RulesProfileDto rulesProfile, OrganizationDto organization) { - OrgQProfileDto orgQProfileDto = new OrgQProfileDto() - .setUuid(Uuids.createFast()) - .setRulesProfileUuid(rulesProfile.getKee()) - .setOrganizationUuid(organization.getUuid()); - db.getDbClient().qualityProfileDao().insert(dbSession, orgQProfileDto); - db.commit(); - return QProfileDto.from(orgQProfileDto, rulesProfile); - } - - private AbstractObjectAssert<?, QProfileDto> assertQualityProfileFromDb(QProfileDto profile) { - return assertThat(db.getDbClient().qualityProfileDao().selectByUuid(dbSession, profile.getKee())); - } - - private void verifyNoCallsActiveRuleIndexerDelete() { - verify(activeRuleIndexer, never()).commitDeletionOfProfiles(any(DbSession.class), anyCollection()); - } - - private void verifyCallActiveRuleIndexerDelete(String... expectedRuleProfileUuids) { - Class<Set<QProfileDto>> setClass = (Class<Set<QProfileDto>>) (Class) Set.class; - ArgumentCaptor<Set<QProfileDto>> setCaptor = ArgumentCaptor.forClass(setClass); - verify(activeRuleIndexer).commitDeletionOfProfiles(any(DbSession.class), setCaptor.capture()); - - assertThat(setCaptor.getValue()) - .extracting(QProfileDto::getKee) - .containsExactlyInAnyOrder(expectedRuleProfileUuids); - } - - private void assertThatRulesProfileExists(RulesProfileDto rulesProfile) { - assertThat(db.getDbClient().qualityProfileDao().selectBuiltInRuleProfiles(dbSession)) - .extracting(RulesProfileDto::getKee) - .containsExactly(rulesProfile.getKee()); - assertThat(db.countRowsOfTable(dbSession, "active_rules")).isGreaterThan(0); - assertThat(db.countRowsOfTable(dbSession, "active_rule_parameters")).isGreaterThan(0); - assertThat(db.countRowsOfTable(dbSession, "qprofile_changes")).isGreaterThan(0); - } - - private void assertThatCustomProfileDoesNotExist(QProfileDto profile) { - assertThat(db.countSql(dbSession, "select count(*) from org_qprofiles where uuid = '" + profile.getKee() + "'")).isEqualTo(0); - assertThat(db.countSql(dbSession, "select count(*) from project_qprofiles where profile_key = '" + profile.getKee() + "'")).isEqualTo(0); - assertThat(db.countSql(dbSession, "select count(*) from default_qprofiles where qprofile_uuid = '" + profile.getKee() + "'")).isEqualTo(0); - assertThat(db.countSql(dbSession, "select count(*) from rules_profiles where kee = '" + profile.getRulesProfileUuid() + "'")).isEqualTo(0); - assertThat(db.countSql(dbSession, "select count(*) from active_rules where profile_id = " + profile.getId())).isEqualTo(0); - assertThat(db.countSql(dbSession, "select count(*) from qprofile_changes where rules_profile_uuid = '" + profile.getRulesProfileUuid() + "'")).isEqualTo(0); - // TODO active_rule_parameters - } - - private void assertThatCustomProfileExists(QProfileDto profile) { - assertThat(db.countSql(dbSession, "select count(*) from org_qprofiles where uuid = '" + profile.getKee() + "'")).isGreaterThan(0); - //assertThat(db.countSql(dbSession, "select count(*) from project_qprofiles where profile_key = '" + profile.getKee() + "'")).isGreaterThan(0); - //assertThat(db.countSql(dbSession, "select count(*) from default_qprofiles where qprofile_uuid = '" + profile.getKee() + "'")).isGreaterThan(0); - assertThat(db.countSql(dbSession, "select count(*) from rules_profiles where kee = '" + profile.getRulesProfileUuid() + "'")).isEqualTo(1); - assertThat(db.countSql(dbSession, "select count(*) from active_rules where profile_id = " + profile.getId())).isGreaterThan(0); - assertThat(db.countSql(dbSession, "select count(*) from qprofile_changes where rules_profile_uuid = '" + profile.getRulesProfileUuid() + "'")).isGreaterThan(0); - // TODO active_rule_parameters - } - - private static void assertEqual(QProfileDto p1, QProfileDto p2) { - assertThat(p2.getOrganizationUuid()).isEqualTo(p1.getOrganizationUuid()); - assertThat(p2.getName()).isEqualTo(p1.getName()); - assertThat(p2.getKee()).startsWith(p1.getKee()); - assertThat(p2.getLanguage()).isEqualTo(p1.getLanguage()); - assertThat(p2.getId()).isEqualTo(p1.getId()); - assertThat(p2.getParentKee()).isEqualTo(p1.getParentKee()); - } - - private void expectBadRequestException(String message) { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(message); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetImplTest.java deleted file mode 100644 index b53733b9cd1..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetImplTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.ActiveRuleKey; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.QualityProfileTesting; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.util.IntegerTypeValidation; -import org.sonar.server.util.StringTypeValidation; -import org.sonar.server.util.TypeValidations; - -import static java.util.Arrays.asList; -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.Mockito.mock; -import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; - -public class QProfileResetImplTest { - - private static final String LANGUAGE = "xoo"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public DbTester db = DbTester.create(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - private System2 system2 = new AlwaysIncreasingSystem2(); - private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); - private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); - private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); - private QProfileTree qProfileTree = new QProfileTreeImpl(db.getDbClient(), ruleActivator, system2, activeRuleIndexer); - private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer); - private QProfileResetImpl underTest = new QProfileResetImpl(db.getDbClient(), ruleActivator, activeRuleIndexer); - - @Test - public void reset() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE)); - RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(LANGUAGE)); - qProfileRules.activateAndCommit(db.getSession(), profile, singleton(RuleActivation.create(existingRule.getId()))); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(LANGUAGE)); - - BulkChangeResult result = underTest.reset(db.getSession(), profile, singletonList(RuleActivation.create(newRule.getId()))); - - assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)) - .extracting(OrgActiveRuleDto::getRuleKey) - .containsExactlyInAnyOrder(newRule.getKey()); - // Only activated rules are returned in the result - assertThat(result.getChanges()) - .extracting(ActiveRuleChange::getKey, ActiveRuleChange::getType) - .containsExactlyInAnyOrder(tuple(ActiveRuleKey.of(profile, newRule.getKey()), ACTIVATED)); - } - - @Test - public void inherited_rules_are_not_disabled() { - QProfileDto parentProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE)); - QProfileDto childProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE)); - qProfileTree.setParentAndCommit(db.getSession(), childProfile, parentProfile); - RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(LANGUAGE)); - qProfileRules.activateAndCommit(db.getSession(), parentProfile, singleton(RuleActivation.create(existingRule.getId()))); - qProfileRules.activateAndCommit(db.getSession(), childProfile, singleton(RuleActivation.create(existingRule.getId()))); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(LANGUAGE)); - - underTest.reset(db.getSession(), childProfile, singletonList(RuleActivation.create(newRule.getId()))); - - assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), childProfile)) - .extracting(OrgActiveRuleDto::getRuleKey) - .containsExactlyInAnyOrder(newRule.getKey(), existingRule.getKey()); - } - - @Test - public void fail_when_profile_is_built_in() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE).setIsBuiltIn(true)); - RuleDefinitionDto defaultRule = db.rules().insert(r -> r.setLanguage(LANGUAGE)); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage(String.format("Operation forbidden for built-in Quality Profile '%s'", profile.getKee())); - - underTest.reset(db.getSession(), profile, singletonList(RuleActivation.create(defaultRule.getId()))); - } - - @Test - public void fail_when_profile_is_not_persisted() { - QProfileDto profile = QualityProfileTesting.newQualityProfileDto().setLanguage(LANGUAGE); - RuleDefinitionDto defaultRule = db.rules().insert(r -> r.setLanguage(LANGUAGE)); - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("Quality profile must be persisted"); - - underTest.reset(db.getSession(), profile, singletonList(RuleActivation.create(defaultRule.getId()))); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleImplTest.java deleted file mode 100644 index c2c813f10d8..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleImplTest.java +++ /dev/null @@ -1,971 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.stream.IntStream; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.PropertyType; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.server.es.EsTester; -import org.sonar.server.es.SearchOptions; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.rule.index.RuleQuery; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.util.IntegerTypeValidation; -import org.sonar.server.util.StringTypeValidation; -import org.sonar.server.util.TypeValidations; - -import static com.google.common.collect.ImmutableMap.of; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.sonar.api.rule.Severity.BLOCKER; -import static org.sonar.api.rule.Severity.CRITICAL; -import static org.sonar.api.rule.Severity.MAJOR; -import static org.sonar.api.rule.Severity.MINOR; -import static org.sonar.db.rule.RuleTesting.newCustomRule; -import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED; - -public class QProfileRuleImplTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private System2 system2 = new AlwaysIncreasingSystem2(); - @Rule - public DbTester db = DbTester.create(system2); - @Rule - public EsTester es = EsTester.create(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - private RuleIndex ruleIndex = new RuleIndex(es.client(), system2); - private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); - private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); - private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); - - private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); - private QProfileRules underTest = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer); - - @Test - public void system_activates_rule_without_parameters() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId(), BLOCKER, null); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap()); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void user_activates_rule_without_parameters() { - userSession.logIn(); - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId(), BLOCKER, null); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap()); - assertThatProfileIsUpdatedByUser(profile); - } - - @Test - public void activate_rule_with_default_severity_and_parameters() { - RuleDefinitionDto rule = createRule(); - RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10")); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void activate_rule_with_parameters() { - RuleDefinitionDto rule = createRule(); - RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId(), null, of(ruleParam.getName(), "15")); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "15")); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void activate_rule_with_default_severity() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); - assertThatProfileIsUpdatedBySystem(profile); - } - - /** - * SONAR-5841 - */ - @Test - public void activate_rule_with_empty_parameter_having_no_default_value() { - RuleDefinitionDto rule = createRule(); - RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId(), null, of("min", "")); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10")); - assertThatProfileIsUpdatedBySystem(profile); - } - - /** - * // * SONAR-5840 - * // - */ - @Test - public void activate_rule_with_negative_integer_value_on_parameter_having_no_default_value() { - RuleDefinitionDto rule = createRule(); - RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null)); - RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId(), null, of(paramWithoutDefault.getName(), "-10")); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, - of(paramWithoutDefault.getName(), "-10", paramWithDefault.getName(), paramWithDefault.getDefaultValue())); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void activation_ignores_unsupported_parameters() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId(), null, of("xxx", "yyy")); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void update_an_already_activated_rule() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - // initial activation - RuleActivation activation = RuleActivation.create(rule.getId(), MAJOR, null); - activate(profile, activation); - - // update - RuleActivation updateActivation = RuleActivation.create(rule.getId(), CRITICAL, of(param.getName(), "20")); - List<ActiveRuleChange> changes = activate(profile, updateActivation); - - assertThatRuleIsUpdated(profile, rule, CRITICAL, null, of(param.getName(), "20")); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void update_activation_with_parameter_without_default_value() { - RuleDefinitionDto rule = createRule(); - RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null)); - RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - // initial activation -> param "max" has a default value - RuleActivation activation = RuleActivation.create(rule.getId()); - activate(profile, activation); - - // update param "min", which has no default value - RuleActivation updateActivation = RuleActivation.create(rule.getId(), MAJOR, of(paramWithoutDefault.getName(), "3")); - List<ActiveRuleChange> changes = activate(profile, updateActivation); - - assertThatRuleIsUpdated(profile, rule, MAJOR, null, of(paramWithDefault.getName(), "10", paramWithoutDefault.getName(), "3")); - assertThatProfileIsUpdatedBySystem(profile); - } - - @Test - public void reset_parameter_to_default_value() { - RuleDefinitionDto rule = createRule(); - RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - // initial activation -> param "max" has a default value - RuleActivation activation = RuleActivation.create(rule.getId(), null, of(paramWithDefault.getName(), "20")); - activate(profile, activation); - - // reset to default_value - RuleActivation updateActivation = RuleActivation.create(rule.getId(), null, of(paramWithDefault.getName(), "")); - List<ActiveRuleChange> changes = activate(profile, updateActivation); - - assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), "10")); - assertThat(changes).hasSize(1); - } - - @Test - public void update_activation_removes_parameter_without_default_value() { - RuleDefinitionDto rule = createRule(); - RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null)); - RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - // initial activation -> param "max" has a default value - RuleActivation activation = RuleActivation.create(rule.getId(), null, of(paramWithoutDefault.getName(), "20")); - activate(profile, activation); - - // remove parameter - RuleActivation updateActivation = RuleActivation.create(rule.getId(), null, of(paramWithoutDefault.getName(), "")); - List<ActiveRuleChange> changes = activate(profile, updateActivation); - - assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), paramWithDefault.getDefaultValue())); - assertThat(changes).hasSize(1); - } - - @Test - public void update_activation_with_new_parameter() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - // initial activation -> param "max" has a default value - RuleActivation activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(profile, activation); - db.getDbClient().activeRuleDao().deleteParametersByRuleProfileUuids(db.getSession(), asList(profile.getRulesProfileUuid())); - assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); - - // contrary to activerule, the param is supposed to be inserted but not updated - RuleActivation updateActivation = RuleActivation.create(rule.getId(), null, of(param.getName(), "")); - changes = activate(profile, updateActivation); - - assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); - assertThat(changes).hasSize(1); - } - - @Test - public void ignore_activation_without_changes() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - - // initial activation - RuleActivation activation = RuleActivation.create(rule.getId()); - activate(profile, activation); - - // update with exactly the same severity and params - activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(profile, activation); - - assertThat(changes).isEmpty(); - } - - @Test - public void do_not_change_severity_and_params_if_unset_and_already_activated() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); - QProfileDto profile = createProfile(rule); - - // initial activation -> param "max" has a default value - RuleActivation activation = RuleActivation.create(rule.getId(), BLOCKER, of(param.getName(), "20")); - activate(profile, activation); - - // update without any severity or params => keep - RuleActivation update = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(profile, update); - - assertThat(changes).isEmpty(); - } - - @Test - public void fail_to_activate_rule_if_profile_is_on_different_languages() { - RuleDefinitionDto rule = createJavaRule(); - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage("js")); - RuleActivation activation = RuleActivation.create(rule.getId()); - - expectFailure("java rule " + rule.getKey() + " cannot be activated on js profile " + profile.getKee(), () -> activate(profile, activation)); - } - - @Test - public void fail_to_activate_rule_if_rule_has_REMOVED_status() { - RuleDefinitionDto rule = db.rules().insert(r -> r.setStatus(RuleStatus.REMOVED)); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId()); - - expectFailure("Rule was removed: " + rule.getKey(), () -> activate(profile, activation)); - } - - @Test - public void fail_to_activate_if_template() { - RuleDefinitionDto rule = db.rules().insert(r -> r.setIsTemplate(true)); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId()); - - expectFailure("Rule template can't be activated on a Quality profile: " + rule.getKey(), () -> activate(profile, activation)); - } - - @Test - public void fail_to_activate_if_invalid_parameter() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10").setType(PropertyType.INTEGER.name())); - QProfileDto profile = createProfile(rule); - - RuleActivation activation = RuleActivation.create(rule.getId(), null, of(param.getName(), "foo")); - expectFailure("Value 'foo' must be an integer.", () -> activate(profile, activation)); - } - - @Test - public void ignore_parameters_when_activating_custom_rule() { - RuleDefinitionDto templateRule = db.rules().insert(r -> r.setIsTemplate(true)); - RuleParamDto templateParam = db.rules().insertRuleParam(templateRule, p -> p.setName("format")); - RuleDefinitionDto customRule = db.rules().insert(newCustomRule(templateRule)); - RuleParamDto customParam = db.rules().insertRuleParam(customRule, p -> p.setName("format").setDefaultValue("txt")); - QProfileDto profile = createProfile(customRule); - - // initial activation - RuleActivation activation = RuleActivation.create(customRule.getId(), MAJOR, emptyMap()); - activate(profile, activation); - assertThatRuleIsActivated(profile, customRule, null, MAJOR, null, of("format", "txt")); - - // update -> parameter is not changed - RuleActivation updateActivation = RuleActivation.create(customRule.getId(), BLOCKER, of("format", "xml")); - activate(profile, updateActivation); - assertThatRuleIsActivated(profile, customRule, null, BLOCKER, null, of("format", "txt")); - } - - @Test - public void user_deactivates_a_rule() { - userSession.logIn(); - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId()); - activate(profile, activation); - - List<ActiveRuleChange> changes = deactivate(profile, rule); - verifyNoActiveRules(); - assertThatProfileIsUpdatedByUser(profile); - assertThat(changes).hasSize(1); - assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED); - } - - @Test - public void system_deactivates_a_rule() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId()); - activate(profile, activation); - - List<ActiveRuleChange> changes = deactivate(profile, rule); - verifyNoActiveRules(); - assertThatProfileIsUpdatedBySystem(profile); - assertThatChangeIsDeactivation(changes, rule); - } - - private void assertThatChangeIsDeactivation(List<ActiveRuleChange> changes, RuleDefinitionDto rule) { - assertThat(changes).hasSize(1); - ActiveRuleChange change = changes.get(0); - assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED); - assertThat(change.getKey().getRuleKey()).isEqualTo(rule.getKey()); - } - - @Test - public void ignore_deactivation_if_rule_is_not_activated() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - - List<ActiveRuleChange> changes = deactivate(profile, rule); - verifyNoActiveRules(); - assertThat(changes).hasSize(0); - } - - @Test - public void deactivate_rule_that_has_REMOVED_status() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - RuleActivation activation = RuleActivation.create(rule.getId()); - activate(profile, activation); - - rule.setStatus(RuleStatus.REMOVED); - db.getDbClient().ruleDao().update(db.getSession(), rule); - - List<ActiveRuleChange> changes = deactivate(profile, rule); - verifyNoActiveRules(); - assertThatChangeIsDeactivation(changes, rule); - } - - @Test - public void activation_on_child_profile_is_propagated_to_descendants() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - List<ActiveRuleChange> changes = activate(childProfile, RuleActivation.create(rule.getId())); - assertThatProfileHasNoActiveRules(parentProfile); - assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(grandChildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); - } - - @Test - public void update_on_child_profile_is_propagated_to_descendants() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - System.out.println("ACTIVATE ON " + childProfile.getName()); - RuleActivation initialActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - activate(childProfile, initialActivation); - - System.out.println("---------------"); - System.out.println("ACTIVATE ON " + childProfile.getName()); - RuleActivation updateActivation = RuleActivation.create(rule.getId(), CRITICAL, of(param.getName(), "bar")); - List<ActiveRuleChange> changes = activate(childProfile, updateActivation); - - assertThatProfileHasNoActiveRules(parentProfile); - assertThatRuleIsUpdated(childProfile, rule, CRITICAL, null, of(param.getName(), "bar")); - assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, INHERITED, of(param.getName(), "bar")); - assertThat(changes).hasSize(2); - } - - @Test - public void override_activation_of_inherited_profile() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - RuleActivation initialActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - activate(childProfile, initialActivation); - - RuleActivation overrideActivation = RuleActivation.create(rule.getId(), CRITICAL, of(param.getName(), "bar")); - List<ActiveRuleChange> changes = activate(grandChildProfile, overrideActivation); - - assertThatProfileHasNoActiveRules(parentProfile); - assertThatRuleIsUpdated(childProfile, rule, MAJOR, null, of(param.getName(), "foo")); - assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar")); - assertThat(changes).hasSize(1); - } - - @Test - public void updated_activation_on_parent_is_not_propagated_to_overridden_profiles() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - RuleActivation initialActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - activate(childProfile, initialActivation); - - RuleActivation overrideActivation = RuleActivation.create(rule.getId(), CRITICAL, of(param.getName(), "bar")); - activate(grandChildProfile, overrideActivation); - - // update child --> do not touch grandChild - RuleActivation updateActivation = RuleActivation.create(rule.getId(), BLOCKER, of(param.getName(), "baz")); - List<ActiveRuleChange> changes = activate(childProfile, updateActivation); - - assertThatProfileHasNoActiveRules(parentProfile); - assertThatRuleIsUpdated(childProfile, rule, BLOCKER, null, of(param.getName(), "baz")); - assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar")); - assertThat(changes).hasSize(1); - } - - @Test - public void reset_on_parent_is_not_propagated_to_overridden_profiles() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - RuleActivation initialActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - activate(parentProfile, initialActivation); - - RuleActivation overrideActivation = RuleActivation.create(rule.getId(), CRITICAL, of(param.getName(), "bar")); - activate(grandChildProfile, overrideActivation); - - // reset parent --> touch child but not grandChild - RuleActivation updateActivation = RuleActivation.createReset(rule.getId()); - List<ActiveRuleChange> changes = activate(parentProfile, updateActivation); - - assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); - assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, of(param.getName(), param.getDefaultValue())); - assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar")); - assertThat(changes).hasSize(2); - } - - @Test - public void active_on_parent_a_rule_already_activated_on_child() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - RuleActivation childActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - activate(childProfile, childActivation); - - RuleActivation parentActivation = RuleActivation.create(rule.getId(), CRITICAL, of(param.getName(), "bar")); - List<ActiveRuleChange> changes = activate(parentProfile, parentActivation); - - assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, of(param.getName(), "bar")); - assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "foo")); - assertThat(changes).hasSize(2); - } - - @Test - public void do_not_mark_as_overridden_if_same_values_than_parent() { - RuleDefinitionDto rule = createRule(); - RuleParamDto param = db.rules().insertRuleParam(rule); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - RuleActivation parentActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - activate(parentProfile, parentActivation); - - RuleActivation overrideActivation = RuleActivation.create(rule.getId(), MAJOR, of(param.getName(), "foo")); - List<ActiveRuleChange> changes = activate(childProfile, overrideActivation); - - assertThatRuleIsUpdated(childProfile, rule, MAJOR, INHERITED, of(param.getName(), "foo")); - assertThat(changes).hasSize(0); - } - - @Test - public void propagate_deactivation_on_children() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - RuleActivation activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(parentProfile, activation); - assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); - - changes = deactivate(parentProfile, rule); - assertThatProfileHasNoActiveRules(parentProfile); - assertThatProfileHasNoActiveRules(childProfile); - assertThat(changes).hasSize(2); - } - - @Test - public void propagate_deactivation_on_children_even_when_overridden() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - RuleActivation activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(parentProfile, activation); - assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); - - activation = RuleActivation.create(rule.getId(), CRITICAL, null); - activate(childProfile, activation); - - changes = deactivate(parentProfile, rule); - assertThatProfileHasNoActiveRules(parentProfile); - assertThatProfileHasNoActiveRules(childProfile); - assertThat(changes).hasSize(2); - } - - @Test - public void cannot_deactivate_rule_inherited() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - RuleActivation activation = RuleActivation.create(rule.getId()); - List<ActiveRuleChange> changes = activate(parentProfile, activation); - assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Cannot deactivate inherited rule"); - deactivate(childProfile, rule); - } - - @Test - public void reset_child_profile_do_not_change_parent() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - RuleActivation activation = RuleActivation.create(rule.getId(), CRITICAL, null); - List<ActiveRuleChange> changes = activate(parentProfile, activation); - assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap()); - assertThat(changes).hasSize(2); - - RuleActivation childActivation = RuleActivation.create(rule.getId(), BLOCKER, null); - changes = activate(childProfile, childActivation); - assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap()); - assertThat(changes).hasSize(1); - - RuleActivation resetActivation = RuleActivation.createReset(rule.getId()); - changes = activate(childProfile, resetActivation); - assertThatRuleIsUpdated(childProfile, rule, CRITICAL, INHERITED, emptyMap()); - assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, emptyMap()); - assertThat(changes).hasSize(1); - } - - @Test - public void reset_parent_is_not_propagated_when_child_overrides() { - RuleDefinitionDto rule = createRule(); - QProfileDto baseProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(baseProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - RuleActivation activation = RuleActivation.create(rule.getId(), CRITICAL, null); - List<ActiveRuleChange> changes = activate(baseProfile, activation); - assertThatRuleIsActivated(baseProfile, rule, changes, CRITICAL, null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap()); - assertThatRuleIsActivated(grandChildProfile, rule, changes, CRITICAL, INHERITED, emptyMap()); - assertThat(changes).hasSize(3); - - RuleActivation childActivation = RuleActivation.create(rule.getId(), BLOCKER, null); - changes = activate(childProfile, childActivation); - assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap()); - assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap()); - assertThat(changes).hasSize(2); - - // Reset on parent do not change child nor grandchild - RuleActivation resetActivation = RuleActivation.createReset(rule.getId()); - changes = activate(baseProfile, resetActivation); - assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap()); - assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap()); - assertThat(changes).hasSize(1); - - // Reset on child change grandchild - resetActivation = RuleActivation.createReset(rule.getId()); - changes = activate(childProfile, resetActivation); - assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, emptyMap()); - assertThatRuleIsUpdated(grandChildProfile, rule, rule.getSeverityString(), INHERITED, emptyMap()); - assertThat(changes).hasSize(2); - } - - @Test - public void ignore_reset_if_not_activated() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - createChildProfile(parentProfile); - - RuleActivation resetActivation = RuleActivation.createReset(rule.getId()); - List<ActiveRuleChange> changes = activate(parentProfile, resetActivation); - verifyNoActiveRules(); - assertThat(changes).hasSize(0); - } - - @Test - public void bulk_activation() { - int bulkSize = SearchOptions.MAX_LIMIT + 10 + new Random().nextInt(100); - String language = randomAlphanumeric(10); - String repositoryKey = randomAlphanumeric(10); - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(language)); - - List<RuleDto> rules = new ArrayList<>(); - IntStream.rangeClosed(1, bulkSize).forEach( - i -> rules.add(db.rules().insertRule(r -> r.setLanguage(language).setRepositoryKey(repositoryKey)))); - - verifyNoActiveRules(); - ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes()); - - RuleQuery ruleQuery = new RuleQuery() - .setRepositories(singletonList(repositoryKey)); - - BulkChangeResult bulkChangeResult = underTest.bulkActivateAndCommit(db.getSession(), profile, ruleQuery, MINOR); - - assertThat(bulkChangeResult.countFailed()).isEqualTo(0); - assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize); - assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize); - assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(bulkSize); - rules.stream().forEach( - r -> assertThatRuleIsActivated(profile, r.getDefinition(), null, MINOR, null, emptyMap())); - } - - @Test - public void bulk_deactivation() { - int bulkSize = SearchOptions.MAX_LIMIT + 10 + new Random().nextInt(100); - String language = randomAlphanumeric(10); - String repositoryKey = randomAlphanumeric(10); - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(language)); - - List<RuleDto> rules = new ArrayList<>(); - IntStream.rangeClosed(1, bulkSize).forEach( - i -> rules.add(db.rules().insertRule(r -> r.setLanguage(language).setRepositoryKey(repositoryKey)))); - - verifyNoActiveRules(); - ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes()); - - RuleQuery ruleQuery = new RuleQuery() - .setRepositories(singletonList(repositoryKey)); - - BulkChangeResult bulkChangeResult = underTest.bulkActivateAndCommit(db.getSession(), profile, ruleQuery, MINOR); - - assertThat(bulkChangeResult.countFailed()).isEqualTo(0); - assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize); - assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize); - assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(bulkSize); - - // Now deactivate all rules - bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), profile, ruleQuery); - - assertThat(bulkChangeResult.countFailed()).isEqualTo(0); - assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize); - assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize); - assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(0); - rules.stream().forEach( - r -> assertThatRuleIsNotPresent(profile, r.getDefinition())); - } - - @Test - public void bulk_deactivation_ignores_errors() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule.getId())); - assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap()); - - ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes()); - - RuleQuery ruleQuery = new RuleQuery() - .setQProfile(childProfile); - BulkChangeResult bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), childProfile, ruleQuery); - - assertThat(bulkChangeResult.countFailed()).isEqualTo(1); - assertThat(bulkChangeResult.countSucceeded()).isEqualTo(0); - assertThat(bulkChangeResult.getChanges()).hasSize(0); - assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap()); - } - - @Test - public void bulk_change_severity() { - RuleDefinitionDto rule1 = createJavaRule(); - RuleDefinitionDto rule2 = createJavaRule(); - QProfileDto parentProfile = createProfile(rule1); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandchildProfile = createChildProfile(childProfile); - - activate(parentProfile, RuleActivation.create(rule1.getId())); - activate(parentProfile, RuleActivation.create(rule2.getId())); - - ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes()); - - RuleQuery query = new RuleQuery() - .setRuleKey(rule1.getRuleKey()) - .setQProfile(parentProfile); - BulkChangeResult result = underTest.bulkActivateAndCommit(db.getSession(), parentProfile, query, "BLOCKER"); - - assertThat(result.getChanges()).hasSize(3); - assertThat(result.countSucceeded()).isEqualTo(1); - assertThat(result.countFailed()).isEqualTo(0); - - // Rule1 must be activated with BLOCKER on all profiles - assertThatRuleIsActivated(parentProfile, rule1, null, BLOCKER, null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule1, null, BLOCKER, INHERITED, emptyMap()); - assertThatRuleIsActivated(grandchildProfile, rule1, null, BLOCKER, INHERITED, emptyMap()); - - // Rule2 did not changed - assertThatRuleIsActivated(parentProfile, rule2, null, rule2.getSeverityString(), null, emptyMap()); - assertThatRuleIsActivated(childProfile, rule2, null, rule2.getSeverityString(), INHERITED, emptyMap()); - assertThatRuleIsActivated(grandchildProfile, rule2, null, rule2.getSeverityString(), INHERITED, emptyMap()); - } - - @Test - public void delete_rule_from_all_profiles() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandChildProfile = createChildProfile(childProfile); - - RuleActivation activation = RuleActivation.create(rule.getId(), CRITICAL, null); - activate(parentProfile, activation); - - RuleActivation overrideActivation = RuleActivation.create(rule.getId(), BLOCKER, null); - activate(grandChildProfile, overrideActivation); - - // Reset on parent do not change child nor grandchild - List<ActiveRuleChange> changes = underTest.deleteRule(db.getSession(), rule); - - assertThatRuleIsNotPresent(parentProfile, rule); - assertThatRuleIsNotPresent(childProfile, rule); - assertThatRuleIsNotPresent(grandChildProfile, rule); - assertThat(changes) - .extracting(ActiveRuleChange::getType) - .containsOnly(ActiveRuleChange.Type.DEACTIVATED) - .hasSize(3); - } - - @Test - public void activation_fails_when_profile_is_built_in() { - RuleDefinitionDto rule = createRule(); - QProfileDto builtInProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true)); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The built-in profile " + builtInProfile.getName() + " is read-only and can't be updated"); - - underTest.activateAndCommit(db.getSession(), builtInProfile, singleton(RuleActivation.create(rule.getId()))); - } - - private void assertThatProfileHasNoActiveRules(QProfileDto profile) { - List<OrgActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile); - assertThat(activeRules).isEmpty(); - } - - private List<ActiveRuleChange> deactivate(QProfileDto profile, RuleDefinitionDto rule) { - return underTest.deactivateAndCommit(db.getSession(), profile, singleton(rule.getId())); - } - - private List<ActiveRuleChange> activate(QProfileDto profile, RuleActivation activation) { - return underTest.activateAndCommit(db.getSession(), profile, singleton(activation)); - } - - private QProfileDto createProfile(RuleDefinitionDto rule) { - return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage())); - } - - private QProfileDto createChildProfile(QProfileDto parent) { - return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p - .setLanguage(parent.getLanguage()) - .setParentKee(parent.getKee()) - .setName("Child of " + parent.getName())); - } - - private void assertThatProfileIsUpdatedByUser(QProfileDto profile) { - QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee()); - assertThat(loaded.getUserUpdatedAt()).isNotNull(); - assertThat(loaded.getRulesUpdatedAt()).isNotEmpty(); - } - - private void assertThatProfileIsUpdatedBySystem(QProfileDto profile) { - QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee()); - assertThat(loaded.getUserUpdatedAt()).isNull(); - assertThat(loaded.getRulesUpdatedAt()).isNotEmpty(); - } - - private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes, - String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) { - OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) - .stream() - .filter(ar -> ar.getRuleKey().equals(rule.getKey())) - .findFirst() - .orElseThrow(IllegalStateException::new); - - assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity); - assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null); - assertThat(activeRule.getCreatedAt()).isNotNull(); - assertThat(activeRule.getUpdatedAt()).isNotNull(); - - List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId()); - assertThat(params).hasSize(expectedParams.size()); - - if (changes != null) { - ActiveRuleChange change = changes.stream() - .filter(c -> c.getActiveRule().getId().equals(activeRule.getId())) - .findFirst().orElseThrow(IllegalStateException::new); - assertThat(change.getInheritance()).isEqualTo(expectedInheritance); - assertThat(change.getSeverity()).isEqualTo(expectedSeverity); - assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED); - } - } - - private void assertThatRuleIsNotPresent(QProfileDto profile, RuleDefinitionDto rule) { - Optional<OrgActiveRuleDto> activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) - .stream() - .filter(ar -> ar.getRuleKey().equals(rule.getKey())) - .findFirst(); - - assertThat(activeRule).isEmpty(); - } - - private void assertThatRuleIsUpdated(QProfileDto profile, RuleDefinitionDto rule, - String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) { - OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) - .stream() - .filter(ar -> ar.getRuleKey().equals(rule.getKey())) - .findFirst() - .orElseThrow(IllegalStateException::new); - - assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity); - assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null); - assertThat(activeRule.getCreatedAt()).isNotNull(); - assertThat(activeRule.getUpdatedAt()).isNotNull(); - - List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId()); - assertThat(params).hasSize(expectedParams.size()); - } - - private void expectFailure(String expectedMessage, Runnable runnable) { - try { - runnable.run(); - fail(); - } catch (BadRequestException e) { - assertThat(e.getMessage()).isEqualTo(expectedMessage); - } - verifyNoActiveRules(); - } - - private void verifyNoActiveRules() { - assertThat(db.countRowsOfTable(db.getSession(), "active_rules")).isEqualTo(0); - } - - private RuleDefinitionDto createRule() { - return db.rules().insert(r -> r.setSeverity(Severity.MAJOR)); - } - - private RuleDefinitionDto createJavaRule() { - return db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("java")); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRulesImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRulesImplTest.java deleted file mode 100644 index 88c3a82e875..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRulesImplTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.rule.Severity; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileChangeDto; -import org.sonar.db.qualityprofile.QProfileChangeQuery; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.es.EsTester; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.util.IntegerTypeValidation; -import org.sonar.server.util.TypeValidations; - -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - -public class QProfileRulesImplTest { - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - @Rule - public DbTester db = DbTester.create(); - @Rule - public EsTester es = EsTester.create(); - - private RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE); - private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); - private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), new TypeValidations(singletonList(new IntegerTypeValidation())), userSession); - - private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer); - - @Test - public void activate_one_rule() { - OrganizationDto organization = db.organizations().insert(); - QProfileDto qProfile = db.qualityProfiles().insert(organization); - RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage(qProfile.getLanguage())); - RuleActivation ruleActivation = RuleActivation.create(rule.getId(), Severity.CRITICAL, Collections.emptyMap()); - - qProfileRules.activateAndCommit(db.getSession(), qProfile, singleton(ruleActivation)); - - assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), qProfile)) - .extracting(ActiveRuleDto::getRuleKey, ActiveRuleDto::getSeverityString) - .containsExactlyInAnyOrder(tuple(rule.getKey(), Severity.CRITICAL)); - } - - @Test - public void active_rule_change() { - UserDto user = db.users().insertUser(); - userSession.logIn(user); - OrganizationDto organization = db.organizations().insert(); - QProfileDto qProfile = db.qualityProfiles().insert(organization); - RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage(qProfile.getLanguage())); - RuleActivation ruleActivation = RuleActivation.create(rule.getId(), Severity.CRITICAL, Collections.emptyMap()); - - qProfileRules.activateAndCommit(db.getSession(), qProfile, singleton(ruleActivation)); - - assertThat(db.getDbClient().qProfileChangeDao().selectByQuery(db.getSession(), new QProfileChangeQuery(qProfile.getKee()))) - .extracting(QProfileChangeDto::getUserUuid, QProfileChangeDto::getDataAsMap) - .containsExactlyInAnyOrder(tuple(user.getUuid(), ImmutableMap.of("ruleId", Integer.toString(rule.getId()), "severity", Severity.CRITICAL))); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTesting.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTesting.java deleted file mode 100644 index 4339d33c9ba..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTesting.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileDto; - -/** - * Utility class for tests involving quality profiles. - * @deprecated replaced by {@link org.sonar.db.qualityprofile.QualityProfileDbTester} - */ -@Deprecated -public class QProfileTesting { - - public static final QProfileName XOO_P1_NAME = new QProfileName("xoo", "P1"); - public static final String XOO_P1_KEY = "XOO_P1"; - public static final QProfileName XOO_P2_NAME = new QProfileName("xoo", "P2"); - public static final String XOO_P2_KEY = "XOO_P2"; - public static final QProfileName XOO_P3_NAME = new QProfileName("xoo", "P3"); - public static final String XOO_P3_KEY = "XOO_P3"; - - /** - * @deprecated provide organization as dto - */ - @Deprecated - public static QProfileDto newQProfileDto(String organizationUuid, QProfileName name, String key) { - return new QProfileDto() - .setKee(key) - .setRulesProfileUuid("rp-" + key) - .setOrganizationUuid(organizationUuid) - .setName(name.getName()) - .setLanguage(name.getLanguage()); - } - - /** - * @deprecated provide organization as dto - */ - @Deprecated - public static QProfileDto newXooP1(String organizationUuid) { - return newQProfileDto(organizationUuid, XOO_P1_NAME, XOO_P1_KEY); - } - - /** - * @deprecated provide organization as dto - */ - @Deprecated - public static QProfileDto newXooP2(String organizationUuid) { - return newQProfileDto(organizationUuid, XOO_P2_NAME, XOO_P2_KEY); - } - - /** - * @deprecated provide organization as dto - */ - @Deprecated - public static QProfileDto newXooP3(String organizationUuid) { - return newQProfileDto(organizationUuid, XOO_P3_NAME, XOO_P3_KEY); - } - - public static QProfileDto newQProfileDto(OrganizationDto organization, QProfileName name, String uuid) { - return new QProfileDto() - .setKee(uuid) - .setRulesProfileUuid("rp-" + uuid) - .setOrganizationUuid(organization.getUuid()) - .setName(name.getName()) - .setLanguage(name.getLanguage()); - } - - public static QProfileDto newXooP1(OrganizationDto organization) { - return newQProfileDto(organization, XOO_P1_NAME, XOO_P1_KEY); - } - - public static QProfileDto newXooP2(OrganizationDto organization) { - return newQProfileDto(organization, XOO_P2_NAME, XOO_P2_KEY); - } - - public static QProfileDto newXooP3(OrganizationDto organization) { - return newQProfileDto(organization, XOO_P3_NAME, XOO_P3_KEY); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTreeImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTreeImplTest.java deleted file mode 100644 index 77e3fcc903e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTreeImplTest.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.OrgActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.es.EsTester; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.util.IntegerTypeValidation; -import org.sonar.server.util.StringTypeValidation; -import org.sonar.server.util.TypeValidations; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singleton; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.rule.Severity.BLOCKER; -import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED; - -public class QProfileTreeImplTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private System2 system2 = new AlwaysIncreasingSystem2(); - @Rule - public DbTester db = DbTester.create(system2); - @Rule - public EsTester es = EsTester.create(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); - private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); - private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); - private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer); - private QProfileTree underTest = new QProfileTreeImpl(db.getDbClient(), ruleActivator, System2.INSTANCE, activeRuleIndexer); - - @Test - public void set_itself_as_parent_fails() { - RuleDefinitionDto rule = createRule(); - QProfileDto profile = createProfile(rule); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(" can not be selected as parent of "); - - underTest.setParentAndCommit(db.getSession(), profile, profile); - } - - @Test - public void set_child_as_parent_fails() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(" can not be selected as parent of "); - underTest.setParentAndCommit(db.getSession(), parentProfile, childProfile); - } - - @Test - public void set_grandchild_as_parent_fails() { - RuleDefinitionDto rule = createRule(); - QProfileDto parentProfile = createProfile(rule); - QProfileDto childProfile = createChildProfile(parentProfile); - QProfileDto grandchildProfile = createChildProfile(childProfile); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage(" can not be selected as parent of "); - underTest.setParentAndCommit(db.getSession(), parentProfile, grandchildProfile); - } - - @Test - public void cannot_set_parent_if_language_is_different() { - RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("foo")); - RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("bar")); - - QProfileDto parentProfile = createProfile(rule1); - List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule1.getId())); - assertThat(changes).hasSize(1); - - QProfileDto childProfile = createProfile(rule2); - changes = activate(childProfile, RuleActivation.create(rule2.getId())); - assertThat(changes).hasSize(1); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Cannot set the profile"); - - underTest.setParentAndCommit(db.getSession(), childProfile, parentProfile); - } - - @Test - public void set_then_unset_parent() { - RuleDefinitionDto rule1 = createJavaRule(); - RuleDefinitionDto rule2 = createJavaRule(); - - QProfileDto profile1 = createProfile(rule1); - List<ActiveRuleChange> changes = activate(profile1, RuleActivation.create(rule1.getId())); - assertThat(changes).hasSize(1); - - QProfileDto profile2 = createProfile(rule2); - changes = activate(profile2, RuleActivation.create(rule2.getId())); - assertThat(changes).hasSize(1); - - changes = underTest.setParentAndCommit(db.getSession(), profile2, profile1); - assertThat(changes).hasSize(1); - assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), INHERITED, emptyMap()); - assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); - - changes = underTest.removeParentAndCommit(db.getSession(), profile2); - assertThat(changes).hasSize(1); - assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); - assertThatRuleIsNotPresent(profile2, rule1); - } - - @Test - public void set_then_unset_parent_keep_overridden_rules() { - RuleDefinitionDto rule1 = createJavaRule(); - RuleDefinitionDto rule2 = createJavaRule(); - QProfileDto profile1 = createProfile(rule1); - List<ActiveRuleChange> changes = activate(profile1, RuleActivation.create(rule1.getId())); - assertThat(changes).hasSize(1); - - QProfileDto profile2 = createProfile(rule2); - changes = activate(profile2, RuleActivation.create(rule2.getId())); - assertThat(changes).hasSize(1); - - changes = underTest.setParentAndCommit(db.getSession(), profile2, profile1); - assertThat(changes).hasSize(1); - assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), INHERITED, emptyMap()); - assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); - - RuleActivation activation = RuleActivation.create(rule1.getId(), BLOCKER, null); - changes = activate(profile2, activation); - assertThat(changes).hasSize(1); - assertThatRuleIsUpdated(profile2, rule1, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap()); - assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); - - changes = underTest.removeParentAndCommit(db.getSession(), profile2); - assertThat(changes).hasSize(1); - // Not testing changes here since severity is not set in changelog - assertThatRuleIsActivated(profile2, rule1, null, BLOCKER, null, emptyMap()); - assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); - } - - @Test - public void activation_errors_are_ignored_when_setting_a_parent() { - RuleDefinitionDto rule1 = createJavaRule(); - RuleDefinitionDto rule2 = createJavaRule(); - QProfileDto parentProfile = createProfile(rule1); - activate(parentProfile, RuleActivation.create(rule1.getId())); - activate(parentProfile, RuleActivation.create(rule2.getId())); - - rule1.setStatus(RuleStatus.REMOVED); - db.rules().update(rule1); - - QProfileDto childProfile = createProfile(rule1); - List<ActiveRuleChange> changes = underTest.setParentAndCommit(db.getSession(), childProfile, parentProfile); - - assertThatRuleIsNotPresent(childProfile, rule1); - assertThatRuleIsActivated(childProfile, rule2, changes, rule2.getSeverityString(), INHERITED, emptyMap()); - } - - private List<ActiveRuleChange> activate(QProfileDto profile, RuleActivation activation) { - return qProfileRules.activateAndCommit(db.getSession(), profile, singleton(activation)); - } - - private QProfileDto createProfile(RuleDefinitionDto rule) { - return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage())); - } - - private QProfileDto createChildProfile(QProfileDto parent) { - return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p - .setLanguage(parent.getLanguage()) - .setParentKee(parent.getKee()) - .setName("Child of " + parent.getName())); - } - - private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes, - String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) { - OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) - .stream() - .filter(ar -> ar.getRuleKey().equals(rule.getKey())) - .findFirst() - .orElseThrow(IllegalStateException::new); - - assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity); - assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null); - assertThat(activeRule.getCreatedAt()).isNotNull(); - assertThat(activeRule.getUpdatedAt()).isNotNull(); - - List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId()); - assertThat(params).hasSize(expectedParams.size()); - - if (changes != null) { - ActiveRuleChange change = changes.stream() - .filter(c -> c.getActiveRule().getId().equals(activeRule.getId())) - .findFirst().orElseThrow(IllegalStateException::new); - assertThat(change.getInheritance()).isEqualTo(expectedInheritance); - assertThat(change.getSeverity()).isEqualTo(expectedSeverity); - assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED); - } - } - - private void assertThatRuleIsNotPresent(QProfileDto profile, RuleDefinitionDto rule) { - Optional<OrgActiveRuleDto> activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) - .stream() - .filter(ar -> ar.getRuleKey().equals(rule.getKey())) - .findFirst(); - - assertThat(activeRule).isEmpty(); - } - - private void assertThatRuleIsUpdated(QProfileDto profile, RuleDefinitionDto rule, - String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) { - OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) - .stream() - .filter(ar -> ar.getRuleKey().equals(rule.getKey())) - .findFirst() - .orElseThrow(IllegalStateException::new); - - assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity); - assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null); - assertThat(activeRule.getCreatedAt()).isNotNull(); - assertThat(activeRule.getUpdatedAt()).isNotNull(); - - List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId()); - assertThat(params).hasSize(expectedParams.size()); - } - - private RuleDefinitionDto createRule() { - return db.rules().insert(r -> r.setSeverity(Severity.MAJOR)); - } - - private RuleDefinitionDto createJavaRule() { - return db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("java")); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java deleted file mode 100644 index d6a535e448f..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import com.google.common.collect.Multimap; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.function.Consumer; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.Severity; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; -import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInActiveRule; -import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.LogTester; -import org.sonar.core.util.UuidFactoryFast; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.RulesProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.util.TypeValidations; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Collections.singleton; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.apache.commons.lang.math.RandomUtils.nextLong; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.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.api.rules.RulePriority.MAJOR; -import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto; -import static org.sonar.server.language.LanguageTesting.newLanguage; -import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; -import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; -import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED; - -public class RegisterQualityProfilesNotificationTest { - - private static final Random RANDOM = new SecureRandom(); - - private System2 system2 = mock(System2.class); - @Rule - public DbTester db = DbTester.create(system2); - @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public BuiltInQProfileRepositoryRule builtInQProfileRepositoryRule = new BuiltInQProfileRepositoryRule(); - @Rule - public LogTester logTester = new LogTester(); - - private DbClient dbClient = db.getDbClient(); - private TypeValidations typeValidations = mock(TypeValidations.class); - private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); - private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, system2, UuidFactoryFast.getInstance(), typeValidations, activeRuleIndexer); - private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, typeValidations, userSessionRule); - private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, mock(RuleIndex.class), activeRuleIndexer); - private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer); - private BuiltInQualityProfilesUpdateListener builtInQualityProfilesNotification = mock(BuiltInQualityProfilesUpdateListener.class); - private RegisterQualityProfiles underTest = new RegisterQualityProfiles(builtInQProfileRepositoryRule, dbClient, - builtInQProfileInsert, builtInQProfileUpdate, builtInQualityProfilesNotification, system2); - - @Test - public void do_not_send_notification_on_new_profile() { - String language = newLanguageKey(); - builtInQProfileRepositoryRule.add(newLanguage(language), "Sonar way"); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - verifyZeroInteractions(builtInQualityProfilesNotification); - } - - @Test - public void do_not_send_notification_when_profile_is_not_updated() { - String language = newLanguageKey(); - RuleDefinitionDto dbRule = db.rules().insert(r -> r.setLanguage(language)); - RulesProfileDto dbProfile = insertBuiltInProfile(language); - activateRuleInDb(dbProfile, dbRule, MAJOR); - addPluginProfile(dbProfile, dbRule); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - verifyZeroInteractions(builtInQualityProfilesNotification); - } - - @Test - public void send_notification_when_a_new_rule_is_activated() { - String language = newLanguageKey(); - RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(language)); - RulesProfileDto dbProfile = insertBuiltInProfile(language); - activateRuleInDb(dbProfile, existingRule, MAJOR); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(language)); - addPluginProfile(dbProfile, existingRule, newRule); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); - verify(builtInQualityProfilesNotification).onChange(captor.capture(), anyLong(), anyLong()); - Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); - assertThat(updatedProfiles.keySet()) - .extracting(QProfileName::getName, QProfileName::getLanguage) - .containsExactlyInAnyOrder(tuple(dbProfile.getName(), dbProfile.getLanguage())); - assertThat(updatedProfiles.values()) - .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) - .containsExactlyInAnyOrder(tuple(newRule.getId(), ACTIVATED)); - } - - @Test - public void send_notification_when_a_rule_is_deactivated() { - String language = newLanguageKey(); - RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(language)); - RulesProfileDto dbProfile = insertBuiltInProfile(language); - activateRuleInDb(dbProfile, existingRule, MAJOR); - addPluginProfile(dbProfile); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); - verify(builtInQualityProfilesNotification).onChange(captor.capture(), anyLong(), anyLong()); - Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); - assertThat(updatedProfiles.keySet()) - .extracting(QProfileName::getName, QProfileName::getLanguage) - .containsExactlyInAnyOrder(tuple(dbProfile.getName(), dbProfile.getLanguage())); - assertThat(updatedProfiles.values()) - .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) - .containsExactlyInAnyOrder(tuple(existingRule.getId(), DEACTIVATED)); - } - - @Test - public void send_a_single_notification_when_multiple_rules_are_activated() { - String language = newLanguageKey(); - - RuleDefinitionDto existingRule1 = db.rules().insert(r -> r.setLanguage(language)); - RuleDefinitionDto newRule1 = db.rules().insert(r -> r.setLanguage(language)); - RulesProfileDto dbProfile1 = insertBuiltInProfile(language); - activateRuleInDb(dbProfile1, existingRule1, MAJOR); - addPluginProfile(dbProfile1, existingRule1, newRule1); - - RuleDefinitionDto existingRule2 = db.rules().insert(r -> r.setLanguage(language)); - RuleDefinitionDto newRule2 = db.rules().insert(r -> r.setLanguage(language)); - RulesProfileDto dbProfile2 = insertBuiltInProfile(language); - activateRuleInDb(dbProfile2, existingRule2, MAJOR); - addPluginProfile(dbProfile2, existingRule2, newRule2); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); - verify(builtInQualityProfilesNotification).onChange(captor.capture(), anyLong(), anyLong()); - Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); - assertThat(updatedProfiles.keySet()) - .extracting(QProfileName::getName, QProfileName::getLanguage) - .containsExactlyInAnyOrder( - tuple(dbProfile1.getName(), dbProfile1.getLanguage()), - tuple(dbProfile2.getName(), dbProfile2.getLanguage())); - assertThat(updatedProfiles.values()) - .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) - .containsExactlyInAnyOrder( - tuple(newRule1.getId(), ACTIVATED), - tuple(newRule2.getId(), ACTIVATED)); - } - - @Test - public void notification_does_not_include_inherited_profiles_when_rule_is_added() { - String language = newLanguageKey(); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(language)); - OrganizationDto organization = db.organizations().insert(); - - QProfileDto builtInQProfileDto = insertProfile(organization, orgQProfile -> orgQProfile.setIsBuiltIn(true).setLanguage(language)); - QProfileDto childQProfileDto = insertProfile(organization, orgQProfile -> orgQProfile.setIsBuiltIn(false).setLanguage(language).setParentKee(builtInQProfileDto.getKee())); - addPluginProfile(builtInQProfileDto, newRule); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); - verify(builtInQualityProfilesNotification).onChange(captor.capture(), anyLong(), anyLong()); - Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); - assertThat(updatedProfiles.keySet()) - .extracting(QProfileName::getName, QProfileName::getLanguage) - .containsExactlyInAnyOrder(tuple(builtInQProfileDto.getName(), builtInQProfileDto.getLanguage())); - assertThat(updatedProfiles.values()) - .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) - .containsExactlyInAnyOrder(tuple(newRule.getId(), ACTIVATED)); - } - - @Test - public void notification_does_not_include_inherited_profiled_when_rule_is_changed() { - String language = newLanguageKey(); - RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage(language).setSeverity(Severity.MINOR)); - OrganizationDto organization = db.organizations().insert(); - - QProfileDto builtInProfile = insertProfile(organization, orgQProfile -> orgQProfile.setIsBuiltIn(true).setLanguage(language)); - db.qualityProfiles().activateRule(builtInProfile, rule, ar -> ar.setSeverity(Severity.MINOR)); - QProfileDto childProfile = insertProfile(organization, orgQProfile -> orgQProfile.setIsBuiltIn(false).setLanguage(language).setParentKee(builtInProfile.getKee())); - db.qualityProfiles().activateRule(childProfile, rule, ar -> ar.setInheritance(ActiveRuleDto.INHERITED).setSeverity(Severity.MINOR)); - addPluginProfile(builtInProfile, rule); - builtInQProfileRepositoryRule.initialize(); - db.commit(); - - underTest.start(); - - ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); - verify(builtInQualityProfilesNotification).onChange(captor.capture(), anyLong(), anyLong()); - Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); - assertThat(updatedProfiles.keySet()) - .extracting(QProfileName::getName, QProfileName::getLanguage) - .containsExactlyInAnyOrder(tuple(builtInProfile.getName(), builtInProfile.getLanguage())); - assertThat(updatedProfiles.values()) - .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) - .containsExactlyInAnyOrder(tuple(rule.getId(), UPDATED)); - } - - @Test - public void notification_does_not_include_inherited_profiles_when_rule_is_deactivated() { - String language = newLanguageKey(); - RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage(language).setSeverity(Severity.MINOR)); - OrganizationDto organization = db.organizations().insert(); - - QProfileDto builtInQProfileDto = insertProfile(organization, - orgQProfile -> orgQProfile.setIsBuiltIn(true).setLanguage(language)); - db.qualityProfiles().activateRule(builtInQProfileDto, rule); - QProfileDto childQProfileDto = insertProfile(organization, - orgQProfile -> orgQProfile.setIsBuiltIn(false).setLanguage(language).setParentKee(builtInQProfileDto.getKee())); - qProfileRules.activateAndCommit(db.getSession(), childQProfileDto, singleton(RuleActivation.create(rule.getId()))); - db.commit(); - - addPluginProfile(builtInQProfileDto); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); - verify(builtInQualityProfilesNotification).onChange(captor.capture(), anyLong(), anyLong()); - Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); - assertThat(updatedProfiles.keySet()) - .extracting(QProfileName::getName, QProfileName::getLanguage) - .containsExactlyInAnyOrder(tuple(builtInQProfileDto.getName(), builtInQProfileDto.getLanguage())); - assertThat(updatedProfiles.values()) - .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) - .containsExactlyInAnyOrder(tuple(rule.getId(), DEACTIVATED)); - } - - @Test - public void notification_contains_send_start_and_end_date() { - String language = newLanguageKey(); - RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(language)); - RulesProfileDto dbProfile = insertBuiltInProfile(language); - activateRuleInDb(dbProfile, existingRule, MAJOR); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(language)); - addPluginProfile(dbProfile, existingRule, newRule); - builtInQProfileRepositoryRule.initialize(); - long startDate = RANDOM.nextInt(5000); - long endDate = startDate + RANDOM.nextInt(5000); - when(system2.now()).thenReturn(startDate, endDate); - - underTest.start(); - - verify(builtInQualityProfilesNotification).onChange(any(), eq(startDate), eq(endDate)); - } - - private void addPluginProfile(RulesProfileDto dbProfile, RuleDefinitionDto... dbRules) { - BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context(); - NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(dbProfile.getName(), dbProfile.getLanguage()); - - Arrays.stream(dbRules).forEach(dbRule -> newQp.activateRule(dbRule.getRepositoryKey(), dbRule.getRuleKey()).overrideSeverity(Severity.MAJOR)); - newQp.done(); - List<BuiltInActiveRule> rules = context.profile(dbProfile.getLanguage(), dbProfile.getName()).rules(); - BuiltInQProfile.ActiveRule[] activeRules = toActiveRules(rules, dbRules); - builtInQProfileRepositoryRule.add(newLanguage(dbProfile.getLanguage()), dbProfile.getName(), false, activeRules); - } - - private static BuiltInQProfile.ActiveRule[] toActiveRules(List<BuiltInActiveRule> rules, RuleDefinitionDto[] dbRules) { - Map<RuleKey, RuleDefinitionDto> dbRulesByRuleKey = Arrays.stream(dbRules) - .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey)); - return rules.stream() - .map(r -> { - RuleKey ruleKey = RuleKey.of(r.repoKey(), r.ruleKey()); - RuleDefinitionDto ruleDefinitionDto = dbRulesByRuleKey.get(ruleKey); - checkState(ruleDefinitionDto != null, "Rule '%s' not found", ruleKey); - return new BuiltInQProfile.ActiveRule(ruleDefinitionDto.getId(), r); - }).toArray(BuiltInQProfile.ActiveRule[]::new); - } - - private void addPluginProfile(QProfileDto profile, RuleDefinitionDto... dbRules) { - BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context(); - NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage()); - - Arrays.stream(dbRules).forEach(dbRule -> newQp.activateRule(dbRule.getRepositoryKey(), dbRule.getRuleKey()).overrideSeverity(Severity.MAJOR)); - newQp.done(); - BuiltInQProfile.ActiveRule[] activeRules = toActiveRules(context.profile(profile.getLanguage(), profile.getName()).rules(), dbRules); - builtInQProfileRepositoryRule.add(newLanguage(profile.getLanguage()), profile.getName(), false, activeRules); - } - - private RulesProfileDto insertBuiltInProfile(String language) { - RulesProfileDto ruleProfileDto = newRuleProfileDto(rp -> rp.setIsBuiltIn(true).setLanguage(language)); - db.getDbClient().qualityProfileDao().insert(db.getSession(), ruleProfileDto); - db.commit(); - return ruleProfileDto; - } - - private void activateRuleInDb(RulesProfileDto profile, RuleDefinitionDto rule, RulePriority severity) { - ActiveRuleDto dto = new ActiveRuleDto() - .setProfileId(profile.getId()) - .setSeverity(severity.name()) - .setRuleId(rule.getId()) - .setCreatedAt(nextLong()) - .setUpdatedAt(nextLong()); - db.getDbClient().activeRuleDao().insert(db.getSession(), dto); - db.commit(); - } - - private QProfileDto insertProfile(OrganizationDto organization, Consumer<QProfileDto> consumer) { - QProfileDto builtInQProfileDto = db.qualityProfiles().insert(organization, consumer); - db.commit(); - return builtInQProfileDto; - } - - private static String newLanguageKey() { - return randomAlphanumeric(20).toLowerCase(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java deleted file mode 100644 index 6b7d6a6dd73..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.qualityprofile; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; -import org.sonar.api.resources.Language; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.core.util.UuidFactoryFast; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.qualityprofile.RulesProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.language.LanguageTesting; -import org.sonar.server.tester.UserSessionRule; - -import static java.lang.String.format; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.sonar.db.qualityprofile.QualityProfileTesting.newQualityProfileDto; -import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto; - -public class RegisterQualityProfilesTest { - private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo"); - private static final Language BAR_LANGUAGE = LanguageTesting.newLanguage("bar"); - - private System2 system2 = new AlwaysIncreasingSystem2(); - @Rule - public DbTester db = DbTester.create(system2); - @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public BuiltInQProfileRepositoryRule builtInQProfileRepositoryRule = new BuiltInQProfileRepositoryRule(); - @Rule - public LogTester logTester = new LogTester(); - - private DbClient dbClient = db.getDbClient(); - private DummyBuiltInQProfileInsert insert = new DummyBuiltInQProfileInsert(); - private DummyBuiltInQProfileUpdate update = new DummyBuiltInQProfileUpdate(); - private RegisterQualityProfiles underTest = new RegisterQualityProfiles(builtInQProfileRepositoryRule, dbClient, insert, update, mock(BuiltInQualityProfilesUpdateListener.class), system2); - - @Test - public void start_fails_if_BuiltInQProfileRepository_has_not_been_initialized() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("initialize must be called first"); - - underTest.start(); - } - - @Test - public void persist_built_in_profiles_that_are_not_persisted_yet() { - BuiltInQProfile builtInQProfile = builtInQProfileRepositoryRule.add(FOO_LANGUAGE, "Sonar way"); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - assertThat(insert.callLogs).containsExactly(builtInQProfile); - assertThat(update.callLogs).isEmpty(); - assertThat(logTester.logs(LoggerLevel.INFO)).contains("Register profile foo/Sonar way"); - } - - @Test - public void dont_persist_built_in_profiles_that_are_already_persisted() { - String name = "doh"; - - BuiltInQProfile persistedBuiltIn = builtInQProfileRepositoryRule.add(FOO_LANGUAGE, name, true); - BuiltInQProfile nonPersistedBuiltIn = builtInQProfileRepositoryRule.add(BAR_LANGUAGE, name, true); - builtInQProfileRepositoryRule.initialize(); - insertRulesProfile(persistedBuiltIn); - - underTest.start(); - - assertThat(insert.callLogs).containsExactly(nonPersistedBuiltIn); - assertThat(update.callLogs).containsExactly(persistedBuiltIn); - } - - @Test - public void rename_custom_outdated_profiles_if_same_name_than_built_in_profile() { - OrganizationDto org1 = db.organizations().insert(org -> org.setKey("org1")); - OrganizationDto org2 = db.organizations().insert(org -> org.setKey("org2")); - - QProfileDto outdatedProfileInOrg1 = db.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false) - .setLanguage(FOO_LANGUAGE.getKey()).setName("Sonar way")); - QProfileDto outdatedProfileInOrg2 = db.qualityProfiles().insert(org2, p -> p.setIsBuiltIn(false) - .setLanguage(FOO_LANGUAGE.getKey()).setName("Sonar way")); - builtInQProfileRepositoryRule.add(FOO_LANGUAGE, "Sonar way", false); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - assertThat(selectPersistedName(outdatedProfileInOrg1)).isEqualTo("Sonar way (outdated copy)"); - assertThat(selectPersistedName(outdatedProfileInOrg2)).isEqualTo("Sonar way (outdated copy)"); - assertThat(logTester.logs(LoggerLevel.INFO)).contains("Rename Quality profiles [foo/Sonar way] to [Sonar way (outdated copy)] in 2Â organizations"); - } - - @Test - public void update_built_in_profile_if_it_already_exists() { - RulesProfileDto ruleProfile = newRuleProfileDto(rp -> rp.setIsBuiltIn(true).setName("Sonar way").setLanguage(FOO_LANGUAGE.getKey())); - db.getDbClient().qualityProfileDao().insert(db.getSession(), ruleProfile); - db.commit(); - - BuiltInQProfile builtIn = builtInQProfileRepositoryRule.add(FOO_LANGUAGE, ruleProfile.getName(), false); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - assertThat(insert.callLogs).isEmpty(); - assertThat(update.callLogs).containsExactly(builtIn); - assertThat(logTester.logs(LoggerLevel.INFO)).contains("Update profile foo/Sonar way"); - } - - @Test - public void update_default_built_in_quality_profile() { - String orgUuid = UuidFactoryFast.getInstance().create(); - - RulesProfileDto ruleProfileWithoutRule = newRuleProfileDto(rp -> rp.setIsBuiltIn(true).setName("Sonar way").setLanguage(FOO_LANGUAGE.getKey())); - RulesProfileDto ruleProfileWithOneRule = newRuleProfileDto(rp -> rp.setIsBuiltIn(true).setName("Sonar way 2").setLanguage(FOO_LANGUAGE.getKey())); - - QProfileDto qProfileWithoutRule = newQualityProfileDto() - .setIsBuiltIn(true) - .setLanguage(FOO_LANGUAGE.getKey()) - .setOrganizationUuid(orgUuid) - .setRulesProfileUuid(ruleProfileWithoutRule.getKee()); - QProfileDto qProfileWithOneRule = newQualityProfileDto() - .setIsBuiltIn(true) - .setLanguage(FOO_LANGUAGE.getKey()) - .setOrganizationUuid(orgUuid) - .setRulesProfileUuid(ruleProfileWithOneRule.getKee()); - - db.qualityProfiles().insert(qProfileWithoutRule, qProfileWithOneRule); - db.qualityProfiles().setAsDefault(qProfileWithoutRule); - - RuleDefinitionDto ruleDefinition = db.rules().insert(); - db.qualityProfiles().activateRule(qProfileWithOneRule, ruleDefinition); - db.commit(); - - builtInQProfileRepositoryRule.add(FOO_LANGUAGE, ruleProfileWithoutRule.getName(), true); - builtInQProfileRepositoryRule.add(FOO_LANGUAGE, ruleProfileWithOneRule.getName(), false); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - logTester.logs(LoggerLevel.INFO).contains( - format("Default built-in quality profile for language [foo] has been updated from [%s] to [%s] since previous default does not have active rules.", - qProfileWithoutRule.getName(), qProfileWithOneRule.getName())); - - assertThat(selectUuidOfDefaultProfile(FOO_LANGUAGE.getKey())) - .isPresent().get() - .isEqualTo(qProfileWithOneRule.getKee()); - } - - private Optional<String> selectUuidOfDefaultProfile(String language) { - return db.select("select qprofile_uuid as \"profileUuid\" " + - " from default_qprofiles " + - " where language='" + language + "'") - .stream() - .findFirst() - .map(m -> (String) m.get("profileUuid")); - } - - private String selectPersistedName(QProfileDto profile) { - return db.qualityProfiles().selectByUuid(profile.getKee()).get().getName(); - } - - private void insertRulesProfile(BuiltInQProfile builtIn) { - RulesProfileDto dto = newRuleProfileDto(rp -> rp - .setIsBuiltIn(true) - .setLanguage(builtIn.getLanguage()) - .setName(builtIn.getName())); - dbClient.qualityProfileDao().insert(db.getSession(), dto); - db.commit(); - } - - - - private static class DummyBuiltInQProfileInsert implements BuiltInQProfileInsert { - private final List<BuiltInQProfile> callLogs = new ArrayList<>(); - - @Override - public void create(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtIn) { - callLogs.add(builtIn); - } - } - - private static class DummyBuiltInQProfileUpdate implements BuiltInQProfileUpdate { - private final List<BuiltInQProfile> callLogs = new ArrayList<>(); - - @Override - public List<ActiveRuleChange> update(DbSession dbSession, BuiltInQProfile builtIn, RulesProfileDto ruleProfile) { - callLogs.add(builtIn); - return Collections.emptyList(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java deleted file mode 100644 index a557963cee6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.IntStream; -import org.junit.Before; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.sonar.api.resources.Language; -import org.sonar.api.resources.Languages; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleScope; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rules.RuleType; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.utils.DateUtils; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.core.util.UuidFactory; -import org.sonar.core.util.UuidFactoryFast; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.rule.DeprecatedRuleKeyDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.rule.RuleDto.Scope; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.db.rule.RuleRepositoryDto; -import org.sonar.server.es.EsTester; -import org.sonar.server.es.SearchIdResult; -import org.sonar.server.es.SearchOptions; -import org.sonar.server.organization.OrganizationFlags; -import org.sonar.server.organization.TestOrganizationFlags; -import org.sonar.server.plugins.ServerPluginRepository; -import org.sonar.server.qualityprofile.QProfileRules; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleIndexDefinition; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.rule.index.RuleQuery; - -import static com.google.common.collect.Sets.newHashSet; -import static java.lang.String.valueOf; -import static java.util.Collections.singletonList; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.api.rule.RuleStatus.READY; -import static org.sonar.api.rule.RuleStatus.REMOVED; -import static org.sonar.api.rule.Severity.BLOCKER; -import static org.sonar.api.rule.Severity.INFO; -import static org.sonar.api.server.rule.RulesDefinition.NewRepository; -import static org.sonar.api.server.rule.RulesDefinition.NewRule; - -@RunWith(DataProviderRunner.class) -public class RegisterRulesTest { - - private static final String FAKE_PLUGIN_KEY = "unittest"; - private static final Date DATE1 = DateUtils.parseDateTime("2014-01-01T19:10:03+0100"); - private static final Date DATE2 = DateUtils.parseDateTime("2014-02-01T12:10:03+0100"); - private static final Date DATE3 = DateUtils.parseDateTime("2014-03-01T12:10:03+0100"); - - private static final RuleKey EXTERNAL_RULE_KEY1 = RuleKey.of("external_eslint", "rule1"); - private static final RuleKey EXTERNAL_HOTSPOT_RULE_KEY = RuleKey.of("external_eslint", "hotspot"); - - private static final RuleKey RULE_KEY1 = RuleKey.of("fake", "rule1"); - private static final RuleKey RULE_KEY2 = RuleKey.of("fake", "rule2"); - private static final RuleKey RULE_KEY3 = RuleKey.of("fake", "rule3"); - private static final RuleKey HOTSPOT_RULE_KEY = RuleKey.of("fake", "hotspot"); - - private System2 system = mock(System2.class); - - @org.junit.Rule - public ExpectedException expectedException = ExpectedException.none(); - @org.junit.Rule - public DbTester db = DbTester.create(system); - @org.junit.Rule - public EsTester es = EsTester.create(); - @org.junit.Rule - public LogTester logTester = new LogTester(); - - private QProfileRules qProfileRules = mock(QProfileRules.class); - private WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class); - private DbClient dbClient = db.getDbClient(); - private RuleIndexer ruleIndexer; - private ActiveRuleIndexer activeRuleIndexer; - private RuleIndex ruleIndex; - private OrganizationDto defaultOrganization; - private OrganizationFlags organizationFlags = TestOrganizationFlags.standalone(); - private UuidFactory uuidFactory = UuidFactoryFast.getInstance(); - - @Before - public void before() { - when(system.now()).thenReturn(DATE1.getTime()); - ruleIndexer = new RuleIndexer(es.client(), dbClient); - ruleIndex = new RuleIndex(es.client(), system); - activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client()); - defaultOrganization = db.getDefaultOrganization(); - } - - @Test - public void insert_new_rules() { - execute(new FakeRepositoryV1()); - - // verify db - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3); - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), RULE_KEY1); - assertThat(rule1.getName()).isEqualTo("One"); - assertThat(rule1.getDescription()).isEqualTo("Description of One"); - assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER); - assertThat(rule1.getTags()).isEmpty(); - assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3"); - assertThat(rule1.getConfigKey()).isEqualTo("config1"); - assertThat(rule1.getStatus()).isEqualTo(RuleStatus.BETA); - assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime()); - assertThat(rule1.getScope()).isEqualTo(Scope.ALL); - assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime()); - assertThat(rule1.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET.name()); - assertThat(rule1.getDefRemediationGapMultiplier()).isEqualTo("5d"); - assertThat(rule1.getDefRemediationBaseEffort()).isEqualTo("10h"); - assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant()); - assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY); - assertThat(rule1.isExternal()).isFalse(); - assertThat(rule1.isAdHoc()).isFalse(); - - RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), HOTSPOT_RULE_KEY); - assertThat(hotspotRule.getName()).isEqualTo("Hotspot"); - assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot"); - assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime()); - assertThat(hotspotRule.getUpdatedAt()).isEqualTo(DATE1.getTime()); - assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant()); - assertThat(hotspotRule.getSecurityStandards()).containsExactly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3"); - - List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(db.getSession(), RULE_KEY1); - assertThat(params).hasSize(2); - RuleParamDto param = getParam(params, "param1"); - assertThat(param.getDescription()).isEqualTo("parameter one"); - assertThat(param.getDefaultValue()).isEqualTo("default1"); - - // verify index - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), RULE_KEY2); - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule2.getId(), hotspotRule.getId()); - - // verify repositories - assertThat(dbClient.ruleRepositoryDao().selectAll(db.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake"); - } - - @Test - public void insert_new_external_rule() { - execute(new ExternalRuleRepository()); - - // verify db - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(2); - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), EXTERNAL_RULE_KEY1); - assertThat(rule1.getName()).isEqualTo("One"); - assertThat(rule1.getDescription()).isEqualTo("Description of One"); - assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER); - assertThat(rule1.getTags()).isEmpty(); - assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3"); - assertThat(rule1.getConfigKey()).isEqualTo("config1"); - assertThat(rule1.getStatus()).isEqualTo(RuleStatus.BETA); - assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime()); - assertThat(rule1.getScope()).isEqualTo(Scope.ALL); - assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime()); - assertThat(rule1.getDefRemediationFunction()).isNull(); - assertThat(rule1.getDefRemediationGapMultiplier()).isNull(); - assertThat(rule1.getDefRemediationBaseEffort()).isNull(); - assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant()); - assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY); - assertThat(rule1.isExternal()).isTrue(); - assertThat(rule1.isAdHoc()).isFalse(); - - RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), EXTERNAL_HOTSPOT_RULE_KEY); - assertThat(hotspotRule.getName()).isEqualTo("Hotspot"); - assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot"); - assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime()); - assertThat(hotspotRule.getUpdatedAt()).isEqualTo(DATE1.getTime()); - assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant()); - assertThat(hotspotRule.getSecurityStandards()).containsExactly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3"); - } - - @Test - public void insert_then_remove_rule() { - String ruleKey = randomAlphanumeric(5); - - // register one rule - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule(ruleKey) - .setName(randomAlphanumeric(5)) - .setHtmlDescription(randomAlphanumeric(20)); - repo.done(); - }); - - // verify db - List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession()); - assertThat(rules) - .extracting(RuleDefinitionDto::getKey) - .extracting(RuleKey::rule) - .containsExactly(ruleKey); - RuleDefinitionDto rule = rules.iterator().next(); - - // verify index - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()) - .containsExactly(rule.getId()); - - // register no rule - execute(context -> context.createRepository("fake", "java").done()); - - // verify db - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())) - .extracting(RuleDefinitionDto::getKey) - .extracting(RuleKey::rule) - .containsExactly(ruleKey); - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())) - .extracting(RuleDefinitionDto::getStatus) - .containsExactly(REMOVED); - - // verify index - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()) - .isEmpty(); - } - - @Test - public void mass_insert_then_remove_rule() { - int numberOfRules = 5000; - - // register many rules - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - IntStream.range(0, numberOfRules) - .mapToObj(i -> "rule-" + i) - .forEach(ruleKey -> repo.createRule(ruleKey) - .setName(randomAlphanumeric(20)) - .setHtmlDescription(randomAlphanumeric(20))); - repo.done(); - }); - - // verify db - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())) - .hasSize(numberOfRules) - .extracting(RuleDefinitionDto::getStatus) - .containsOnly(READY); - - // verify index - assertThat(es.countDocuments(RuleIndexDefinition.TYPE_RULE)).isEqualTo(numberOfRules); - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()) - .isNotEmpty(); - - // register no rule - execute(context -> context.createRepository("fake", "java").done()); - - // verify db - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())) - .hasSize(numberOfRules) - .extracting(RuleDefinitionDto::getStatus) - .containsOnly(REMOVED); - - // verify index (documents are still in the index, but all are removed) - assertThat(es.countDocuments(RuleIndexDefinition.TYPE_RULE)).isEqualTo(numberOfRules); - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()) - .isEmpty(); - } - - @Test - public void delete_repositories_that_have_been_uninstalled() { - RuleRepositoryDto repository = new RuleRepositoryDto("findbugs", "java", "Findbugs"); - DbSession dbSession = db.getSession(); - db.getDbClient().ruleRepositoryDao().insertOrUpdate(dbSession, singletonList(repository)); - dbSession.commit(); - - execute(new FakeRepositoryV1()); - - assertThat(db.getDbClient().ruleRepositoryDao().selectAll(dbSession)).extracting(RuleRepositoryDto::getKey).containsOnly("fake"); - } - - @Test - public void update_and_remove_rules_on_changes() { - execute(new FakeRepositoryV1()); - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3); - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2); - RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, HOTSPOT_RULE_KEY); - assertThat(es.getIds(RuleIndexDefinition.TYPE_RULE)).containsOnly(valueOf(rule1.getId()), valueOf(rule2.getId()), valueOf(hotspotRule.getId())); - - // user adds tags and sets markdown note - rule1.setTags(newHashSet("usertag1", "usertag2")); - rule1.setNoteData("user *note*"); - rule1.setNoteUserUuid("marius"); - dbClient.ruleDao().insertOrUpdate(db.getSession(), rule1.getMetadata()); - db.getSession().commit(); - - when(system.now()).thenReturn(DATE2.getTime()); - execute(new FakeRepositoryV2()); - - // rule1 has been updated - rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule1.getName()).isEqualTo("One v2"); - assertThat(rule1.getDescription()).isEqualTo("Description of One v2"); - assertThat(rule1.getSeverityString()).isEqualTo(INFO); - assertThat(rule1.getTags()).containsOnly("usertag1", "usertag2"); - assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag4"); - assertThat(rule1.getConfigKey()).isEqualTo("config1 v2"); - assertThat(rule1.getNoteData()).isEqualTo("user *note*"); - assertThat(rule1.getNoteUserUuid()).isEqualTo("marius"); - assertThat(rule1.getStatus()).isEqualTo(READY); - assertThat(rule1.getType()).isEqualTo(RuleType.BUG.getDbConstant()); - assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime()); - assertThat(rule1.getUpdatedAt()).isEqualTo(DATE2.getTime()); - - List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(db.getSession(), RULE_KEY1); - assertThat(params).hasSize(2); - RuleParamDto param = getParam(params, "param1"); - assertThat(param.getDescription()).isEqualTo("parameter one v2"); - assertThat(param.getDefaultValue()).isEqualTo("default1 v2"); - - // rule2 has been removed -> status set to REMOVED but db row is not deleted - rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2); - assertThat(rule2.getStatus()).isEqualTo(REMOVED); - assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2.getTime()); - - // rule3 has been created - RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY3); - assertThat(rule3).isNotNull(); - assertThat(rule3.getStatus()).isEqualTo(READY); - - // verify index - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId()); - - // verify repositories - assertThat(dbClient.ruleRepositoryDao().selectAll(db.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake"); - } - - @Test - public void add_new_tag() { - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule1") - .setName("Rule One") - .setHtmlDescription("Description of Rule One") - .setTags("tag1"); - repo.done(); - }); - - OrganizationDto defaultOrganization = db.getDefaultOrganization(); - RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule.getSystemTags()).containsOnly("tag1"); - - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule1") - .setName("Rule One") - .setHtmlDescription("Description of Rule One") - .setTags("tag1", "tag2"); - repo.done(); - }); - - rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule.getSystemTags()).containsOnly("tag1", "tag2"); - } - - @Test - public void add_new_security_standards() { - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule1") - .setName("Rule One") - .setHtmlDescription("Description of Rule One") - .addOwaspTop10(RulesDefinition.OwaspTop10.A1) - .addCwe(123); - repo.done(); - }); - - OrganizationDto defaultOrganization = db.getDefaultOrganization(); - RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule.getSecurityStandards()).containsOnly("cwe:123", "owaspTop10:a1"); - - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule1") - .setName("Rule One") - .setHtmlDescription("Description of Rule One") - .addOwaspTop10(RulesDefinition.OwaspTop10.A1, RulesDefinition.OwaspTop10.A3) - .addCwe(1, 123, 863); - repo.done(); - }); - - rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule.getSecurityStandards()).containsOnly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3"); - } - - @Test - public void update_only_rule_name() { - when(system.now()).thenReturn(DATE1.getTime()); - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule") - .setName("Name1") - .setHtmlDescription("Description"); - repo.done(); - }); - - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule") - .setName("Name2") - .setHtmlDescription("Description"); - repo.done(); - }); - - // rule1 has been updated - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of("fake", "rule")); - assertThat(rule1.getName()).isEqualTo("Name2"); - assertThat(rule1.getDescription()).isEqualTo("Description"); - - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()).getTotal()).isEqualTo(1); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isEqualTo(0); - } - - @Test - public void update_if_rule_key_renamed_and_deprecated_key_declared() { - String ruleKey1 = "rule1"; - String ruleKey2 = "rule2"; - String repository = "fake"; - - when(system.now()).thenReturn(DATE1.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repository, "java"); - repo.createRule(ruleKey1) - .setName("Name1") - .setHtmlDescription("Description"); - repo.done(); - }); - - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey1)); - SearchIdResult<Integer> searchRule1 = ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()); - assertThat(searchRule1.getIds()).containsOnly(rule1.getId()); - assertThat(searchRule1.getTotal()).isEqualTo(1); - - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repository, "java"); - repo.createRule(ruleKey2) - .setName("Name2") - .setHtmlDescription("Description") - .addDeprecatedRuleKey(repository, ruleKey1); - repo.done(); - }); - - // rule2 is actually rule1 - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey2)); - assertThat(rule2.getId()).isEqualTo(rule1.getId()); - assertThat(rule2.getName()).isEqualTo("Name2"); - assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription()); - - SearchIdResult<Integer> searchRule2 = ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()); - assertThat(searchRule2.getIds()).containsOnly(rule2.getId()); - assertThat(searchRule2.getTotal()).isEqualTo(1); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isEqualTo(0); - } - - @Test - public void update_if_repository_changed_and_deprecated_key_declared() { - String ruleKey = "rule"; - String repository1 = "fake1"; - String repository2 = "fake2"; - - when(system.now()).thenReturn(DATE1.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repository1, "java"); - repo.createRule(ruleKey) - .setName("Name1") - .setHtmlDescription("Description"); - repo.done(); - }); - - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey)); - SearchIdResult<Integer> searchRule1 = ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()); - assertThat(searchRule1.getIds()).containsOnly(rule1.getId()); - assertThat(searchRule1.getTotal()).isEqualTo(1); - - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repository2, "java"); - repo.createRule(ruleKey) - .setName("Name2") - .setHtmlDescription("Description") - .addDeprecatedRuleKey(repository1, ruleKey); - repo.done(); - }); - - // rule2 is actually rule1 - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey)); - assertThat(rule2.getId()).isEqualTo(rule1.getId()); - assertThat(rule2.getName()).isEqualTo("Name2"); - assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription()); - - SearchIdResult<Integer> searchRule2 = ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()); - assertThat(searchRule2.getIds()).containsOnly(rule2.getId()); - assertThat(searchRule2.getTotal()).isEqualTo(1); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isEqualTo(0); - } - - @Test - @UseDataProvider("allRenamingCases") - public void update_if_only_renamed_and_deprecated_key_declared(String ruleKey1, String repo1, String ruleKey2, String repo2) { - String name = "Name1"; - String description = "Description"; - when(system.now()).thenReturn(DATE1.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repo1, "java"); - repo.createRule(ruleKey1) - .setName(name) - .setHtmlDescription(description); - repo.done(); - }); - - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repo1, ruleKey1)); - assertThat(ruleIndex.search(new RuleQuery().setQueryText(name), new SearchOptions()).getIds()) - .containsOnly(rule1.getId()); - - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repo2, "java"); - repo.createRule(ruleKey2) - .setName(name) - .setHtmlDescription(description) - .addDeprecatedRuleKey(repo1, ruleKey1); - repo.done(); - }); - - // rule2 is actually rule1 - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repo2, ruleKey2)); - assertThat(rule2.getId()).isEqualTo(rule1.getId()); - assertThat(rule2.getName()).isEqualTo(rule1.getName()); - assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription()); - - assertThat(ruleIndex.search(new RuleQuery().setQueryText(name), new SearchOptions()).getIds()) - .containsOnly(rule2.getId()); - } - - @DataProvider - public static Object[][] allRenamingCases() { - return new Object[][] { - {"repo1", "rule1", "repo1", "rule2"}, - {"repo1", "rule1", "repo2", "rule1"}, - {"repo1", "rule1", "repo2", "rule2"}, - }; - } - - @Test - public void update_if_repository_and_key_changed_and_deprecated_key_declared_among_others() { - String ruleKey1 = "rule1"; - String ruleKey2 = "rule2"; - String repository1 = "fake1"; - String repository2 = "fake2"; - - when(system.now()).thenReturn(DATE1.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repository1, "java"); - repo.createRule(ruleKey1) - .setName("Name1") - .setHtmlDescription("Description"); - repo.done(); - }); - - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey1)); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getIds()) - .containsOnly(rule1.getId()); - - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - RulesDefinition.NewRepository repo = context.createRepository(repository2, "java"); - repo.createRule(ruleKey2) - .setName("Name2") - .setHtmlDescription("Description") - .addDeprecatedRuleKey("foo", "bar") - .addDeprecatedRuleKey(repository1, ruleKey1) - .addDeprecatedRuleKey("some", "noise"); - repo.done(); - }); - - // rule2 is actually rule1 - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey2)); - assertThat(rule2.getId()).isEqualTo(rule1.getId()); - - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()).getIds()) - .containsOnly(rule1.getId()); - } - - @Test - public void update_only_rule_description() { - when(system.now()).thenReturn(DATE1.getTime()); - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule") - .setName("Name") - .setHtmlDescription("Desc1"); - repo.done(); - }); - - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule") - .setName("Name") - .setHtmlDescription("Desc2"); - repo.done(); - }); - - // rule1 has been updated - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of("fake", "rule")); - assertThat(rule1.getName()).isEqualTo("Name"); - assertThat(rule1.getDescription()).isEqualTo("Desc2"); - - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc2"), new SearchOptions()).getTotal()).isEqualTo(1); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc1"), new SearchOptions()).getTotal()).isEqualTo(0); - } - - @Test - public void rule_previously_created_as_adhoc_becomes_none_adhoc() { - RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake").setIsExternal(true).setIsAdHoc(true)); - when(system.now()).thenReturn(DATE2.getTime()); - execute((RulesDefinition) context -> { - NewRepository repo = context.createExternalRepository("fake", rule.getLanguage()); - repo.createRule(rule.getRuleKey()) - .setName(rule.getName()) - .setHtmlDescription(rule.getDescription()); - repo.done(); - }); - - RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization.getUuid(), rule.getKey()).get(); - assertThat(reloaded.isAdHoc()).isFalse(); - } - - @Test - public void remove_no_more_defined_external_rule() { - RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake") - .setStatus(READY) - .setIsExternal(true) - .setIsAdHoc(false)); - - execute(); - - RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization.getUuid(), rule.getKey()).get(); - assertThat(reloaded.getStatus()).isEqualTo(REMOVED); - } - - @Test - public void do_not_remove_no_more_defined_ad_hoc_rule() { - RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake") - .setStatus(READY) - .setIsExternal(true) - .setIsAdHoc(true)); - - execute(); - - RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization.getUuid(), rule.getKey()).get(); - assertThat(reloaded.getStatus()).isEqualTo(READY); - } - - @Test - public void disable_then_enable_rule() { - // Install rule - when(system.now()).thenReturn(DATE1.getTime()); - execute(new FakeRepositoryV1()); - - // Uninstall rule - when(system.now()).thenReturn(DATE2.getTime()); - execute(); - - RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule.getStatus()).isEqualTo(REMOVED); - assertThat(ruleIndex.search(new RuleQuery().setKey(RULE_KEY1.toString()), new SearchOptions()).getTotal()).isEqualTo(0); - - // Re-install rule - when(system.now()).thenReturn(DATE3.getTime()); - execute(new FakeRepositoryV1()); - - rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule.getStatus()).isEqualTo(RuleStatus.BETA); - assertThat(ruleIndex.search(new RuleQuery().setKey(RULE_KEY1.toString()), new SearchOptions()).getTotal()).isEqualTo(1); - } - - @Test - public void do_not_update_rules_when_no_changes() { - execute(new FakeRepositoryV1()); - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3); - - when(system.now()).thenReturn(DATE2.getTime()); - execute(new FakeRepositoryV1()); - - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime()); - assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime()); - } - - @Test - public void do_not_update_already_removed_rules() { - execute(new FakeRepositoryV1()); - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3); - - RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1); - RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2); - RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, HOTSPOT_RULE_KEY); - assertThat(es.getIds(RuleIndexDefinition.TYPE_RULE)).containsOnly(valueOf(rule1.getId()), valueOf(rule2.getId()), valueOf(hotspotRule.getId())); - - assertThat(rule2.getStatus()).isEqualTo(READY); - - when(system.now()).thenReturn(DATE2.getTime()); - execute(new FakeRepositoryV2()); - - // On MySQL, need to update a rule otherwise rule2 will be seen as READY, but why ??? - dbClient.ruleDao().update(db.getSession(), rule1.getDefinition()); - db.getSession().commit(); - - // rule2 is removed - rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2); - RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY3); - assertThat(rule2.getStatus()).isEqualTo(REMOVED); - - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId()); - - when(system.now()).thenReturn(DATE3.getTime()); - execute(new FakeRepositoryV2()); - db.getSession().commit(); - - // -> rule2 is still removed, but not update at DATE3 - rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2); - assertThat(rule2.getStatus()).isEqualTo(REMOVED); - assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2.getTime()); - - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId()); - } - - @Test - public void mass_insert() { - execute(new BigRepository()); - assertThat(db.countRowsOfTable("rules")).isEqualTo(BigRepository.SIZE); - assertThat(db.countRowsOfTable("rules_parameters")).isEqualTo(BigRepository.SIZE * 20); - assertThat(es.getIds(RuleIndexDefinition.TYPE_RULE)).hasSize(BigRepository.SIZE); - } - - @Test - public void manage_repository_extensions() { - execute(new FindbugsRepository(), new FbContribRepository()); - List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession()); - assertThat(rules).hasSize(2); - for (RuleDefinitionDto rule : rules) { - assertThat(rule.getRepositoryKey()).isEqualTo("findbugs"); - } - } - - @Test - public void remove_system_tags_when_plugin_does_not_provide_any() { - // Rule already exists in DB, with some system tags - dbClient.ruleDao().insert(db.getSession(), new RuleDefinitionDto() - .setRuleKey("rule1") - .setRepositoryKey("findbugs") - .setName("Rule One") - .setScope(Scope.ALL) - .setDescription("Rule one description") - .setDescriptionFormat(RuleDto.Format.HTML) - .setSystemTags(newHashSet("tag1", "tag2"))); - db.getSession().commit(); - - // Synchronize rule without tag - execute(new FindbugsRepository()); - - List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession()); - assertThat(rules).hasSize(1); - RuleDefinitionDto result = rules.get(0); - assertThat(result.getKey()).isEqualTo(RuleKey.of("findbugs", "rule1")); - assertThat(result.getSystemTags()).isEmpty(); - } - - @Test - public void ignore_template_rules_if_organizations_are_enabled() { - organizationFlags.enable(db.getSession()); - execute(new RepositoryWithOneTemplateRule()); - - List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession()); - assertThat(rules).hasSize(0); - } - - @Test - public void log_ignored_template_rules_if_organizations_are_enabled() { - organizationFlags.enable(db.getSession()); - execute(new RepositoryWithOneTemplateRule()); - - assertThat(logTester.logs(LoggerLevel.INFO)).contains("Template rule test:rule1 will not be imported, because organizations are enabled."); - } - - @Test - public void rules_that_deprecate_previous_rule_must_be_recorded() { - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule1") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - repo.done(); - }); - - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("newKey") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA) - .addDeprecatedRuleKey("fake", "rule1") - .addDeprecatedRuleKey("fake", "rule2"); - repo.done(); - }); - - List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession()); - Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession()); - assertThat(rules).hasSize(1); - assertThat(deprecatedRuleKeys).hasSize(2); - } - - @Test - public void rules_that_remove_deprecated_key_must_remove_records() { - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("rule1") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - repo.done(); - }); - - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("newKey") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA) - .addDeprecatedRuleKey("fake", "rule1") - .addDeprecatedRuleKey("fake", "rule2"); - repo.done(); - }); - - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(1); - Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession()); - assertThat(deprecatedRuleKeys).hasSize(2); - - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("newKey") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - repo.done(); - }); - - assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(1); - deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession()); - assertThat(deprecatedRuleKeys).hasSize(0); - } - - @Test - public void declaring_two_rules_with_same_deprecated_RuleKey_should_throw_ISE() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("The following deprecated rule keys are declared at least twice [fake:old]"); - - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("newKey1") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .addDeprecatedRuleKey("fake", "old") - .setStatus(RuleStatus.BETA); - repo.createRule("newKey2") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .addDeprecatedRuleKey("fake", "old") - .setStatus(RuleStatus.BETA); - repo.done(); - }); - } - - @Test - public void declaring_a_rule_with_a_deprecated_RuleKey_still_used_should_throw_ISE() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("The following rule keys are declared both as deprecated and used key [fake:newKey1]"); - - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("newKey1") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - - repo.createRule("newKey2") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .addDeprecatedRuleKey("fake", "newKey1") - .setStatus(RuleStatus.BETA); - repo.done(); - }); - } - - @Test - public void updating_the_deprecated_to_a_new_ruleKey_should_throw_an_ISE() { - // On this new rule add a deprecated key - execute(context -> createRule(context, "javascript", "javascript", "s103", - r -> r.addDeprecatedRuleKey("javascript", "linelength"))); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("An incorrect state of deprecated rule keys has been detected.\n " + - "The deprecated rule key [javascript:linelength] was previously deprecated by [javascript:s103]. [javascript:s103] should be a deprecated key of [sonarjs:s103],"); - - // This rule should have been moved to another repository - execute(context -> createRule(context, "javascript", "sonarjs", "s103", - r -> r.addDeprecatedRuleKey("javascript", "linelength"))); - } - - @Test - public void declaring_a_rule_with_an_existing_RuleKey_still_used_should_throw_IAE() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The rule 'newKey1' of repository 'fake' is declared several times"); - - execute(context -> { - NewRepository repo = context.createRepository("fake", "java"); - repo.createRule("newKey1") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - - repo.createRule("newKey1") - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setType(RuleType.CODE_SMELL) - .addDeprecatedRuleKey("fake", "newKey1") - .setStatus(RuleStatus.BETA); - repo.done(); - }); - } - - private void execute(RulesDefinition... defs) { - ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class); - when(pluginRepository.getPluginKey(any(RulesDefinition.class))).thenReturn(FAKE_PLUGIN_KEY); - RuleDefinitionsLoader loader = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), mock(CommonRuleDefinitionsImpl.class), pluginRepository, - defs); - Languages languages = mock(Languages.class); - when(languages.get(any())).thenReturn(mock(Language.class)); - reset(webServerRuleFinder); - - RegisterRules task = new RegisterRules(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer, - languages, system, organizationFlags, webServerRuleFinder, uuidFactory); - task.start(); - // Execute a commit to refresh session state as the task is using its own session - db.getSession().commit(); - - verify(webServerRuleFinder).startCaching(); - } - - @SafeVarargs - private final void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) { - NewRepository repo = context.createRepository(repositoryKey, language); - NewRule newRule = repo.createRule(ruleKey) - .setName(ruleKey) - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - - Arrays.stream(consumers).forEach(c -> c.accept(newRule)); - repo.done(); - } - - private RuleParamDto getParam(List<RuleParamDto> params, String key) { - for (RuleParamDto param : params) { - if (param.getName().equals(key)) { - return param; - } - } - return null; - } - - static class FakeRepositoryV1 implements RulesDefinition { - @Override - public void define(Context context) { - NewRepository repo = context.createRepository("fake", "java"); - NewRule rule1 = repo.createRule(RULE_KEY1.rule()) - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setScope(RuleScope.ALL) - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA) - .setGapDescription("squid.S115.effortToFix"); - rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("5d", "10h")); - - rule1.createParam("param1").setDescription("parameter one").setDefaultValue("default1"); - rule1.createParam("param2").setDescription("parameter two").setDefaultValue("default2"); - - repo.createRule(HOTSPOT_RULE_KEY.rule()) - .setName("Hotspot") - .setHtmlDescription("Minimal hotspot") - .setType(RuleType.SECURITY_HOTSPOT) - .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3) - .addCwe(1, 123, 863); - - repo.createRule(RULE_KEY2.rule()) - .setName("Two") - .setHtmlDescription("Minimal rule"); - repo.done(); - } - } - - /** - * FakeRepositoryV1 with some changes - */ - static class FakeRepositoryV2 implements RulesDefinition { - @Override - public void define(Context context) { - NewRepository repo = context.createRepository("fake", "java"); - - // almost all the attributes of rule1 are changed - NewRule rule1 = repo.createRule(RULE_KEY1.rule()) - .setName("One v2") - .setHtmlDescription("Description of One v2") - .setSeverity(INFO) - .setInternalKey("config1 v2") - // tag2 and tag3 removed, tag4 added - .setTags("tag1", "tag4") - .setType(RuleType.BUG) - .setStatus(READY) - .setGapDescription("squid.S115.effortToFix.v2"); - rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("6d", "2h")); - rule1.createParam("param1").setDescription("parameter one v2").setDefaultValue("default1 v2"); - rule1.createParam("param2").setDescription("parameter two v2").setDefaultValue("default2 v2"); - - // rule2 is dropped, rule3 is new - repo.createRule(RULE_KEY3.rule()) - .setName("Three") - .setHtmlDescription("Rule Three"); - - repo.done(); - } - } - - static class ExternalRuleRepository implements RulesDefinition { - @Override - public void define(Context context) { - NewRepository repo = context.createExternalRepository("eslint", "js"); - repo.createRule(RULE_KEY1.rule()) - .setName("One") - .setHtmlDescription("Description of One") - .setSeverity(BLOCKER) - .setInternalKey("config1") - .setTags("tag1", "tag2", "tag3") - .setScope(RuleScope.ALL) - .setType(RuleType.CODE_SMELL) - .setStatus(RuleStatus.BETA); - - repo.createRule(EXTERNAL_HOTSPOT_RULE_KEY.rule()) - .setName("Hotspot") - .setHtmlDescription("Minimal hotspot") - .setType(RuleType.SECURITY_HOTSPOT) - .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3) - .addCwe(1, 123, 863); - - repo.done(); - } - } - - static class BigRepository implements RulesDefinition { - static final int SIZE = 500; - - @Override - public void define(Context context) { - NewRepository repo = context.createRepository("big", "java"); - for (int i = 0; i < SIZE; i++) { - NewRule rule = repo.createRule("rule" + i) - .setName("name of " + i) - .setHtmlDescription("description of " + i); - for (int j = 0; j < 20; j++) { - rule.createParam("param" + j); - } - - } - repo.done(); - } - } - - static class FindbugsRepository implements RulesDefinition { - @Override - public void define(Context context) { - NewRepository repo = context.createRepository("findbugs", "java"); - repo.createRule("rule1") - .setName("Rule One") - .setHtmlDescription("Description of Rule One"); - repo.done(); - } - } - - static class FbContribRepository implements RulesDefinition { - @Override - public void define(Context context) { - NewExtendedRepository repo = context.extendRepository("findbugs", "java"); - repo.createRule("rule2") - .setName("Rule Two") - .setHtmlDescription("Description of Rule Two"); - repo.done(); - } - } - - static class RepositoryWithOneTemplateRule implements RulesDefinition { - @Override - public void define(Context context) { - NewRepository repo = context.createRepository("test", "java"); - repo.createRule("rule1") - .setName("Rule One") - .setHtmlDescription("Description of Rule One") - .setTemplate(true); - repo.done(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorTest.java deleted file mode 100644 index 45bef460214..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorTest.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; -import java.util.Date; -import java.util.List; -import org.assertj.core.api.Fail; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.rule.RuleDto.Format; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.db.rule.RuleTesting; -import org.sonar.server.es.EsTester; -import org.sonar.server.es.SearchOptions; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.organization.TestDefaultOrganizationProvider; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.rule.index.RuleQuery; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.sonar.db.rule.RuleTesting.newRule; -import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations; - -public class RuleCreatorTest { - - private System2 system2 = mock(System2.class); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public DbTester dbTester = DbTester.create(system2); - - @Rule - public EsTester es = EsTester.create(); - - private RuleIndex ruleIndex = new RuleIndex(es.client(), system2); - private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), dbTester.getDbClient()); - private DbSession dbSession = dbTester.getSession(); - - private RuleCreator underTest = new RuleCreator(system2, new RuleIndexer(es.client(), dbTester.getDbClient()), dbTester.getDbClient(), newFullTypeValidations(), - TestDefaultOrganizationProvider.from(dbTester)); - - @Test - public void create_custom_rule() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - RuleDto rule = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, dbTester.getDefaultOrganization(), customRuleKey); - assertThat(rule).isNotNull(); - assertThat(rule.getKey()).isEqualTo(RuleKey.of("java", "CUSTOM_RULE")); - assertThat(rule.getPluginKey()).isEqualTo("sonarjava"); - assertThat(rule.getTemplateId()).isEqualTo(templateRule.getId()); - assertThat(rule.getName()).isEqualTo("My custom"); - assertThat(rule.getDescription()).isEqualTo("Some description"); - assertThat(rule.getSeverityString()).isEqualTo("MAJOR"); - assertThat(rule.getStatus()).isEqualTo(RuleStatus.READY); - assertThat(rule.getLanguage()).isEqualTo("java"); - assertThat(rule.getConfigKey()).isEqualTo("S001"); - assertThat(rule.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET"); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1h"); - assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); - assertThat(rule.getGapDescription()).isEqualTo("desc"); - assertThat(rule.getTags()).containsOnly("usertag1", "usertag2"); - assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4"); - assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123"); - assertThat(rule.isExternal()).isFalse(); - assertThat(rule.isAdHoc()).isFalse(); - - List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - - RuleParamDto param = params.get(0); - // From template rule - assertThat(param.getName()).isEqualTo("regex"); - assertThat(param.getDescription()).isEqualTo("Reg ex"); - assertThat(param.getType()).isEqualTo("STRING"); - // From user - assertThat(param.getDefaultValue()).isEqualTo("a.*"); - - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule.getId(), templateRule.getId()); - } - - @Test - public void create_custom_rule_with_empty_parameter_value() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "")); - - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - RuleParamDto param = params.get(0); - assertThat(param.getName()).isEqualTo("regex"); - assertThat(param.getDescription()).isEqualTo("Reg ex"); - assertThat(param.getType()).isEqualTo("STRING"); - assertThat(param.getDefaultValue()).isNull(); - } - - @Test - public void create_custom_rule_with_no_parameter_value() { - // insert template rule - RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam(); - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - RuleParamDto param = params.get(0); - assertThat(param.getName()).isEqualTo("myIntegers"); - assertThat(param.getDescription()).isEqualTo("My Integers"); - assertThat(param.getType()).isEqualTo("INTEGER,multiple=true,values=1;2;3"); - assertThat(param.getDefaultValue()).isNull(); - } - - @Test - public void create_custom_rule_with_multiple_parameter_values() { - // insert template rule - RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam(); - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("myIntegers", "1,3")); - - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - RuleParamDto param = params.get(0); - assertThat(param.getName()).isEqualTo("myIntegers"); - assertThat(param.getDescription()).isEqualTo("My Integers"); - assertThat(param.getType()).isEqualTo("INTEGER,multiple=true,values=1;2;3"); - assertThat(param.getDefaultValue()).isEqualTo("1,3"); - } - - @Test - public void fail_to_create_custom_rule_with_invalid_parameter() { - // insert template rule - RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Value 'polop' must be an integer."); - - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("myIntegers", "1,polop,2")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_with_invalid_parameters() { - // insert template rule - RuleDefinitionDto templateRule = createTemplateRuleWithTwoIntParams(); - - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("first", "polop", "second", "palap")); - try { - underTest.create(dbSession, newRule); - Fail.failBecauseExceptionWasNotThrown(BadRequestException.class); - } catch (BadRequestException badRequest) { - assertThat(badRequest.errors().toString()).contains("palap").contains("polop"); - } - } - - @Test - public void reactivate_custom_rule_if_already_exists_in_removed_status() { - String key = "CUSTOM_RULE"; - - // insert template rule - RuleDto templateRule = createTemplateRule(); - - // insert a removed rule - RuleDto rule = RuleTesting.newCustomRule(templateRule) - .setRuleKey(key) - .setStatus(RuleStatus.REMOVED) - .setName("Old name") - .setDescription("Old description") - .setDescriptionFormat(Format.MARKDOWN) - .setSeverity(Severity.INFO); - dbTester.rules().insert(rule.getDefinition()); - dbTester.rules().insertRuleParam(rule.getDefinition(), param -> param.setDefaultValue("a.*")); - dbSession.commit(); - - // Create custom rule with same key, but with different values - NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey()) - .setName("New name") - .setMarkdownDescription("New description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "c.*")); - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - RuleDefinitionDto result = dbTester.getDbClient().ruleDao().selectOrFailDefinitionByKey(dbSession, customRuleKey); - assertThat(result.getKey()).isEqualTo(RuleKey.of("java", key)); - assertThat(result.getStatus()).isEqualTo(RuleStatus.READY); - - // These values should be the same than before - assertThat(result.getName()).isEqualTo("Old name"); - assertThat(result.getDescription()).isEqualTo("Old description"); - assertThat(result.getSeverityString()).isEqualTo(Severity.INFO); - - List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - assertThat(params.get(0).getDefaultValue()).isEqualTo("a.*"); - } - - @Test - public void generate_reactivation_exception_when_rule_exists_in_removed_status_and_prevent_reactivation_parameter_is_true() { - String key = "CUSTOM_RULE"; - // insert template rule - RuleDto templateRule = createTemplateRule(); - // insert a removed rule - RuleDto rule = RuleTesting.newCustomRule(templateRule) - .setRuleKey(key) - .setStatus(RuleStatus.REMOVED) - .setName("Old name") - .setDescription("Old description") - .setSeverity(Severity.INFO); - dbTester.rules().insert(rule.getDefinition()); - dbTester.rules().insertRuleParam(rule.getDefinition(), param -> param.setDefaultValue("a.*")); - dbSession.commit(); - - // Create custom rule with same key, but with different values - NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey()) - .setName("New name") - .setHtmlDescription("New description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "c.*")) - .setPreventReactivation(true); - - try { - underTest.create(dbSession, newRule); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(ReactivationException.class); - ReactivationException reactivationException = (ReactivationException) e; - assertThat(reactivationException.ruleKey()).isEqualTo(rule.getKey()); - } - } - - @Test - public void fail_to_create_custom_rule_when_invalid_key() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("The rule key \"*INVALID*\" is invalid, it should only contain: a-z, 0-9, \"_\""); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("*INVALID*", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_rule_key_already_exists() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - // Create a custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("A rule with the key 'CUSTOM_RULE' already exists"); - - // Create another custom rule having same key - newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My another custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_missing_name() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("The name is missing"); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_missing_description() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("The description is missing"); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_missing_severity() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("The severity is missing"); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_invalid_severity() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Severity \"INVALID\" is invalid"); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity("INVALID") - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_missing_status() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("The status is missing"); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_wrong_rule_template() { - // insert rule - RuleDefinitionDto rule = newRule(RuleKey.of("java", "S001")).setIsTemplate(false); - dbTester.rules().insert(rule); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("This rule is not a template rule: java:S001"); - - // Create custom rule with unknown template rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey()) - .setName("My custom") - .setHtmlDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - } - - @Test - public void fail_to_create_custom_rule_when_unknown_template() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The template key doesn't exist: java:S001"); - - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", RuleKey.of("java", "S001")) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - underTest.create(dbSession, newRule); - } - - private RuleDto createTemplateRule() { - RuleDto templateRule = RuleTesting.newDto(RuleKey.of("java", "S001"), dbTester.getDefaultOrganization()) - .setIsTemplate(true) - .setLanguage("java") - .setPluginKey("sonarjava") - .setConfigKey("S001") - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1h") - .setDefRemediationBaseEffort("5min") - .setGapDescription("desc") - .setTags(Sets.newHashSet("usertag1", "usertag2")) - .setSystemTags(Sets.newHashSet("tag1", "tag4")) - .setSecurityStandards(Sets.newHashSet("owaspTop10:a1", "cwe:123")) - .setCreatedAt(new Date().getTime()) - .setUpdatedAt(new Date().getTime()); - dbTester.rules().insert(templateRule.getDefinition()); - dbTester.rules().insertOrUpdateMetadata(templateRule.getMetadata().setRuleId(templateRule.getId())); - dbTester.rules().insertRuleParam(templateRule.getDefinition(), param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*")); - ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getDefinition().getId()); - return templateRule; - } - - private RuleDefinitionDto createTemplateRuleWithIntArrayParam() { - RuleDefinitionDto templateRule = newRule(RuleKey.of("java", "S002")) - .setIsTemplate(true) - .setLanguage("java") - .setConfigKey("S002") - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1h") - .setDefRemediationBaseEffort("5min") - .setGapDescription("desc") - .setCreatedAt(new Date().getTime()) - .setUpdatedAt(new Date().getTime()); - dbTester.rules().insert(templateRule); - dbTester.rules().insertRuleParam(templateRule, - param -> param.setName("myIntegers").setType("INTEGER,multiple=true,values=1;2;3").setDescription("My Integers").setDefaultValue("1")); - ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getId()); - return templateRule; - } - - private RuleDefinitionDto createTemplateRuleWithTwoIntParams() { - RuleDefinitionDto templateRule = newRule(RuleKey.of("java", "S003")) - .setIsTemplate(true) - .setLanguage("java") - .setConfigKey("S003") - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1h") - .setDefRemediationBaseEffort("5min") - .setGapDescription("desc") - .setCreatedAt(new Date().getTime()) - .setUpdatedAt(new Date().getTime()); - dbTester.rules().insert(templateRule); - dbTester.rules().insertRuleParam(templateRule, param -> param.setName("first").setType("INTEGER").setDescription("First integer").setDefaultValue("0")); - dbTester.rules().insertRuleParam(templateRule, param -> param.setName("second").setType("INTEGER").setDescription("Second integer").setDefaultValue("0")); - return templateRule; - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleTagHelperTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/RuleTagHelperTest.java deleted file mode 100644 index 90d821e024f..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleTagHelperTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.collect.Sets; -import org.junit.Test; -import org.sonar.db.rule.RuleDto; - -import java.util.Collections; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -public class RuleTagHelperTest { - - @Test - public void applyTags() { - RuleDto rule = new RuleDto().setTags(Sets.newHashSet("performance")); - boolean changed = RuleTagHelper.applyTags(rule, Sets.newHashSet("java8", "security")); - assertThat(rule.getTags()).containsOnly("java8", "security"); - assertThat(changed).isTrue(); - } - - @Test - public void applyTags_remove_all_existing_tags() { - RuleDto rule = new RuleDto().setTags(Sets.newHashSet("performance")); - boolean changed = RuleTagHelper.applyTags(rule, Collections.emptySet()); - assertThat(rule.getTags()).isEmpty(); - assertThat(changed).isTrue(); - } - - @Test - public void applyTags_no_changes() { - RuleDto rule = new RuleDto().setTags(Sets.newHashSet("performance")); - boolean changed = RuleTagHelper.applyTags(rule, Sets.newHashSet("performance")); - assertThat(rule.getTags()).containsOnly("performance"); - assertThat(changed).isFalse(); - } - - @Test - public void applyTags_validate_format() { - RuleDto rule = new RuleDto(); - boolean changed = RuleTagHelper.applyTags(rule, Sets.newHashSet("java8", "security")); - assertThat(rule.getTags()).containsOnly("java8", "security"); - assertThat(changed).isTrue(); - - try { - RuleTagHelper.applyTags(rule, Sets.newHashSet("Java Eight")); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage()).startsWith("Tag 'Java Eight' is invalid"); - } - } - - @Test - public void applyTags_do_not_duplicate_system_tags() { - RuleDto rule = new RuleDto() - .setTags(Sets.newHashSet("performance")) - .setSystemTags(Sets.newHashSet("security")); - - boolean changed = RuleTagHelper.applyTags(rule, Sets.newHashSet("java8", "security")); - - assertThat(changed).isTrue(); - assertThat(rule.getTags()).containsOnly("java8"); - assertThat(rule.getSystemTags()).containsOnly("security"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java deleted file mode 100644 index 7869b26b16a..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.rule; - -import com.google.common.base.Function; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.RuleStatus; -import org.sonar.api.rule.Severity; -import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleKey; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.rule.RuleParamDto; -import org.sonar.db.rule.RuleTesting; -import org.sonar.db.user.UserDto; -import org.sonar.server.es.EsTester; -import org.sonar.server.es.SearchOptions; -import org.sonar.server.qualityprofile.QProfileTesting; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.rule.index.RuleQuery; -import org.sonar.server.tester.UserSessionRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.sonar.api.rule.Severity.CRITICAL; -import static org.sonar.db.rule.RuleTesting.newRule; -import static org.sonar.server.rule.RuleUpdate.createForCustomRule; -import static org.sonar.server.rule.RuleUpdate.createForPluginRule; - -public class RuleUpdaterTest { - - static final RuleKey RULE_KEY = RuleKey.of("squid", "S001"); - - private System2 system2 = mock(System2.class); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone(); - - @Rule - public DbTester db = DbTester.create(system2); - - @Rule - public EsTester es = EsTester.create(); - - private RuleIndex ruleIndex = new RuleIndex(es.client(), system2); - private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); - private DbSession dbSession = db.getSession(); - - private RuleUpdater underTest = new RuleUpdater(db.getDbClient(), ruleIndexer, system2); - - @Test - public void do_not_update_rule_with_removed_status() { - db.rules().insert(newRule(RULE_KEY).setStatus(RuleStatus.REMOVED)); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setTags(Sets.newHashSet("java9")) - .setOrganization(db.getDefaultOrganization()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Rule with REMOVED status cannot be updated: squid:S001"); - - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - } - - @Test - public void no_changes() { - RuleDto ruleDto = RuleTesting.newDto(RULE_KEY, db.getDefaultOrganization()) - // the following fields are not supposed to be updated - .setNoteData("my *note*") - .setNoteUserUuid("me") - .setTags(ImmutableSet.of("tag1")) - .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()) - .setRemediationGapMultiplier("1d") - .setRemediationBaseEffort("5min"); - db.rules().insert(ruleDto.getDefinition()); - db.rules().insertOrUpdateMetadata(ruleDto.getMetadata().setRuleId(ruleDto.getId())); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY); - assertThat(update.isEmpty()).isTrue(); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - dbSession.clearCache(); - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getNoteData()).isEqualTo("my *note*"); - assertThat(rule.getNoteUserUuid()).isEqualTo("me"); - assertThat(rule.getTags()).containsOnly("tag1"); - assertThat(rule.getRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()); - assertThat(rule.getRemediationGapMultiplier()).isEqualTo("1d"); - assertThat(rule.getRemediationBaseEffort()).isEqualTo("5min"); - } - - @Test - public void set_markdown_note() { - UserDto user = db.users().insertUser(); - userSessionRule.logIn(user); - - RuleDto ruleDto = RuleTesting.newDto(RULE_KEY, db.getDefaultOrganization()) - .setNoteData(null) - .setNoteUserUuid(null) - - // the following fields are not supposed to be updated - .setTags(ImmutableSet.of("tag1")) - .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()) - .setRemediationGapMultiplier("1d") - .setRemediationBaseEffort("5min"); - db.rules().insert(ruleDto.getDefinition()); - db.rules().insertOrUpdateMetadata(ruleDto.getMetadata().setRuleId(ruleDto.getId())); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setMarkdownNote("my *note*") - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - dbSession.clearCache(); - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getNoteData()).isEqualTo("my *note*"); - assertThat(rule.getNoteUserUuid()).isEqualTo(user.getUuid()); - assertThat(rule.getNoteCreatedAt()).isNotNull(); - assertThat(rule.getNoteUpdatedAt()).isNotNull(); - // no other changes - assertThat(rule.getTags()).containsOnly("tag1"); - assertThat(rule.getRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()); - assertThat(rule.getRemediationGapMultiplier()).isEqualTo("1d"); - assertThat(rule.getRemediationBaseEffort()).isEqualTo("5min"); - } - - @Test - public void remove_markdown_note() { - RuleDto ruleDto = RuleTesting.newDto(RULE_KEY, db.getDefaultOrganization()) - .setNoteData("my *note*") - .setNoteUserUuid("me"); - db.rules().insert(ruleDto.getDefinition()); - db.rules().insertOrUpdateMetadata(ruleDto.getMetadata().setRuleId(ruleDto.getId())); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setMarkdownNote(null) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - dbSession.clearCache(); - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getNoteData()).isNull(); - assertThat(rule.getNoteUserUuid()).isNull(); - assertThat(rule.getNoteCreatedAt()).isNull(); - assertThat(rule.getNoteUpdatedAt()).isNull(); - } - - @Test - public void set_tags() { - // insert db - db.rules().insert(RuleTesting.newDto(RULE_KEY, db.getDefaultOrganization()) - .setTags(Sets.newHashSet("security")) - .setSystemTags(Sets.newHashSet("java8", "javadoc")).getDefinition()); - dbSession.commit(); - - // java8 is a system tag -> ignore - RuleUpdate update = createForPluginRule(RULE_KEY) - .setTags(Sets.newHashSet("bug", "java8")) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getTags()).containsOnly("bug"); - assertThat(rule.getSystemTags()).containsOnly("java8", "javadoc"); - - // verify that tags are indexed in index - List<String> tags = ruleIndex.listTags(db.getDefaultOrganization(), null, 10); - assertThat(tags).containsExactly("bug", "java8", "javadoc"); - } - - @Test - public void remove_tags() { - RuleDto ruleDto = RuleTesting.newDto(RULE_KEY, db.getDefaultOrganization()) - .setTags(Sets.newHashSet("security")) - .setSystemTags(Sets.newHashSet("java8", "javadoc")); - db.rules().insert(ruleDto.getDefinition()); - db.rules().insertOrUpdateMetadata(ruleDto.getMetadata()); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setTags(null) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - dbSession.clearCache(); - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getTags()).isEmpty(); - assertThat(rule.getSystemTags()).containsOnly("java8", "javadoc"); - - // verify that tags are indexed in index - List<String> tags = ruleIndex.listTags(db.getDefaultOrganization(), null, 10); - assertThat(tags).containsExactly("java8", "javadoc"); - } - - @Test - public void override_debt() { - db.rules().insert(newRule(RULE_KEY) - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1d") - .setDefRemediationBaseEffort("5min")); - dbSession.commit(); - - DefaultDebtRemediationFunction fn = new DefaultDebtRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE, null, "1min"); - RuleUpdate update = createForPluginRule(RULE_KEY) - .setDebtRemediationFunction(fn) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - dbSession.clearCache(); - - // verify debt is overridden - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()); - assertThat(rule.getRemediationGapMultiplier()).isNull(); - assertThat(rule.getRemediationBaseEffort()).isEqualTo("1min"); - - assertThat(rule.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET.name()); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1d"); - assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); - } - - @Test - public void override_debt_only_offset() { - db.rules().insert(newRule(RULE_KEY) - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR.name()) - .setDefRemediationGapMultiplier("1d") - .setDefRemediationBaseEffort(null)); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setDebtRemediationFunction(new DefaultDebtRemediationFunction(DebtRemediationFunction.Type.LINEAR, "2d", null)) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - dbSession.clearCache(); - - // verify debt is overridden - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR.name()); - assertThat(rule.getRemediationGapMultiplier()).isEqualTo("2d"); - assertThat(rule.getRemediationBaseEffort()).isNull(); - - assertThat(rule.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR.name()); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1d"); - assertThat(rule.getDefRemediationBaseEffort()).isNull(); - } - - @Test - public void override_debt_from_linear_with_offset_to_constant() { - db.rules().insert(newRule(RULE_KEY) - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1d") - .setDefRemediationBaseEffort("5min")); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setDebtRemediationFunction(new DefaultDebtRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE, null, "10min")) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - dbSession.clearCache(); - - // verify debt is overridden - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()); - assertThat(rule.getRemediationGapMultiplier()).isNull(); - assertThat(rule.getRemediationBaseEffort()).isEqualTo("10min"); - - assertThat(rule.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET.name()); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1d"); - assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); - } - - @Test - public void reset_remediation_function() { - RuleDto ruleDto = RuleTesting.newDto(RULE_KEY, db.getDefaultOrganization()) - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR.name()) - .setDefRemediationGapMultiplier("1d") - .setDefRemediationBaseEffort("5min") - .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name()) - .setRemediationGapMultiplier(null) - .setRemediationBaseEffort("1min"); - db.rules().insert(ruleDto.getDefinition()); - db.rules().insertOrUpdateMetadata(ruleDto.getMetadata().setRuleId(ruleDto.getId())); - dbSession.commit(); - - RuleUpdate update = createForPluginRule(RULE_KEY) - .setDebtRemediationFunction(null) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - dbSession.clearCache(); - - // verify debt is coming from default values - RuleDto rule = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), RULE_KEY); - assertThat(rule.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR.name()); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1d"); - assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); - - assertThat(rule.getRemediationFunction()).isNull(); - assertThat(rule.getRemediationGapMultiplier()).isNull(); - assertThat(rule.getRemediationBaseEffort()).isNull(); - } - - @Test - public void update_custom_rule() { - // Create template rule - RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001")); - db.rules().insert(templateRule.getDefinition()); - db.rules().insertRuleParam(templateRule.getDefinition(), param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*")); - db.rules().insertRuleParam(templateRule.getDefinition(), param -> param.setName("format").setType("STRING").setDescription("Format")); - - // Create custom rule - RuleDefinitionDto customRule = RuleTesting.newCustomRule(templateRule) - .setName("Old name") - .setDescription("Old description") - .setSeverity(Severity.MINOR) - .setStatus(RuleStatus.BETA) - .getDefinition(); - db.rules().insert(customRule); - db.rules().insertRuleParam(customRule, param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue("a.*")); - db.rules().insertRuleParam(customRule, param -> param.setName("format").setType("STRING").setDescription("Format").setDefaultValue(null)); - - // Update custom rule - RuleUpdate update = createForCustomRule(customRule.getKey()) - .setName("New name") - .setMarkdownDescription("New description") - .setSeverity("MAJOR") - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "b.*")) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - dbSession.clearCache(); - - // Verify custom rule is updated - RuleDto customRuleReloaded = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, db.getDefaultOrganization(), customRule.getKey()); - assertThat(customRuleReloaded).isNotNull(); - assertThat(customRuleReloaded.getName()).isEqualTo("New name"); - assertThat(customRuleReloaded.getDescription()).isEqualTo("New description"); - assertThat(customRuleReloaded.getSeverityString()).isEqualTo("MAJOR"); - assertThat(customRuleReloaded.getStatus()).isEqualTo(RuleStatus.READY); - - List<RuleParamDto> params = db.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleReloaded.getKey()); - assertThat(params).extracting(RuleParamDto::getDefaultValue).containsOnly("b.*", null); - - // Verify in index - assertThat(ruleIndex.search(new RuleQuery().setQueryText("New name"), new SearchOptions()).getIds()).containsOnly(customRule.getId()); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("New description"), new SearchOptions()).getIds()).containsOnly(customRule.getId()); - - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Old name"), new SearchOptions()).getTotal()).isZero(); - assertThat(ruleIndex.search(new RuleQuery().setQueryText("Old description"), new SearchOptions()).getTotal()).isZero(); - } - - @Test - public void update_custom_rule_with_empty_parameter() { - // Create template rule - RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001")); - db.rules().insert(templateRule.getDefinition()); - db.rules().insertRuleParam(templateRule.getDefinition(), param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(null)); - - // Create custom rule - RuleDefinitionDto customRule = RuleTesting.newCustomRule(templateRule) - .setName("Old name") - .setDescription("Old description") - .setSeverity(Severity.MINOR) - .setStatus(RuleStatus.BETA) - .getDefinition(); - db.rules().insert(customRule); - db.rules().insertRuleParam(customRule, param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(null)); - - dbSession.commit(); - - // Update custom rule without setting a value for the parameter - RuleUpdate update = createForCustomRule(customRule.getKey()) - .setName("New name") - .setMarkdownDescription("New description") - .setSeverity("MAJOR") - .setStatus(RuleStatus.READY) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - dbSession.clearCache(); - - // Verify custom rule is updated - List<RuleParamDto> params = db.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRule.getKey()); - assertThat(params.get(0).getDefaultValue()).isNull(); - } - - @Test - public void update_active_rule_parameters_when_updating_custom_rule() { - // Create template rule with 3 parameters - RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001")).setLanguage("xoo"); - RuleDefinitionDto templateRuleDefinition = templateRule.getDefinition(); - db.rules().insert(templateRuleDefinition); - db.rules().insertRuleParam(templateRuleDefinition, param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*")); - db.rules().insertRuleParam(templateRuleDefinition, param -> param.setName("format").setType("STRING").setDescription("format").setDefaultValue("csv")); - db.rules().insertRuleParam(templateRuleDefinition, param -> param.setName("message").setType("STRING").setDescription("message")); - - // Create custom rule - RuleDefinitionDto customRule = RuleTesting.newCustomRule(templateRule) - .setSeverity(Severity.MAJOR) - .setLanguage("xoo") - .getDefinition(); - db.rules().insert(customRule); - RuleParamDto ruleParam1 = db.rules().insertRuleParam(customRule, param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue("a.*")); - db.rules().insertRuleParam(customRule, param -> param.setName("format").setType("STRING").setDescription("format").setDefaultValue("txt")); - db.rules().insertRuleParam(customRule, param -> param.setName("message").setType("STRING").setDescription("message")); - - // Create a quality profile - QProfileDto profileDto = QProfileTesting.newXooP1(db.getDefaultOrganization()); - db.getDbClient().qualityProfileDao().insert(dbSession, profileDto); - dbSession.commit(); - - // Activate the custom rule - ActiveRuleDto activeRuleDto = new ActiveRuleDto() - .setProfileId(profileDto.getId()) - .setRuleId(customRule.getId()) - .setSeverity(Severity.BLOCKER); - db.getDbClient().activeRuleDao().insert(dbSession, activeRuleDto); - db.getDbClient().activeRuleDao().insertParam(dbSession, activeRuleDto, new ActiveRuleParamDto() - .setActiveRuleId(activeRuleDto.getId()) - .setRulesParameterId(ruleParam1.getId()) - .setKey(ruleParam1.getName()) - .setValue(ruleParam1.getDefaultValue())); - dbSession.commit(); - - // Update custom rule parameter 'regex', add 'message' and remove 'format' - RuleUpdate update = createForCustomRule(customRule.getKey()) - .setParameters(ImmutableMap.of("regex", "b.*", "message", "a message")) - .setOrganization(db.getDefaultOrganization()); - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - - // Verify custom rule parameters has been updated - List<RuleParamDto> params = db.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRule.getKey()); - assertThat(params).hasSize(3); - - Map<String, RuleParamDto> paramsByKey = paramsByKey(params); - assertThat(paramsByKey.get("regex")).isNotNull(); - assertThat(paramsByKey.get("regex").getDefaultValue()).isEqualTo("b.*"); - assertThat(paramsByKey.get("message")).isNotNull(); - assertThat(paramsByKey.get("message").getDefaultValue()).isEqualTo("a message"); - assertThat(paramsByKey.get("format")).isNotNull(); - assertThat(paramsByKey.get("format").getDefaultValue()).isNull(); - - // Verify that severity has not changed - ActiveRuleDto activeRuleReloaded = db.getDbClient().activeRuleDao().selectByKey(dbSession, ActiveRuleKey.of(profileDto, customRule.getKey())).get(); - assertThat(activeRuleReloaded.getSeverityString()).isEqualTo(Severity.BLOCKER); - - // Verify active rule parameters has been updated - List<ActiveRuleParamDto> activeRuleParams = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(dbSession, activeRuleReloaded.getId()); - - assertThat(activeRuleParams).hasSize(2); - Map<String, ActiveRuleParamDto> activeRuleParamsByKey = ActiveRuleParamDto.groupByKey(activeRuleParams); - assertThat(activeRuleParamsByKey.get("regex").getValue()).isEqualTo("b.*"); - assertThat(activeRuleParamsByKey.get("message").getValue()).isEqualTo("a message"); - assertThat(activeRuleParamsByKey.get("format")).isNull(); - } - - @Test - public void fail_to_update_custom_rule_when_empty_name() { - // Create template rule - RuleDefinitionDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001")).getDefinition(); - db.rules().insert(templateRule); - - // Create custom rule - RuleDefinitionDto customRule = RuleTesting.newCustomRule(templateRule); - db.rules().insert(customRule); - - dbSession.commit(); - - // Update custom rule - RuleUpdate update = createForCustomRule(customRule.getKey()) - .setName("") - .setMarkdownDescription("New desc") - .setOrganization(db.getDefaultOrganization()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The name is missing"); - - underTest.update(dbSession, update, db.getDefaultOrganization(), userSessionRule); - } - - @Test - public void fail_to_update_custom_rule_when_empty_description() { - // Create template rule - RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001")); - db.rules().insert(templateRule.getDefinition()); - - // Create custom rule - RuleDto customRule = RuleTesting.newCustomRule(templateRule); - db.rules().insert(customRule.getDefinition()); - - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The description is missing"); - - underTest.update(dbSession, - createForCustomRule(customRule.getKey()).setName("New name").setMarkdownDescription("").setOrganization(db.getDefaultOrganization()), - db.getDefaultOrganization(), userSessionRule); - } - - @Test - public void fail_to_update_plugin_rule_if_name_is_set() { - RuleDefinitionDto ruleDefinition = db.rules().insert(newRule(RuleKey.of("squid", "S01"))); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Not a custom rule"); - - createForPluginRule(ruleDefinition.getKey()).setName("New name"); - } - - @Test - public void fail_to_update_plugin_rule_if_description_is_set() { - RuleDefinitionDto ruleDefinition = db.rules().insert(newRule(RuleKey.of("squid", "S01"))); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Not a custom rule"); - - createForPluginRule(ruleDefinition.getKey()).setMarkdownDescription("New description"); - } - - @Test - public void fail_to_update_plugin_rule_if_severity_is_set() { - RuleDefinitionDto ruleDefinition = db.rules().insert(newRule(RuleKey.of("squid", "S01"))); - dbSession.commit(); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Not a custom rule"); - - createForPluginRule(ruleDefinition.getKey()).setSeverity(CRITICAL); - } - - private static Map<String, RuleParamDto> paramsByKey(List<RuleParamDto> params) { - return FluentIterable.from(params).uniqueIndex(RuleParamToKey.INSTANCE); - } - - private enum RuleParamToKey implements Function<RuleParamDto, String> { - INSTANCE; - - @Override - public String apply(@Nonnull RuleParamDto input) { - return input.getName(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectConfigurationLoaderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectConfigurationLoaderImplTest.java deleted file mode 100644 index 60944a2a608..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectConfigurationLoaderImplTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.settings; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import java.util.Collections; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.config.Configuration; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.property.PropertiesDao; -import org.sonar.db.property.PropertyDto; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class ProjectConfigurationLoaderImplTest { - private DbClient dbClient = mock(DbClient.class); - private DbSession dbSession = mock(DbSession.class); - private PropertiesDao propertiesDao = mock(PropertiesDao.class); - private MapSettings globalSettings = new MapSettings(); - private ProjectConfigurationLoaderImpl underTest = new ProjectConfigurationLoaderImpl(globalSettings, dbClient); - - @Before - public void setUp() throws Exception { - when(dbClient.openSession(anyBoolean())) - .thenThrow(new IllegalStateException("ProjectConfigurationLoaderImpl should not open DB session")); - when(dbClient.propertiesDao()).thenReturn(propertiesDao); - } - - @Test - public void returns_empty_map_when_no_component() { - assertThat(underTest.loadProjectConfigurations(dbSession, Collections.emptySet())) - .isEmpty(); - - verifyZeroInteractions(propertiesDao); - } - - @Test - public void return_configuration_with_just_global_settings_when_no_component_settings() { - String key = randomAlphanumeric(3); - String value = randomAlphanumeric(4); - String componentDbKey = randomAlphanumeric(5); - String componentUuid = randomAlphanumeric(6); - globalSettings.setProperty(key, value); - when(propertiesDao.selectProjectProperties(dbSession, componentDbKey)) - .thenReturn(emptyList()); - ComponentDto component = newComponentDto(componentDbKey, componentUuid); - - Map<String, Configuration> configurations = underTest.loadProjectConfigurations(dbSession, singleton(component)); - - assertThat(configurations) - .containsOnlyKeys(componentUuid); - assertThat(configurations.get(componentUuid).get(key)).contains(value); - } - - @Test - public void return_configuration_with_global_settings_and_component_settings() { - String globalKey = randomAlphanumeric(3); - String globalValue = randomAlphanumeric(4); - String componentDbKey = randomAlphanumeric(5); - String componentUuid = randomAlphanumeric(6); - String projectPropKey1 = randomAlphanumeric(7); - String projectPropValue1 = randomAlphanumeric(8); - String projectPropKey2 = randomAlphanumeric(9); - String projectPropValue2 = randomAlphanumeric(10); - globalSettings.setProperty(globalKey, globalValue); - when(propertiesDao.selectProjectProperties(dbSession, componentDbKey)) - .thenReturn(ImmutableList.of(newPropertyDto(projectPropKey1, projectPropValue1), newPropertyDto(projectPropKey2, projectPropValue2))); - ComponentDto component = newComponentDto(componentDbKey, componentUuid); - - Map<String, Configuration> configurations = underTest.loadProjectConfigurations(dbSession, singleton(component)); - - assertThat(configurations) - .containsOnlyKeys(componentUuid); - assertThat(configurations.get(componentUuid).get(globalKey)).contains(globalValue); - assertThat(configurations.get(componentUuid).get(projectPropKey1)).contains(projectPropValue1); - assertThat(configurations.get(componentUuid).get(projectPropKey2)).contains(projectPropValue2); - } - - @Test - public void return_configuration_with_global_settings_main_branch_settings_and_branch_settings() { - String globalKey = randomAlphanumeric(3); - String globalValue = randomAlphanumeric(4); - String mainBranchDbKey = randomAlphanumeric(5); - String branchDbKey = mainBranchDbKey + ComponentDto.BRANCH_KEY_SEPARATOR + randomAlphabetic(5); - String branchUuid = randomAlphanumeric(6); - String mainBranchPropKey = randomAlphanumeric(7); - String mainBranchPropValue = randomAlphanumeric(8); - String branchPropKey = randomAlphanumeric(9); - String branchPropValue = randomAlphanumeric(10); - globalSettings.setProperty(globalKey, globalValue); - when(propertiesDao.selectProjectProperties(dbSession, mainBranchDbKey)) - .thenReturn(ImmutableList.of(newPropertyDto(mainBranchPropKey, mainBranchPropValue))); - when(propertiesDao.selectProjectProperties(dbSession, branchDbKey)) - .thenReturn(ImmutableList.of(newPropertyDto(branchPropKey, branchPropValue))); - ComponentDto component = newComponentDto(branchDbKey, branchUuid); - - Map<String, Configuration> configurations = underTest.loadProjectConfigurations(dbSession, singleton(component)); - - assertThat(configurations) - .containsOnlyKeys(branchUuid); - assertThat(configurations.get(branchUuid).get(globalKey)).contains(globalValue); - assertThat(configurations.get(branchUuid).get(mainBranchPropKey)).contains(mainBranchPropValue); - assertThat(configurations.get(branchUuid).get(branchPropKey)).contains(branchPropValue); - } - - @Test - public void loads_configuration_of_any_given_component_only_once() { - String mainBranch1DbKey = randomAlphanumeric(4); - String mainBranch1Uuid = randomAlphanumeric(5); - String branch1DbKey = mainBranch1DbKey + ComponentDto.BRANCH_KEY_SEPARATOR + randomAlphabetic(5); - String branch1Uuid = randomAlphanumeric(6); - String branch2DbKey = mainBranch1DbKey + ComponentDto.BRANCH_KEY_SEPARATOR + randomAlphabetic(7); - String branch2Uuid = randomAlphanumeric(8); - String mainBranch2DbKey = randomAlphanumeric(14); - String mainBranch2Uuid = randomAlphanumeric(15); - String branch3DbKey = mainBranch2DbKey + ComponentDto.BRANCH_KEY_SEPARATOR + randomAlphabetic(5); - String branch3Uuid = randomAlphanumeric(16); - - ComponentDto mainBranch1 = newComponentDto(mainBranch1DbKey, mainBranch1Uuid); - ComponentDto branch1 = newComponentDto(branch1DbKey, branch1Uuid); - ComponentDto branch2 = newComponentDto(branch2DbKey, branch2Uuid); - ComponentDto mainBranch2 = newComponentDto(mainBranch2DbKey, mainBranch2Uuid); - ComponentDto branch3 = newComponentDto(branch3DbKey, branch3Uuid); - - underTest.loadProjectConfigurations(dbSession, ImmutableSet.of(mainBranch1, mainBranch2, branch1, branch2, branch3)); - - verify(propertiesDao, times(1)).selectProjectProperties(dbSession, mainBranch1DbKey); - verify(propertiesDao, times(1)).selectProjectProperties(dbSession, mainBranch2DbKey); - verify(propertiesDao, times(1)).selectProjectProperties(dbSession, branch1DbKey); - verify(propertiesDao, times(1)).selectProjectProperties(dbSession, branch2DbKey); - verify(propertiesDao, times(1)).selectProjectProperties(dbSession, branch3DbKey); - verifyNoMoreInteractions(propertiesDao); - } - - private ComponentDto newComponentDto(String componentDbKey, String componentUuid) { - return new ComponentDto().setDbKey(componentDbKey).setUuid(componentUuid); - } - - private PropertyDto newPropertyDto(String projectKey1, String projectValue1) { - return new PropertyDto() - .setKey(projectKey1) - .setValue(projectValue1); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/TestProjectConfigurationLoader.java b/server/sonar-server/src/test/java/org/sonar/server/settings/TestProjectConfigurationLoader.java deleted file mode 100644 index 36820604f60..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/settings/TestProjectConfigurationLoader.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.settings; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import org.sonar.api.config.Configuration; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; - -public class TestProjectConfigurationLoader implements ProjectConfigurationLoader { - - private final Configuration config; - - public TestProjectConfigurationLoader(Configuration config) { - this.config = config; - } - - @Override - public Map<String, Configuration> loadProjectConfigurations(DbSession dbSession, Set<ComponentDto> projects) { - Map<String, Configuration> map = new HashMap<>(); - for (ComponentDto project : projects) { - map.put(project.uuid(), config); - } - return map; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/DecorationDataHolderTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/DecorationDataHolderTest.java deleted file mode 100644 index dbc493dafd2..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/DecorationDataHolderTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import org.junit.Before; -import org.junit.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class DecorationDataHolderTest { - - private static final String SAMPLE_SYNTAX_HIGHLIGHTING_RULES = "0,8,k;0,52,cppd;54,67,a;69,75,k;106,130,cppd;114,130,k;"; - private static final String SAMPLE_SYMBOLS_REFERENCES = "80,85,80,90,140;"; - - private DecorationDataHolder decorationDataHolder; - - @Before - public void setUpHighlightingContext() { - decorationDataHolder = new DecorationDataHolder(); - decorationDataHolder.loadSyntaxHighlightingData(SAMPLE_SYNTAX_HIGHLIGHTING_RULES); - decorationDataHolder.loadSymbolReferences(SAMPLE_SYMBOLS_REFERENCES); - } - - @Test - public void should_extract_lower_bounds_from_serialized_rules() { - - List<OpeningHtmlTag> openingTagsEntries = decorationDataHolder.getOpeningTagsEntries(); - - assertThat(openingTagsEntries.get(0)).isEqualTo(new OpeningHtmlTag(0, "k")); - assertThat(openingTagsEntries.get(1)).isEqualTo(new OpeningHtmlTag(0, "cppd")); - assertThat(openingTagsEntries.get(2)).isEqualTo(new OpeningHtmlTag(54, "a")); - assertThat(openingTagsEntries.get(3)).isEqualTo(new OpeningHtmlTag(69, "k")); - assertThat(openingTagsEntries.get(4)).isEqualTo(new OpeningHtmlTag(80, "sym-80 sym")); - assertThat(openingTagsEntries.get(5)).isEqualTo(new OpeningHtmlTag(90, "sym-80 sym")); - assertThat(openingTagsEntries.get(6)).isEqualTo(new OpeningHtmlTag(106, "cppd")); - assertThat(openingTagsEntries.get(7)).isEqualTo(new OpeningHtmlTag(114, "k")); - assertThat(openingTagsEntries.get(8)).isEqualTo(new OpeningHtmlTag(140, "sym-80 sym")); - } - - @Test - public void should_extract_upper_bounds_from_serialized_rules() { - - List<Integer> offsets = decorationDataHolder.getClosingTagsOffsets(); - - assertThat(offsets.get(0)).isEqualTo(8); - assertThat(offsets.get(1)).isEqualTo(52); - assertThat(offsets.get(2)).isEqualTo(67); - assertThat(offsets.get(3)).isEqualTo(75); - assertThat(offsets.get(4)).isEqualTo(85); - assertThat(offsets.get(5)).isEqualTo(95); - assertThat(offsets.get(6)).isEqualTo(130); - assertThat(offsets.get(7)).isEqualTo(130); - assertThat(offsets.get(8)).isEqualTo(145); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/HtmlSourceDecoratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/HtmlSourceDecoratorTest.java deleted file mode 100644 index ec38ac559e7..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/HtmlSourceDecoratorTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import org.junit.Before; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class HtmlSourceDecoratorTest { - - HtmlSourceDecorator sourceDecorator; - - @Before - public void setUpDatasets() { - sourceDecorator = new HtmlSourceDecorator(); - } - - @Test - public void should_decorate_single_line() { - String sourceLine = "package org.polop;"; - String highlighting = "0,7,k"; - String symbols = "8,17,42"; - assertThat(sourceDecorator.getDecoratedSourceAsHtml(sourceLine, highlighting, symbols)).isEqualTo( - "<span class=\"k\">package</span> <span class=\"sym-42 sym\">org.polop</span>;"); - } - - @Test - public void should_handle_highlighting_too_long() { - String sourceLine = "abc"; - String highlighting = "0,5,c"; - String symbols = ""; - assertThat(sourceDecorator.getDecoratedSourceAsHtml(sourceLine, highlighting, symbols)).isEqualTo("<span class=\"c\">abc</span>"); - } - - @Test - public void should_ignore_missing_highlighting() { - String sourceLine = " if (toto < 42) {"; - assertThat(sourceDecorator.getDecoratedSourceAsHtml(sourceLine, null, null)).isEqualTo(" if (toto < 42) {"); - assertThat(sourceDecorator.getDecoratedSourceAsHtml(sourceLine, "", null)).isEqualTo(" if (toto < 42) {"); - } - - @Test - public void should_ignore_null_source() { - assertThat(sourceDecorator.getDecoratedSourceAsHtml(null, null, null)).isNull(); - } - - @Test - public void should_ignore_empty_source() { - assertThat(sourceDecorator.getDecoratedSourceAsHtml("", "0,1,cppd", "")).isEqualTo(""); - } - - @Test - public void should_ignore_empty_rule() { - String sourceLine = "@Deprecated"; - String highlighting = "0,0,a;0,11,a"; - String symbols = "1,11,1"; - assertThat(sourceDecorator.getDecoratedSourceAsHtml(sourceLine, highlighting, symbols)).isEqualTo("<span class=\"a\">@<span class=\"sym-1 sym\">Deprecated</span></span>"); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/HtmlTextDecoratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/HtmlTextDecoratorTest.java deleted file mode 100644 index 6494abc5897..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/HtmlTextDecoratorTest.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import org.junit.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.source.HtmlTextDecorator.CR_END_OF_LINE; -import static org.sonar.server.source.HtmlTextDecorator.LF_END_OF_LINE; - -public class HtmlTextDecoratorTest { - - @Test - public void should_decorate_simple_character_range() { - - String packageDeclaration = "package org.sonar.core.source;"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,7,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(packageDeclaration, decorationData); - - assertThat(htmlOutput).containsOnly("<span class=\"k\">package</span> org.sonar.core.source;"); - } - - @Test - public void should_decorate_multiple_lines_characters_range() { - - String firstCommentLine = "/*"; - String secondCommentLine = " * Test"; - String thirdCommentLine = " */"; - - String blockComment = firstCommentLine + LF_END_OF_LINE - + secondCommentLine + LF_END_OF_LINE - + thirdCommentLine + LF_END_OF_LINE; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,14,cppd;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(blockComment, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">" + firstCommentLine + "</span>", - "<span class=\"cppd\">" + secondCommentLine + "</span>", - "<span class=\"cppd\">" + thirdCommentLine + "</span>", - "" - ); - } - - @Test - public void should_highlight_multiple_words_in_one_line() { - - String classDeclaration = "public class MyClass implements MyInterface {"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,6,k;7,12,k;21,31,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(classDeclaration, decorationData); - - assertThat(htmlOutput).containsOnly( - "<span class=\"k\">public</span> " + - "<span class=\"k\">class</span> MyClass " + - "<span class=\"k\">implements</span> MyInterface {"); - } - - @Test - public void should_allow_multiple_levels_highlighting() { - - String javaDocSample = - "/**" + LF_END_OF_LINE + - " * Creates a FormulaDecorator" + LF_END_OF_LINE + - " *" + LF_END_OF_LINE + - " * @param metric the metric should have an associated formula" + LF_END_OF_LINE + - " * " + LF_END_OF_LINE + - " * @throws IllegalArgumentException if no formula is associated to the metric" + LF_END_OF_LINE + - " */" + LF_END_OF_LINE; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,184,cppd;47,53,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(javaDocSample, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/**</span>", - "<span class=\"cppd\"> * Creates a FormulaDecorator</span>", - "<span class=\"cppd\"> *</span>", - "<span class=\"cppd\"> * @param <span class=\"k\">metric</span> the metric should have an associated formula</span>", - "<span class=\"cppd\"> * </span>", - "<span class=\"cppd\"> * @throws IllegalArgumentException if no formula is associated to the metric</span>", - "<span class=\"cppd\"> */</span>", - "" - ); - } - - @Test - public void should_support_crlf_line_breaks() { - - String crlfCodeSample = - "/**" + CR_END_OF_LINE + LF_END_OF_LINE + - "* @return metric generated by the decorator" + CR_END_OF_LINE + LF_END_OF_LINE + - "*/" + CR_END_OF_LINE + LF_END_OF_LINE + - "@DependedUpon" + CR_END_OF_LINE + LF_END_OF_LINE + - "public Metric generatesMetric() {" + CR_END_OF_LINE + LF_END_OF_LINE + - " return metric;" + CR_END_OF_LINE + LF_END_OF_LINE + - "}" + CR_END_OF_LINE + LF_END_OF_LINE; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,52,cppd;54,67,a;69,75,k;106,112,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(crlfCodeSample, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/**</span>", - "<span class=\"cppd\">* @return metric generated by the decorator</span>", - "<span class=\"cppd\">*/</span>", - "<span class=\"a\">@DependedUpon</span>", - "<span class=\"k\">public</span> Metric generatesMetric() {", - " <span class=\"k\">return</span> metric;", - "}", - "" - ); - } - - @Test - public void should_close_tags_at_end_of_file() { - - String classDeclarationSample = - "/*" + LF_END_OF_LINE + - " * Header" + LF_END_OF_LINE + - " */" + LF_END_OF_LINE + - LF_END_OF_LINE + - "public class HelloWorld {" + LF_END_OF_LINE + - "}"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,16,cppd;18,25,k;25,31,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(classDeclarationSample, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/*</span>", - "<span class=\"cppd\"> * Header</span>", - "<span class=\"cppd\"> */</span>", - "", - "<span class=\"k\">public </span><span class=\"k\">class </span>HelloWorld {", - "}" - ); - } - - @Test - public void should_escape_markup_chars() { - - String javadocWithHtml = - "/**\n" + - " * Provides a basic framework to sequentially read any kind of character stream in order to feed a generic OUTPUT.\n" + - " * \n" + - " * This framework can used for instance in order to :\n" + - " * <ul>\n" + - " * <li>Create a lexer in charge to generate a list of tokens from a character stream</li>\n" + - " * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li>\n" + - " * <li>Create a javadoc generator</li>\n" + - " * <li>...</li>\n" + - " * </ul>\n" + - " */\n"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,453,cppd;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(javadocWithHtml, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/**</span>", - "<span class=\"cppd\"> * Provides a basic framework to sequentially read any kind of character stream in order to feed a generic OUTPUT.</span>", - "<span class=\"cppd\"> * </span>", - "<span class=\"cppd\"> * This framework can used for instance in order to :</span>", - "<span class=\"cppd\"> * <ul></span>", - "<span class=\"cppd\"> * <li>Create a lexer in charge to generate a list of tokens from a character stream</li></span>", - "<span class=\"cppd\"> * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li></span>", - "<span class=\"cppd\"> * <li>Create a javadoc generator</li></span>", - "<span class=\"cppd\"> * <li>...</li></span>", - "<span class=\"cppd\"> * </ul></span>", - "<span class=\"cppd\"> */</span>", - ""); - } - - @Test - public void should_escape_ampersand_char() { - - String javadocWithAmpersandChar = - "/**\n" + - " * Definition of a dashboard.\n" + - " * <p/>\n" + - " * Its name and description can be retrieved using the i18n mechanism, using the keys \"dashboard.<id>.name\" and\n" + - " * \"dashboard.<id>.description\".\n" + - " *\n" + - " * @since 2.13\n" + - " */\n"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,220,cppd;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(javadocWithAmpersandChar, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/**</span>", - "<span class=\"cppd\"> * Definition of a dashboard.</span>", - "<span class=\"cppd\"> * <p/></span>", - "<span class=\"cppd\"> * Its name and description can be retrieved using the i18n mechanism, using the keys \"dashboard.&lt;id&gt;.name\" and</span>", - "<span class=\"cppd\"> * \"dashboard.&lt;id&gt;.description\".</span>", - "<span class=\"cppd\"> *</span>", - "<span class=\"cppd\"> * @since 2.13</span>", - "<span class=\"cppd\"> */</span>", - ""); - } - - @Test - public void should_support_cr_line_breaks() { - - String crCodeSample = - "/**" + CR_END_OF_LINE + - "* @return metric generated by the decorator" + CR_END_OF_LINE + - "*/" + CR_END_OF_LINE + - "@DependedUpon" + CR_END_OF_LINE + - "public Metric generatesMetric() {" + CR_END_OF_LINE + - " return metric;" + CR_END_OF_LINE + - "}" + CR_END_OF_LINE; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,50,cppd;51,64,a;65,71,k;101,107,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(crCodeSample, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/**</span>", - "<span class=\"cppd\">* @return metric generated by the decorator</span>", - "<span class=\"cppd\">*/</span>", - "<span class=\"a\">@DependedUpon</span>", - "<span class=\"k\">public</span> Metric generatesMetric() {", - " <span class=\"k\">return</span> metric;", - "}", - "" - ); - - } - - @Test - public void should_support_multiple_empty_lines_at_end_of_file() { - - String classDeclarationSample = - "/*" + LF_END_OF_LINE + - " * Header" + LF_END_OF_LINE + - " */" + LF_END_OF_LINE + - LF_END_OF_LINE + - "public class HelloWorld {" + LF_END_OF_LINE + - "}" + LF_END_OF_LINE + LF_END_OF_LINE + LF_END_OF_LINE; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,16,cppd;18,25,k;25,31,k;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(classDeclarationSample, decorationData); - - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/*</span>", - "<span class=\"cppd\"> * Header</span>", - "<span class=\"cppd\"> */</span>", - "", - "<span class=\"k\">public </span><span class=\"k\">class </span>HelloWorld {", - "}", - "", - "", - "" - ); - } - - @Test - public void returned_code_begin_from_given_param() { - - String javadocWithHtml = - "/**\n" + - " * Provides a basic framework to sequentially read any kind of character stream in order to feed a generic OUTPUT.\n" + - " * \n" + - " * This framework can used for instance in order to :\n" + - " * <ul>\n" + - " * <li>Create a lexer in charge to generate a list of tokens from a character stream</li>\n" + - " * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li>\n" + - " * <li>Create a javadoc generator</li>\n" + - " * <li>...</li>\n" + - " * </ul>\n" + - " */\n"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,453,cppd;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(javadocWithHtml, decorationData, 4, null); - assertThat(htmlOutput).hasSize(9); - - // Begin from line 4 - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\"> * This framework can used for instance in order to :</span>", - "<span class=\"cppd\"> * <ul></span>", - "<span class=\"cppd\"> * <li>Create a lexer in charge to generate a list of tokens from a character stream</li></span>", - "<span class=\"cppd\"> * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li></span>", - "<span class=\"cppd\"> * <li>Create a javadoc generator</li></span>", - "<span class=\"cppd\"> * <li>...</li></span>", - "<span class=\"cppd\"> * </ul></span>", - "<span class=\"cppd\"> */</span>", - ""); - } - - @Test - public void returned_code_end_to_given_param() { - - String javadocWithHtml = - "/**\n" + - " * Provides a basic framework to sequentially read any kind of character stream in order to feed a generic OUTPUT.\n" + - " * \n" + - " * This framework can used for instance in order to :\n" + - " * <ul>\n" + - " * <li>Create a lexer in charge to generate a list of tokens from a character stream</li>\n" + - " * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li>\n" + - " * <li>Create a javadoc generator</li>\n" + - " * <li>...</li>\n" + - " * </ul>\n" + - " */\n"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,453,cppd;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(javadocWithHtml, decorationData, null, 4); - assertThat(htmlOutput).hasSize(4); - - // End at line 4 - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\">/**</span>", - "<span class=\"cppd\"> * Provides a basic framework to sequentially read any kind of character stream in order to feed a generic OUTPUT.</span>", - "<span class=\"cppd\"> * </span>", - "<span class=\"cppd\"> * This framework can used for instance in order to :</span>"); - } - - @Test - public void returned_code_is_between_from_and_to_params() { - - String javadocWithHtml = - "/**\n" + - " * Provides a basic framework to sequentially read any kind of character stream in order to feed a generic OUTPUT.\n" + - " * \n" + - " * This framework can used for instance in order to :\n" + - " * <ul>\n" + - " * <li>Create a lexer in charge to generate a list of tokens from a character stream</li>\n" + - " * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li>\n" + - " * <li>Create a javadoc generator</li>\n" + - " * <li>...</li>\n" + - " * </ul>\n" + - " */\n"; - - DecorationDataHolder decorationData = new DecorationDataHolder(); - decorationData.loadSyntaxHighlightingData("0,453,cppd;"); - - HtmlTextDecorator htmlTextDecorator = new HtmlTextDecorator(); - List<String> htmlOutput = htmlTextDecorator.decorateTextWithHtml(javadocWithHtml, decorationData, 4, 8); - assertThat(htmlOutput).hasSize(5); - - // Begin from line 4 and finish at line 8 - assertThat(htmlOutput).containsExactly( - "<span class=\"cppd\"> * This framework can used for instance in order to :</span>", - "<span class=\"cppd\"> * <ul></span>", - "<span class=\"cppd\"> * <li>Create a lexer in charge to generate a list of tokens from a character stream</li></span>", - "<span class=\"cppd\"> * <li>Create a source code syntax highligther in charge to decorate a source code with HTML tags</li></span>", - "<span class=\"cppd\"> * <li>Create a javadoc generator</li></span>" - ); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/OpeningHtmlTagTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/OpeningHtmlTagTest.java deleted file mode 100644 index ece48829aa9..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/OpeningHtmlTagTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class OpeningHtmlTagTest { - - @Test - public void test_getters() { - OpeningHtmlTag openingHtmlTag = new OpeningHtmlTag(3, "tag"); - assertThat(openingHtmlTag.getStartOffset()).isEqualTo(3); - assertThat(openingHtmlTag.getCssClass()).isEqualTo("tag"); - } - - @Test - public void test_equals() { - OpeningHtmlTag openingHtmlTag = new OpeningHtmlTag(3, "tag"); - OpeningHtmlTag openingHtmlTagWithSameValues = new OpeningHtmlTag(3, "tag"); - OpeningHtmlTag openingHtmlTagWithDifferentValues = new OpeningHtmlTag(5, "tag2"); - OpeningHtmlTag openingHtmlTagWithNoCssClass = new OpeningHtmlTag(3, null); - - assertThat(openingHtmlTag).isEqualTo(openingHtmlTagWithSameValues); - assertThat(openingHtmlTag).isEqualTo(openingHtmlTag); - assertThat(openingHtmlTag).isNotEqualTo(openingHtmlTagWithDifferentValues); - assertThat(openingHtmlTag).isNotEqualTo(openingHtmlTagWithNoCssClass); - assertThat(openingHtmlTag).isNotEqualTo(new OpeningHtmlTag(3, "tag"){}); - } - - @Test - public void test_hashcode() { - OpeningHtmlTag openingHtmlTag = new OpeningHtmlTag(3, "tag"); - OpeningHtmlTag openingHtmlTagWithSameValues = new OpeningHtmlTag(3, "tag"); - OpeningHtmlTag openingHtmlTagWithDifferentValue = new OpeningHtmlTag(5, "tag2"); - - assertThat(openingHtmlTag.hashCode()).isEqualTo(openingHtmlTagWithSameValues.hashCode()); - assertThat(openingHtmlTag.hashCode()).isEqualTo(openingHtmlTag.hashCode()); - assertThat(openingHtmlTag.hashCode()).isNotEqualTo(openingHtmlTagWithDifferentValue.hashCode()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java deleted file mode 100644 index 58d1c0b1c79..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.source; - -import com.google.common.collect.Lists; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -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.db.DbTester; -import org.sonar.db.protobuf.DbFileSources; -import org.sonar.db.source.FileSourceDto; -import org.sonar.server.source.index.FileSourceTesting; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SourceServiceTest { - - public static final String FILE_UUID = "FILE_UUID"; - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - HtmlSourceDecorator htmlDecorator = mock(HtmlSourceDecorator.class); - - SourceService underTest = new SourceService(dbTester.getDbClient(), htmlDecorator); - - @Before - public void injectFakeLines() { - FileSourceDto dto = new FileSourceDto(); - dto.setFileUuid(FILE_UUID).setProjectUuid("PROJECT_UUID"); - dto.setSourceData(FileSourceTesting.newFakeData(10).build()); - dbTester.getDbClient().fileSourceDao().insert(dbTester.getSession(), dto); - dbTester.commit(); - } - - @Test - public void get_range_of_lines() { - Set<Integer> lineNumbers = new HashSet<>(Arrays.asList(1, 5, 6)); - Optional<Iterable<DbFileSources.Line>> linesOpt = underTest.getLines(dbTester.getSession(), FILE_UUID, lineNumbers); - assertThat(linesOpt.isPresent()).isTrue(); - List<DbFileSources.Line> lines = Lists.newArrayList(linesOpt.get()); - assertThat(lines).hasSize(3); - assertThat(lines.get(0).getLine()).isEqualTo(1); - assertThat(lines.get(1).getLine()).isEqualTo(5); - assertThat(lines.get(2).getLine()).isEqualTo(6); - } - - @Test - public void get_set_of_lines() { - Optional<Iterable<DbFileSources.Line>> linesOpt = underTest.getLines(dbTester.getSession(), FILE_UUID, 5, 7); - assertThat(linesOpt.isPresent()).isTrue(); - List<DbFileSources.Line> lines = Lists.newArrayList(linesOpt.get()); - assertThat(lines).hasSize(3); - assertThat(lines.get(0).getLine()).isEqualTo(5); - assertThat(lines.get(1).getLine()).isEqualTo(6); - assertThat(lines.get(2).getLine()).isEqualTo(7); - } - - @Test - public void get_range_of_lines_as_raw_text() { - Optional<Iterable<String>> linesOpt = underTest.getLinesAsRawText(dbTester.getSession(), FILE_UUID, 5, 7); - assertThat(linesOpt.isPresent()).isTrue(); - List<String> lines = Lists.newArrayList(linesOpt.get()); - assertThat(lines).containsExactly("SOURCE_5", "SOURCE_6", "SOURCE_7"); - } - - @Test - public void get_range_of_lines_as_html() { - when(htmlDecorator.getDecoratedSourceAsHtml("SOURCE_5", "HIGHLIGHTING_5", "SYMBOLS_5")).thenReturn("HTML_5"); - when(htmlDecorator.getDecoratedSourceAsHtml("SOURCE_6", "HIGHLIGHTING_6", "SYMBOLS_6")).thenReturn("HTML_6"); - when(htmlDecorator.getDecoratedSourceAsHtml("SOURCE_7", "HIGHLIGHTING_7", "SYMBOLS_7")).thenReturn("HTML_7"); - - Optional<Iterable<String>> linesOpt = underTest.getLinesAsHtml(dbTester.getSession(), FILE_UUID, 5, 7); - assertThat(linesOpt.isPresent()).isTrue(); - List<String> lines = Lists.newArrayList(linesOpt.get()); - assertThat(lines).containsExactly("HTML_5", "HTML_6", "HTML_7"); - } - - @Test - public void getLines_fails_if_range_starts_at_zero() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Line number must start at 1, got 0"); - - underTest.getLines(dbTester.getSession(), FILE_UUID, 0, 2); - } - - @Test - public void getLines_fails_if_range_upper_bound_less_than_lower_bound() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Line number must greater than or equal to 5, got 4"); - - underTest.getLines(dbTester.getSession(), FILE_UUID, 5, 4); - } - - @Test - public void getLines_returns_empty_iterable_if_range_is_out_of_scope() { - Optional<Iterable<DbFileSources.Line>> lines = underTest.getLines(dbTester.getSession(), FILE_UUID, 500, 510); - assertThat(lines.isPresent()).isTrue(); - assertThat(lines.get()).isEmpty(); - } - - @Test - public void getLines_file_does_not_exist() { - Optional<Iterable<DbFileSources.Line>> lines = underTest.getLines(dbTester.getSession(), "FILE_DOES_NOT_EXIST", 1, 10); - assertThat(lines.isPresent()).isFalse(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java b/server/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java deleted file mode 100644 index 9a356bd4ff6..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.text; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.platform.Server; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MacroInterpreterTest { - - String path = "http://sonar"; - MacroInterpreter interpreter; - - @Before - public void setUp() { - Server server = mock(Server.class); - when(server.getContextPath()).thenReturn(path); - interpreter = new MacroInterpreter(server); - } - - @Test - public void should_do_nothing_if_no_macro_detected() { - String origin = "nothing to do"; - String result = interpreter.interpret(origin); - assertThat(result).isEqualTo(origin); - } - - @Test - public void should_replace_rule_macro() { - // key of repository and rule can contain alphanumeric latin characters, dashes, underscores and dots - String ruleKey = "Some_Repo-Key.1:Some_Rule-Key.1"; - String origin = "See {rule:" + ruleKey + "} for detail."; - String result = interpreter.interpret(origin); - // colon should be escaped - assertThat(result).isEqualTo("See <a href='" + path + "/coding_rules#rule_key=Some_Repo-Key.1%3ASome_Rule-Key.1'>Some_Rule-Key.1</a> for detail."); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/DeprecatedViewsTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/DeprecatedViewsTest.java deleted file mode 100644 index a25ff785be7..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/DeprecatedViewsTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.api.web.Page; -import org.sonar.api.web.View; -import org.sonar.api.web.Widget; - -import static org.assertj.core.api.Assertions.assertThat; - -public class DeprecatedViewsTest { - - @Rule - public LogTester logger = new LogTester(); - - private DeprecatedViews underTest; - - @Test - public void no_log_when_no_views() { - underTest = new DeprecatedViews(); - underTest.start(); - - assertThat(logger.logs()).isEmpty(); - } - - @Test - public void log_one_warning_by_view() { - underTest = new DeprecatedViews(new View[] { - new FakePage("governance/my_page", "My Page"), - new FakeWidget("governance/my_widget", "My Widget")}); - assertThat(logger.logs()).isEmpty(); - - underTest.start(); - - assertThat(logger.logs()).hasSize(2); - assertThat(logger.logs(LoggerLevel.WARN)).containsExactly( - "Page 'My Page' (governance/my_page) is ignored. See org.sonar.api.web.page.PageDefinition to define pages.", - "Widget 'My Widget' (governance/my_widget) is ignored. See org.sonar.api.web.page.PageDefinition to define pages."); - } - - private static final class FakeWidget implements Widget { - private final String id; - private final String name; - - private FakeWidget(String id, String name) { - this.id = id; - this.name = name; - } - - @Override - public String getId() { - return id; - } - - @Override - public String getTitle() { - return name; - } - } - - private static class FakePage implements Page { - private final String id; - private final String name; - - FakePage(String id, String name) { - this.id = id; - this.name = name; - } - - @Override - public String getId() { - return id; - } - - @Override - public String getTitle() { - return name; - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/PageDecorationsTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/PageDecorationsTest.java deleted file mode 100644 index f255c619ebe..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/PageDecorationsTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import org.junit.Test; -import org.sonar.api.web.PageDecoration; - -import java.util.Arrays; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -public class PageDecorationsTest { - - @Test - public void should_not_fail_if_no_decorations() { - assertThat(new PageDecorations().get()).isEmpty(); - } - - @Test - public void should_register_decorations() { - PageDecoration deco1 = mock(PageDecoration.class); - PageDecoration deco2 = mock(PageDecoration.class); - - PageDecorations decorations = new PageDecorations(Arrays.asList(deco1, deco2)); - - assertThat(decorations.get()).hasSize(2); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/PageRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/PageRepositoryTest.java deleted file mode 100644 index 6202f24b2a9..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/PageRepositoryTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -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.resources.Qualifiers; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.web.page.Page; -import org.sonar.api.web.page.Page.Qualifier; -import org.sonar.api.web.page.PageDefinition; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.platform.PluginRepository; -import org.sonar.core.extension.CoreExtensionRepository; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.api.web.page.Page.Scope.COMPONENT; -import static org.sonar.api.web.page.Page.Scope.GLOBAL; -import static org.sonar.api.web.page.Page.Scope.ORGANIZATION; - -public class PageRepositoryTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public LogTester logTester = new LogTester(); - - private PluginRepository pluginRepository = mock(PluginRepository.class); - private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class); - - private PageRepository underTest = new PageRepository(pluginRepository, coreExtensionRepository); - - @Before - public void setUp() { - when(pluginRepository.hasPlugin(any())).thenReturn(true); - when(pluginRepository.getPluginInfo(any())).thenReturn(new PluginInfo("unused")); - } - - @Test - public void pages_from_different_page_definitions_ordered_by_key() { - PageDefinition firstPlugin = context -> context - .addPage(Page.builder("my_plugin/K1").setName("N1").build()) - .addPage(Page.builder("my_plugin/K3").setName("N3").build()); - PageDefinition secondPlugin = context -> context.addPage(Page.builder("my_plugin/K2").setName("N2").build()); - underTest = new PageRepository(pluginRepository, coreExtensionRepository, new PageDefinition[]{firstPlugin, secondPlugin}); - underTest.start(); - - List<Page> result = underTest.getAllPages(); - - assertThat(result) - .extracting(Page::getKey, Page::getName) - .containsExactly( - tuple("my_plugin/K1", "N1"), - tuple("my_plugin/K2", "N2"), - tuple("my_plugin/K3", "N3")); - } - - @Test - public void filter_by_navigation_and_qualifier() { - PageDefinition plugin = context -> context - // Default with GLOBAL navigation and no qualifiers - .addPage(Page.builder("my_plugin/K1").setName("K1").build()) - .addPage(Page.builder("my_plugin/K2").setName("K2").setScope(COMPONENT).setComponentQualifiers(Qualifier.PROJECT).build()) - .addPage(Page.builder("my_plugin/K3").setName("K3").setScope(COMPONENT).setComponentQualifiers(Qualifier.MODULE).build()) - .addPage(Page.builder("my_plugin/K4").setName("K4").setScope(GLOBAL).build()) - .addPage(Page.builder("my_plugin/K5").setName("K5").setScope(COMPONENT).setComponentQualifiers(Qualifier.VIEW).build()) - .addPage(Page.builder("my_plugin/K6").setName("K6").setScope(COMPONENT).setComponentQualifiers(Qualifier.APP).build()); - underTest = new PageRepository(pluginRepository, coreExtensionRepository, new PageDefinition[]{plugin}); - underTest.start(); - - List<Page> result = underTest.getComponentPages(false, Qualifiers.PROJECT); - - assertThat(result) - .extracting(Page::getKey) - .containsExactly("my_plugin/K2"); - } - - @Test - public void empty_pages_if_no_page_definition() { - underTest.start(); - - List<Page> result = underTest.getAllPages(); - - assertThat(result).isEmpty(); - } - - @Test - public void filter_pages_without_qualifier() { - PageDefinition plugin = context -> context - .addPage(Page.builder("my_plugin/K1").setName("N1").build()) - .addPage(Page.builder("my_plugin/K2").setName("N2").build()) - .addPage(Page.builder("my_plugin/K3").setName("N3").build()); - underTest = new PageRepository(pluginRepository, coreExtensionRepository, new PageDefinition[]{plugin}); - underTest.start(); - - List<Page> result = underTest.getGlobalPages(false); - - assertThat(result) - .extracting(Page::getKey) - .containsExactly("my_plugin/K1", "my_plugin/K2", "my_plugin/K3"); - } - - @Test - public void get_organization_pages() { - PageDefinition plugin = context -> context - .addPage(Page.builder("my_plugin/G1").setName("G1").setScope(GLOBAL).build()) - .addPage(Page.builder("my_plugin/C1").setName("C1").setScope(COMPONENT).build()) - .addPage(Page.builder("my_plugin/O1").setName("O1").setScope(ORGANIZATION).build()) - .addPage(Page.builder("my_plugin/O2").setName("O2").setScope(ORGANIZATION).build()) - .addPage(Page.builder("my_plugin/O3").setName("O3").setScope(ORGANIZATION).build()) - .addPage(Page.builder("my_plugin/OA1").setName("OA1").setScope(ORGANIZATION).setAdmin(true).build()); - underTest = new PageRepository(pluginRepository, coreExtensionRepository, new PageDefinition[]{plugin}); - underTest.start(); - - List<Page> result = underTest.getOrganizationPages(false); - - assertThat(result) - .extracting(Page::getKey) - .containsExactly("my_plugin/O1", "my_plugin/O2", "my_plugin/O3"); - } - - @Test - public void get_organization_admin_pages() { - PageDefinition plugin = context -> context - .addPage(Page.builder("my_plugin/O1").setName("O1").setScope(ORGANIZATION).build()) - .addPage(Page.builder("my_plugin/O2").setName("O2").setScope(ORGANIZATION).setAdmin(true).build()); - underTest = new PageRepository(pluginRepository, coreExtensionRepository, new PageDefinition[]{plugin}); - underTest.start(); - - List<Page> result = underTest.getOrganizationPages(true); - - assertThat(result) - .extracting(Page::getKey) - .containsExactly("my_plugin/O2"); - } - - @Test - public void fail_if_pages_called_before_server_startup() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("Pages haven't been initialized yet"); - - underTest.getAllPages(); - } - - @Test - public void fail_if_page_with_unknown_plugin() { - PageDefinition governance = context -> context.addPage(Page.builder("governance/my_key").setName("N1").build()); - PageDefinition plugin42 = context -> context.addPage(Page.builder("plugin_42/my_key").setName("N2").build()); - pluginRepository = mock(PluginRepository.class); - when(pluginRepository.hasPlugin("governance")).thenReturn(true); - underTest = new PageRepository(pluginRepository, coreExtensionRepository, new PageDefinition[]{governance, plugin42}); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Page 'N2' references plugin 'plugin_42' that does not exist"); - - underTest.start(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/VersionFormatterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/VersionFormatterTest.java deleted file mode 100644 index 35b65e8f720..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/VersionFormatterTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class VersionFormatterTest { - @Test - public void format_technical_version() { - assertThat(format("6.3")).isEqualTo("6.3"); - assertThat(format("6.3.2")).isEqualTo("6.3.2"); - assertThat(format("6.3.2.5498")).isEqualTo("6.3.2 (build 5498)"); - assertThat(format("6.3.0.5499")).isEqualTo("6.3 (build 5499)"); - } - - private static String format(String technicalVersion) { - return VersionFormatter.format(technicalVersion); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/WebAnalyticsLoaderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/WebAnalyticsLoaderImplTest.java deleted file mode 100644 index e7be923df8e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/WebAnalyticsLoaderImplTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.ui; - -import org.junit.Test; -import org.sonar.api.utils.MessageException; -import org.sonar.api.web.WebAnalytics; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class WebAnalyticsLoaderImplTest { - - @Test - public void return_empty_if_no_analytics_plugin() { - assertThat(new WebAnalyticsLoaderImpl().getUrlPathToJs()).isEmpty(); - assertThat(new WebAnalyticsLoaderImpl(new WebAnalytics[0]).getUrlPathToJs()).isEmpty(); - } - - @Test - public void return_js_path_if_analytics_plugin_is_installed() { - WebAnalytics analytics = newWebAnalytics("api/google/analytics"); - WebAnalyticsLoaderImpl underTest = new WebAnalyticsLoaderImpl(new WebAnalytics[] {analytics}); - - assertThat(underTest.getUrlPathToJs()).hasValue("/api/google/analytics"); - } - - @Test - public void return_empty_if_path_starts_with_slash() { - WebAnalytics analytics = newWebAnalytics("/api/google/analytics"); - WebAnalyticsLoaderImpl underTest = new WebAnalyticsLoaderImpl(new WebAnalytics[] {analytics}); - - assertThat(underTest.getUrlPathToJs()).isEmpty(); - } - - @Test - public void return_empty_if_path_is_an_url() { - WebAnalytics analytics = newWebAnalytics("http://foo"); - WebAnalyticsLoaderImpl underTest = new WebAnalyticsLoaderImpl(new WebAnalytics[] {analytics}); - - assertThat(underTest.getUrlPathToJs()).isEmpty(); - } - - @Test - public void return_empty_if_path_has_up_operation() { - WebAnalytics analytics = newWebAnalytics("foo/../bar"); - WebAnalyticsLoaderImpl underTest = new WebAnalyticsLoaderImpl(new WebAnalytics[] {analytics}); - - assertThat(underTest.getUrlPathToJs()).isEmpty(); - } - - @Test - public void fail_if_multiple_analytics_plugins_are_installed() { - WebAnalytics analytics1 = newWebAnalytics("foo"); - WebAnalytics analytics2 = newWebAnalytics("bar"); - - Throwable thrown = catchThrowable(() -> new WebAnalyticsLoaderImpl(new WebAnalytics[] {analytics1, analytics2})); - - assertThat(thrown) - .isInstanceOf(MessageException.class) - .hasMessage("Limited to only one web analytics plugin. Found multiple implementations: [" + - analytics1.getClass().getName() + ", " + analytics2.getClass().getName() + "]"); - } - - private static WebAnalytics newWebAnalytics(String path) { - WebAnalytics analytics = mock(WebAnalytics.class); - when(analytics.getUrlPathToJs()).thenReturn(path); - return analytics; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/util/LanguageParamUtilsTest.java b/server/sonar-server/src/test/java/org/sonar/server/util/LanguageParamUtilsTest.java deleted file mode 100644 index ba47e982444..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/util/LanguageParamUtilsTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.util; - -import org.junit.Test; -import org.sonar.api.resources.AbstractLanguage; -import org.sonar.api.resources.Languages; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LanguageParamUtilsTest { - - @Test - public void getOrderedLanguageKeys() { - assertThat(LanguageParamUtils.getOrderedLanguageKeys(new Languages())).isEmpty(); - - Languages languages = new Languages( - new TestLanguage("java"), - new TestLanguage("abap"), - new TestLanguage("js"), - new TestLanguage("cobol")); - assertThat(LanguageParamUtils.getOrderedLanguageKeys(languages)).containsExactly("abap", "cobol", "java", "js"); - } - - private static class TestLanguage extends AbstractLanguage { - TestLanguage(String key) { - super(key); - } - - @Override - public String[] getFileSuffixes() { - return new String[0]; - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/webhook/WebhookQGChangeEventListenerTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/WebhookQGChangeEventListenerTest.java deleted file mode 100644 index 7d82731e6a3..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/webhook/WebhookQGChangeEventListenerTest.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.webhook; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.function.Supplier; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.sonar.api.config.Configuration; -import org.sonar.api.measures.Metric; -import org.sonar.api.utils.System2; -import org.sonar.core.util.UuidFactoryFast; -import org.sonar.db.DbClient; -import org.sonar.db.DbTester; -import org.sonar.db.component.AnalysisPropertyDto; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.qualitygate.EvaluatedQualityGate; -import org.sonar.server.qualitygate.changeevent.QGChangeEvent; -import org.sonar.server.qualitygate.changeevent.QGChangeEventListener; - -import static java.util.Arrays.stream; -import static java.util.Collections.emptySet; -import static java.util.stream.Stream.concat; -import static java.util.stream.Stream.of; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.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.util.stream.MoreCollectors.toArrayList; -import static org.sonar.db.component.BranchType.LONG; -import static org.sonar.db.component.BranchType.SHORT; -import static org.sonar.db.component.ComponentTesting.newBranchDto; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; - -@RunWith(DataProviderRunner.class) -public class WebhookQGChangeEventListenerTest { - - private static final Set<QGChangeEventListener.ChangedIssue> CHANGED_ISSUES_ARE_IGNORED = emptySet(); - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - private DbClient dbClient = dbTester.getDbClient(); - - private EvaluatedQualityGate newQualityGate = mock(EvaluatedQualityGate.class); - private WebHooks webHooks = mock(WebHooks.class); - private WebhookPayloadFactory webhookPayloadFactory = mock(WebhookPayloadFactory.class); - private DbClient spiedOnDbClient = Mockito.spy(dbClient); - private WebhookQGChangeEventListener underTest = new WebhookQGChangeEventListener(webHooks, webhookPayloadFactory, spiedOnDbClient); - private DbClient mockedDbClient = mock(DbClient.class); - private WebhookQGChangeEventListener mockedUnderTest = new WebhookQGChangeEventListener(webHooks, webhookPayloadFactory, mockedDbClient); - - @Test - @UseDataProvider("allCombinationsOfStatuses") - public void onIssueChanges_has_no_effect_if_no_webhook_is_configured(Metric.Level previousStatus, Metric.Level newStatus) { - Configuration configuration1 = mock(Configuration.class); - when(newQualityGate.getStatus()).thenReturn(newStatus); - QGChangeEvent qualityGateEvent = newQGChangeEvent(configuration1, previousStatus, newQualityGate); - mockWebhookDisabled(qualityGateEvent.getProject()); - - mockedUnderTest.onIssueChanges(qualityGateEvent, CHANGED_ISSUES_ARE_IGNORED); - - verify(webHooks).isEnabled(qualityGateEvent.getProject()); - verifyZeroInteractions(webhookPayloadFactory, mockedDbClient); - } - - @DataProvider - public static Object[][] allCombinationsOfStatuses() { - Metric.Level[] levelsAndNull = concat(of((Metric.Level) null), stream(Metric.Level.values())) - .toArray(Metric.Level[]::new); - Object[][] res = new Object[levelsAndNull.length * levelsAndNull.length][2]; - int i = 0; - for (Metric.Level previousStatus : Arrays.asList(levelsAndNull)) { - for (Metric.Level newStatus : Arrays.asList(levelsAndNull)) { - res[i][0] = previousStatus; - res[i][1] = newStatus; - i++; - } - } - return res; - } - - @Test - public void onIssueChanges_has_no_effect_if_event_has_neither_previousQGStatus_nor_qualityGate() { - Configuration configuration = mock(Configuration.class); - QGChangeEvent qualityGateEvent = newQGChangeEvent(configuration, null, null); - mockWebhookEnabled(qualityGateEvent.getProject()); - - underTest.onIssueChanges(qualityGateEvent, CHANGED_ISSUES_ARE_IGNORED); - - verifyZeroInteractions(webhookPayloadFactory, mockedDbClient); - } - - @Test - public void onIssueChanges_has_no_effect_if_event_has_same_status_in_previous_and_new_QG() { - Configuration configuration = mock(Configuration.class); - Metric.Level previousStatus = randomLevel(); - when(newQualityGate.getStatus()).thenReturn(previousStatus); - QGChangeEvent qualityGateEvent = newQGChangeEvent(configuration, previousStatus, newQualityGate); - mockWebhookEnabled(qualityGateEvent.getProject()); - - underTest.onIssueChanges(qualityGateEvent, CHANGED_ISSUES_ARE_IGNORED); - - verifyZeroInteractions(webhookPayloadFactory, mockedDbClient); - } - - @Test - @UseDataProvider("newQGorNot") - public void onIssueChanges_calls_webhook_for_changeEvent_with_webhook_enabled(@Nullable EvaluatedQualityGate newQualityGate) { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto project = dbTester.components().insertPublicProject(organization); - ComponentAndBranch branch = insertProjectBranch(project, BranchType.SHORT, "foo"); - SnapshotDto analysis = insertAnalysisTask(branch); - Configuration configuration = mock(Configuration.class); - mockPayloadSupplierConsumedByWebhooks(); - Map<String, String> properties = new HashMap<>(); - properties.put("sonar.analysis.test1", randomAlphanumeric(50)); - properties.put("sonar.analysis.test2", randomAlphanumeric(5000)); - insertPropertiesFor(analysis.getUuid(), properties); - QGChangeEvent qualityGateEvent = newQGChangeEvent(branch, analysis, configuration, newQualityGate); - mockWebhookEnabled(qualityGateEvent.getProject()); - - underTest.onIssueChanges(qualityGateEvent, CHANGED_ISSUES_ARE_IGNORED); - - ProjectAnalysis projectAnalysis = verifyWebhookCalledAndExtractPayloadFactoryArgument(branch, analysis, qualityGateEvent.getProject()); - assertThat(projectAnalysis).isEqualTo( - new ProjectAnalysis( - new Project(project.uuid(), project.getKey(), project.name()), - null, - new Analysis(analysis.getUuid(), analysis.getCreatedAt(), analysis.getRevision()), - new Branch(false, "foo", Branch.Type.SHORT), - newQualityGate, - null, - properties)); - } - - @Test - @UseDataProvider("newQGorNot") - public void onIssueChanges_calls_webhook_on_main_branch(@Nullable EvaluatedQualityGate newQualityGate) { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentAndBranch mainBranch = insertMainBranch(organization); - SnapshotDto analysis = insertAnalysisTask(mainBranch); - Configuration configuration = mock(Configuration.class); - QGChangeEvent qualityGateEvent = newQGChangeEvent(mainBranch, analysis, configuration, newQualityGate); - mockWebhookEnabled(qualityGateEvent.getProject()); - - underTest.onIssueChanges(qualityGateEvent, CHANGED_ISSUES_ARE_IGNORED); - - verifyWebhookCalled(mainBranch, analysis, qualityGateEvent.getProject()); - } - - @Test - public void onIssueChanges_calls_webhook_on_long_branch() { - onIssueChangesCallsWebhookOnBranch(BranchType.LONG); - } - - @Test - public void onIssueChanges_calls_webhook_on_short_branch() { - onIssueChangesCallsWebhookOnBranch(SHORT); - } - - public void onIssueChangesCallsWebhookOnBranch(BranchType branchType) { - OrganizationDto organization = dbTester.organizations().insert(); - ComponentAndBranch mainBranch = insertMainBranch(organization); - ComponentAndBranch longBranch = insertProjectBranch(mainBranch.component, branchType, "foo"); - SnapshotDto analysis = insertAnalysisTask(longBranch); - Configuration configuration = mock(Configuration.class); - QGChangeEvent qualityGateEvent = newQGChangeEvent(longBranch, analysis, configuration, null); - mockWebhookEnabled(qualityGateEvent.getProject()); - - underTest.onIssueChanges(qualityGateEvent, CHANGED_ISSUES_ARE_IGNORED); - - verifyWebhookCalled(longBranch, analysis, qualityGateEvent.getProject()); - } - - @DataProvider - public static Object[][] newQGorNot() { - EvaluatedQualityGate newQualityGate = mock(EvaluatedQualityGate.class); - return new Object[][] { - {null}, - {newQualityGate} - }; - } - - private void mockWebhookEnabled(ComponentDto... projects) { - for (ComponentDto dto : projects) { - when(webHooks.isEnabled(dto)).thenReturn(true); - } - } - - private void mockWebhookDisabled(ComponentDto... projects) { - for (ComponentDto dto : projects) { - when(webHooks.isEnabled(dto)).thenReturn(false); - } - } - - private void mockPayloadSupplierConsumedByWebhooks() { - Mockito.doAnswer(invocationOnMock -> { - Supplier<WebhookPayload> supplier = (Supplier<WebhookPayload>) invocationOnMock.getArguments()[1]; - supplier.get(); - return null; - }).when(webHooks) - .sendProjectAnalysisUpdate(any(), any()); - } - - private void insertPropertiesFor(String snapshotUuid, Map<String, String> properties) { - List<AnalysisPropertyDto> analysisProperties = properties.entrySet().stream() - .map(entry -> new AnalysisPropertyDto() - .setUuid(UuidFactoryFast.getInstance().create()) - .setAnalysisUuid(snapshotUuid) - .setKey(entry.getKey()) - .setValue(entry.getValue())) - .collect(toArrayList(properties.size())); - dbTester.getDbClient().analysisPropertiesDao().insert(dbTester.getSession(), analysisProperties); - dbTester.getSession().commit(); - } - - private SnapshotDto insertAnalysisTask(ComponentAndBranch componentAndBranch) { - return dbTester.components().insertSnapshot(componentAndBranch.component); - } - - private ProjectAnalysis verifyWebhookCalledAndExtractPayloadFactoryArgument(ComponentAndBranch componentAndBranch, SnapshotDto analysis, ComponentDto project) { - verifyWebhookCalled(componentAndBranch, analysis, project); - - return extractPayloadFactoryArguments(1).iterator().next(); - } - - private void verifyWebhookCalled(ComponentAndBranch componentAndBranch, SnapshotDto analysis, ComponentDto project) { - verify(webHooks).isEnabled(project); - verify(webHooks).sendProjectAnalysisUpdate( - eq(new WebHooks.Analysis(componentAndBranch.uuid(), analysis.getUuid(), null)), - any()); - } - - private List<ProjectAnalysis> extractPayloadFactoryArguments(int time) { - ArgumentCaptor<ProjectAnalysis> projectAnalysisCaptor = ArgumentCaptor.forClass(ProjectAnalysis.class); - verify(webhookPayloadFactory, Mockito.times(time)).create(projectAnalysisCaptor.capture()); - return projectAnalysisCaptor.getAllValues(); - } - - public ComponentAndBranch insertMainBranch(OrganizationDto organization) { - ComponentDto project = newPrivateProjectDto(organization); - BranchDto branch = newBranchDto(project, LONG).setKey("master"); - dbTester.components().insertComponent(project); - dbClient.branchDao().insert(dbTester.getSession(), branch); - dbTester.commit(); - return new ComponentAndBranch(project, branch); - } - - public ComponentAndBranch insertProjectBranch(ComponentDto project, BranchType type, String branchKey) { - BranchDto branchDto = newBranchDto(project.projectUuid(), type).setKey(branchKey); - ComponentDto newComponent = dbTester.components().insertProjectBranch(project, branchDto); - return new ComponentAndBranch(newComponent, branchDto); - } - - private static class ComponentAndBranch { - private final ComponentDto component; - - private final BranchDto branch; - - private ComponentAndBranch(ComponentDto component, BranchDto branch) { - this.component = component; - this.branch = branch; - } - - public ComponentDto getComponent() { - return component; - } - - public BranchDto getBranch() { - return branch; - } - - public String uuid() { - return component.uuid(); - } - - } - - private static QGChangeEvent newQGChangeEvent(Configuration configuration, @Nullable Metric.Level previousQQStatus, @Nullable EvaluatedQualityGate evaluatedQualityGate) { - return new QGChangeEvent(new ComponentDto(), new BranchDto(), new SnapshotDto(), configuration, previousQQStatus, () -> Optional.ofNullable(evaluatedQualityGate)); - } - - private static QGChangeEvent newQGChangeEvent(ComponentAndBranch branch, SnapshotDto analysis, Configuration configuration, @Nullable EvaluatedQualityGate evaluatedQualityGate) { - Metric.Level previousStatus = randomLevel(); - if (evaluatedQualityGate != null) { - Metric.Level otherLevel = stream(Metric.Level.values()) - .filter(s -> s != previousStatus) - .toArray(Metric.Level[]::new)[new Random().nextInt(Metric.Level.values().length - 1)]; - when(evaluatedQualityGate.getStatus()).thenReturn(otherLevel); - } - return new QGChangeEvent(branch.component, branch.branch, analysis, configuration, previousStatus, () -> Optional.ofNullable(evaluatedQualityGate)); - } - - private static Metric.Level randomLevel() { - return Metric.Level.values()[new Random().nextInt(Metric.Level.values().length)]; - } - -} diff --git a/server/sonar-server/src/test/projects/.gitignore b/server/sonar-server/src/test/projects/.gitignore deleted file mode 100644 index a945b8525e6..00000000000 --- a/server/sonar-server/src/test/projects/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# see README.txt -!*/target/ -*/target/classes/ -*/target/maven-archiver/ -*/target/maven-status/ -*/target/test-*/ - diff --git a/server/sonar-server/src/test/projects/README.txt b/server/sonar-server/src/test/projects/README.txt deleted file mode 100644 index c53a66d52f2..00000000000 --- a/server/sonar-server/src/test/projects/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This directory provides the fake plugins used by tests. These tests are rarely changed, so generated -artifacts are stored in Git repository (see .gitignore). It avoids from adding unnecessary modules -to build. diff --git a/server/sonar-server/src/test/projects/fake-report-plugin/pom.xml b/server/sonar-server/src/test/projects/fake-report-plugin/pom.xml deleted file mode 100644 index 72a04dbe04f..00000000000 --- a/server/sonar-server/src/test/projects/fake-report-plugin/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>fake-report-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Fake Report Plugin</name> - <description>Fake Report Plugin</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>report</pluginKey> - <pluginClass>BasePlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/fake-report-plugin/src/BasePlugin.java b/server/sonar-server/src/test/projects/fake-report-plugin/src/BasePlugin.java deleted file mode 100644 index d12daff3e57..00000000000 --- a/server/sonar-server/src/test/projects/fake-report-plugin/src/BasePlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class BasePlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/fake-report-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java b/server/sonar-server/src/test/projects/fake-report-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java deleted file mode 100644 index e0b54398eaf..00000000000 --- a/server/sonar-server/src/test/projects/fake-report-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.testbase.api; - -public class BaseApi { - public void doNothing() { - } -} diff --git a/server/sonar-server/src/test/projects/fake-report-plugin/target/fake-report-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/fake-report-plugin/target/fake-report-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 6085e44fdca..00000000000 --- a/server/sonar-server/src/test/projects/fake-report-plugin/target/fake-report-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/fake-sqale-plugin/pom.xml b/server/sonar-server/src/test/projects/fake-sqale-plugin/pom.xml deleted file mode 100644 index e417dd96fba..00000000000 --- a/server/sonar-server/src/test/projects/fake-sqale-plugin/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>fake-sqale-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Fake SQALE Plugin</name> - <description>Fake SQALE Plugin</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>sqale</pluginKey> - <pluginClass>BasePlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/fake-sqale-plugin/src/BasePlugin.java b/server/sonar-server/src/test/projects/fake-sqale-plugin/src/BasePlugin.java deleted file mode 100644 index d12daff3e57..00000000000 --- a/server/sonar-server/src/test/projects/fake-sqale-plugin/src/BasePlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class BasePlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/fake-sqale-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java b/server/sonar-server/src/test/projects/fake-sqale-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java deleted file mode 100644 index e0b54398eaf..00000000000 --- a/server/sonar-server/src/test/projects/fake-sqale-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.testbase.api; - -public class BaseApi { - public void doNothing() { - } -} diff --git a/server/sonar-server/src/test/projects/fake-sqale-plugin/target/fake-sqale-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/fake-sqale-plugin/target/fake-sqale-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index b5c99f721b3..00000000000 --- a/server/sonar-server/src/test/projects/fake-sqale-plugin/target/fake-sqale-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/fake-views-plugin/pom.xml b/server/sonar-server/src/test/projects/fake-views-plugin/pom.xml deleted file mode 100644 index 1ef73d2ffda..00000000000 --- a/server/sonar-server/src/test/projects/fake-views-plugin/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>fake-views-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Fake Views Plugin</name> - <description>Fake Views Plugin</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>views</pluginKey> - <pluginClass>BasePlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/fake-views-plugin/src/BasePlugin.java b/server/sonar-server/src/test/projects/fake-views-plugin/src/BasePlugin.java deleted file mode 100644 index d12daff3e57..00000000000 --- a/server/sonar-server/src/test/projects/fake-views-plugin/src/BasePlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class BasePlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/fake-views-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java b/server/sonar-server/src/test/projects/fake-views-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java deleted file mode 100644 index e0b54398eaf..00000000000 --- a/server/sonar-server/src/test/projects/fake-views-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.testbase.api; - -public class BaseApi { - public void doNothing() { - } -} diff --git a/server/sonar-server/src/test/projects/fake-views-plugin/target/fake-views-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/fake-views-plugin/target/fake-views-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index a47d93d94a8..00000000000 --- a/server/sonar-server/src/test/projects/fake-views-plugin/target/fake-views-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/pom.xml b/server/sonar-server/src/test/projects/pom.xml deleted file mode 100644 index 37338313ac0..00000000000 --- a/server/sonar-server/src/test/projects/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>parent</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>pom</packaging> - <modules> - <module>test-base-plugin</module> - <module>test-base-plugin-v2</module> - <module>test-core-plugin</module> - <module>test-extend-plugin</module> - <module>test-libs-plugin</module> - <module>test-require-plugin</module> - <module>test-requirenew-plugin</module> - <module>fake-report-plugin</module> - <module>fake-sqale-plugin</module> - <module>fake-views-plugin</module> - </modules> - -</project> diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml b/server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml deleted file mode 100644 index 982be1c0170..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-base-plugin</artifactId> - <version>0.2-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Base Plugin</name> - <description>Simple standalone plugin. Used by other fake plugins.</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>testbase</pluginKey> - <pluginClass>BasePlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java b/server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java deleted file mode 100644 index d12daff3e57..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class BasePlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/src/org/sonar/plugins/testbase/api/BaseApi.java b/server/sonar-server/src/test/projects/test-base-plugin-v2/src/org/sonar/plugins/testbase/api/BaseApi.java deleted file mode 100644 index e0b54398eaf..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin-v2/src/org/sonar/plugins/testbase/api/BaseApi.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.testbase.api; - -public class BaseApi { - public void doNothing() { - } -} diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 1d4ef5430c7..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/test-base-plugin/pom.xml b/server/sonar-server/src/test/projects/test-base-plugin/pom.xml deleted file mode 100644 index c4e95936e74..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-base-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Base Plugin</name> - <description>Simple standalone plugin. Used by other fake plugins.</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>testbase</pluginKey> - <pluginClass>BasePlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java b/server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java deleted file mode 100644 index d12daff3e57..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class BasePlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/test-base-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java b/server/sonar-server/src/test/projects/test-base-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java deleted file mode 100644 index e0b54398eaf..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin/src/org/sonar/plugins/testbase/api/BaseApi.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.plugins.testbase.api; - -public class BaseApi { - public void doNothing() { - } -} diff --git a/server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 739a22fcdae..00000000000 --- a/server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/test-core-plugin/pom.xml b/server/sonar-server/src/test/projects/test-core-plugin/pom.xml deleted file mode 100644 index d3e86d6cf95..00000000000 --- a/server/sonar-server/src/test/projects/test-core-plugin/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-core-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Test Core Plugin</name> - <description>Fake core plugin used by tests</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>core</pluginKey> - <pluginClass>CorePlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java b/server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java deleted file mode 100644 index 29bc924ff25..00000000000 --- a/server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class CorePlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 831cc364b5c..00000000000 --- a/server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/test-extend-plugin/pom.xml b/server/sonar-server/src/test/projects/test-extend-plugin/pom.xml deleted file mode 100644 index e23667e6318..00000000000 --- a/server/sonar-server/src/test/projects/test-extend-plugin/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-extend-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Test Extend Plugin</name> - <description>Fake plugin that extends the plugin with key "base"</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>testextend</pluginKey> - <pluginClass>ExtendPlugin</pluginClass> - <basePlugin>testbase</basePlugin> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java b/server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java deleted file mode 100644 index d364a2f9dd4..00000000000 --- a/server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class ExtendPlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 2f63c2e652c..00000000000 --- a/server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/test-libs-plugin/pom.xml b/server/sonar-server/src/test/projects/test-libs-plugin/pom.xml deleted file mode 100644 index 2d49cca2cf2..00000000000 --- a/server/sonar-server/src/test/projects/test-libs-plugin/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-libs-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Test Libs Plugin</name> - <description>Fake plugin that embeds some libraries</description> - - <dependencies> - <!-- embedded libs. Chosen because small ! --> - <dependency> - <groupId>commons-email</groupId> - <artifactId>commons-email</artifactId> - <version>20030310.165926</version> - </dependency> - <dependency> - <groupId>commons-daemon</groupId> - <artifactId>commons-daemon</artifactId> - <version>1.0.15</version> - </dependency> - - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - </dependencies> - - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>testlibs</pluginKey> - <pluginClass>LibsPlugin</pluginClass> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java b/server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java deleted file mode 100644 index 7e3ebe0909c..00000000000 --- a/server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class LibsPlugin extends Plugin { - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 6ebe8652d8b..00000000000 --- a/server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/test-require-plugin/pom.xml b/server/sonar-server/src/test/projects/test-require-plugin/pom.xml deleted file mode 100644 index 62462ffbf34..00000000000 --- a/server/sonar-server/src/test/projects/test-require-plugin/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-require-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Test Require Plugin</name> - <description>This fake plugin depends on test-base-plugin</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-base-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <type>sonar-plugin</type> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>testrequire</pluginKey> - <pluginClass>RequirePlugin</pluginClass> - <requirePlugins>testbase:0.1</requirePlugins> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java b/server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java deleted file mode 100644 index 847ae2d994e..00000000000 --- a/server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class RequirePlugin extends Plugin { - - public RequirePlugin() { - // call a class that is in the api published by the base plugin - new org.sonar.plugins.testbase.api.BaseApi().doNothing(); - } - - public void define(Plugin.Context context) { - - } -} diff --git a/server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index f5fc95f9d0d..00000000000 --- a/server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml b/server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml deleted file mode 100644 index 044cd94e8f0..00000000000 --- a/server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-requirenew-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <packaging>sonar-plugin</packaging> - <name>Test Require New Plugin</name> - <description>This fake plugin requires a version of test-base-plugin that is not installed</description> - - <dependencies> - <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-plugin-api</artifactId> - <version>4.5.4</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.sonarsource.sonarqube.tests</groupId> - <artifactId>test-base-plugin</artifactId> - <version>0.1-SNAPSHOT</version> - <type>sonar-plugin</type> - <scope>provided</scope> - </dependency> - </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> - <artifactId>sonar-packaging-maven-plugin</artifactId> - <version>1.15</version> - <extensions>true</extensions> - <configuration> - <pluginKey>testrequire</pluginKey> - <pluginClass>RequirePlugin</pluginClass> - <requirePlugins>testbase:0.2</requirePlugins> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java b/server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java deleted file mode 100644 index 0d14cde33c1..00000000000 --- a/server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -import org.sonar.api.Plugin; - -import java.util.Collections; -import java.util.List; - -public class RequirePlugin extends Plugin { - - public RequirePlugin() { - // call a class that is in the api published by the base plugin - new org.sonar.plugins.testbase.api.BaseApi().doNothing(); - } - - public void define(Plugin.Context context) { - - } - -} diff --git a/server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jar Binary files differdeleted file mode 100644 index 0dd577fc360..00000000000 --- a/server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jar +++ /dev/null diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/duplicates-xml-backup.xml b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/duplicates-xml-backup.xml deleted file mode 100644 index 4a41aa0b275..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/duplicates-xml-backup.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<profile> - <name>P1</name> - <language>xoo</language> - <rules> - <rule> - <repositoryKey>xoo</repositoryKey> - <key>x1</key> - <priority>BLOCKER</priority> - <parameters> - <parameter> - <key>max</key> - <value>7</value> - </parameter> - </parameters> - </rule> - <rule> - <repositoryKey>xoo</repositoryKey> - <key>x2</key> - <priority>CRITICAL</priority> - </rule> - <rule> - <repositoryKey>xoo</repositoryKey> - <key>x1</key> - <priority>MAJOR</priority> - <parameters> - <parameter> - <key>max</key> - <value>5</value> - </parameter> - </parameters> - </rule> - <rule> - <repositoryKey>xoo</repositoryKey> - <key>x2</key> - <priority>MINOR</priority> - </rule> - - </rules> -</profile> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_active_rules_with_inheritance/active_rule25.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_active_rules_with_inheritance/active_rule25.json deleted file mode 100644 index c38e4a347f9..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_active_rules_with_inheritance/active_rule25.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 25, - "severity": "MINOR", - "profileId": 1, - "inheritance": null -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_active_rules_with_inheritance/active_rule391.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_active_rules_with_inheritance/active_rule391.json deleted file mode 100644 index fb70c854fde..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_active_rules_with_inheritance/active_rule391.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": 391, - "severity": "MINOR", - "profileId": 2, - "inheritance": "INHERITED", - "activeRuleParentId": 25 -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_A.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_A.json deleted file mode 100644 index bcd7657a309..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_A.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": 2303, - "key": "RuleA", - "language": "xoo", - "name": "A first rule", - "description": "First rule of Fight Club is: you do not talk about Fight Club.", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "INFO", - "status": "READY", - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_C.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_C.json deleted file mode 100644 index edd28e543ca..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_C.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": 2305, - "key": "RuleC", - "language": "xoo", - "name": "C third rule", - "description": "Third rule of Fight Club: someone yells stop, goes limp, taps out, the fight is over.", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "BLOCKER", - "status": "READY", - "createdAt": "2013-07-04T07:38:05.543Z", - "updatedAt": "2013-03-27T08:52:40.370Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_b.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_b.json deleted file mode 100644 index 89ce23ad769..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_sorted_ignoring_case/rule_b.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": 2304, - "key": "Ruleb", - "language": "xoo", - "name": "b second rule", - "description": "Second rule of Fight Club is: you do NOT talk about Fight Club.", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "MAJOR", - "status": "READY", - "createdAt": "2013-12-04T10:24:11.000Z", - "updatedAt": "2013-12-12T15:20:01.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/active_rule_ace.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/active_rule_ace.json deleted file mode 100644 index 50548b21f07..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/active_rule_ace.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 2307, - "severity": "CRITICAL", - "profileId": 2, - "inheritance": null -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/active_rule_empty.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/active_rule_empty.json deleted file mode 100644 index ed94424e6ac..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/active_rule_empty.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 2303, - "severity": "INFO", - "profileId": 2, - "inheritance": null -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_a.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_a.json deleted file mode 100644 index 948107d967b..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_a.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": 2304, - "key": "RuleWithTagA", - "language": "xoo", - "name": "Rule with tag taga", - "description": "This rule has tag 'taga'", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "INFO", - "status": "READY", - "systemTags": ["taga"], - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_ab.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_ab.json deleted file mode 100644 index 3ca733480ae..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_ab.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": 2305, - "key": "RuleWithTagsAB", - "language": "xoo", - "name": "Rule with tags taga and tagb", - "description": "This rule has tags 'taga' and 'tagb'", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "INFO", - "status": "READY", - "systemTags": ["tagb"], - "adminTags": ["taga"], - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_ace.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_ace.json deleted file mode 100644 index 44243bb1fdb..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_ace.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": 2307, - "key": "RuleWithTagsACE", - "language": "xoo", - "name": "Rule with tags taga, tagc and tage", - "description": "This rule has tags 'taga', 'tagc' and 'tage'", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "INFO", - "status": "READY", - "systemTags": ["taga", "tagc"], - "adminTags": ["tage"], - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_bc.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_bc.json deleted file mode 100644 index 59ca77178d4..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_bc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": 2306, - "key": "RuleWithTagsBC", - "language": "xoo", - "name": "Rule with tags tagb and tagc", - "description": "This rule has tags 'tagb' and 'tagc'", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "INFO", - "status": "READY", - "systemTags": ["tagb", "tagc"], - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_empty.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_empty.json deleted file mode 100644 index 43ca4f94522..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/find_inactive_rules_with_tags/tags_empty.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": 2303, - "key": "RuleWithoutTags", - "language": "xoo", - "name": "Rule without tags", - "description": "This rule has no tag", - "parentKey": null, - "repositoryKey": "xoo", - "severity": "INFO", - "status": "READY", - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule25.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule25.json deleted file mode 100644 index 38c9040b3b5..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule25.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 25, - "severity": "MINOR", - "profileId": 1, - "inheritance": "OVERRIDES" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule2702.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule2702.json deleted file mode 100644 index 2025fbe362c..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule2702.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": 2702, - "severity": "CRITICAL", - "profileId": 1, - "inheritance": null, - "params": [ - { - "key": "fromClasses", - "value": "**.core.**" - }, - { - "key": "toClasses", - "value": "**.server.**" - } - ] -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule391.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule391.json deleted file mode 100644 index 2bb34dc2042..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule391.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": 391, - "severity": "MAJOR", - "profileId": 1, - "inheritance": "INHERITED", - "activeRuleParentId": 25 -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule523.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule523.json deleted file mode 100644 index 96af0f464a5..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/active_rule523.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 523, - "severity": "MAJOR", - "profileId": 2, - "inheritance": null -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule1482.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule1482.json deleted file mode 100644 index 3f2ca70c432..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule1482.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "id": 1482, - "key": "ArchitecturalConstraint", - "language": "java", - "name": "Architectural constraint", - "description": "<p>A source code comply to an architectural model when it fully\n\tadheres to a set of architectural constraints. A constraint allows to\n\tdeny references between classes by pattern.</p>\n<p>You can for instance use this rule to :</p>\n<ul>\n\t<li>forbid access to **.web.** from **.dao.** classes</li>\n\t<li>forbid access to java.util.Vector, java.util.Hashtable and\n\t\tjava.util.Enumeration from any classes</li>\n\t<li>forbid access to java.sql.** from **.ui.** and **.web.**\n\t\tclasses</li>\n</ul>", - "parentKey": null, - "repositoryKey": "squid", - "severity": "MAJOR", - "status": "READY", - "createdAt": "2013-12-11T13:48:00.799Z", - "updatedAt": "2013-12-13T17:26:35.767Z", - "params": [ - { - "key": "toClasses", - "type": "STRING", - "defaultValue": "", - "description": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration" - }, - { - "key": "fromClasses", - "type": "STRING", - "defaultValue": "", - "description": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : **.web.**" - } - ] -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule25.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule25.json deleted file mode 100644 index 6fff4e43a57..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule25.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": 25, - "key": "DM_CONVERT_CASE", - "language": "java", - "name": "Internationalization - Consider using Locale parameterized version of invoked method", - "description": "<p> A String is being converted to upper or lowercase, using the platform's default encoding. This may\n result in improper conversions when used with international characters. Use the </p>\n <table><tr><td>String.toUpperCase( Locale l )</td></tr><tr><td>String.toLowerCase( Locale l )</td></tr></table>\n <p>versions instead.</p>", - "parentKey": null, - "repositoryKey": "findbugs", - "severity": "INFO", - "status": "READY", - "createdAt": "2013-12-04T10:24:09.000Z", - "updatedAt": "2013-12-12T15:19:59.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule719.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule719.json deleted file mode 100644 index 7dc6d03b585..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule719.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": 719, - "key": "com.puppycrawl.tools.checkstyle.checks.coding.DoubleCheckedLockingCheck", - "language": "java", - "name": "Double Checked Locking", - "description": null, - "parentKey": null, - "repositoryKey": "checkstyle", - "severity": "MAJOR", - "status": "READY", - "cardinality": "SINGLE", - "createdAt": "2013-07-04T07:38:05.543Z", - "updatedAt": "2013-03-27T08:52:40.370Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule759.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule759.json deleted file mode 100644 index ceecbbff6de..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule759.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": 759, - "key": "UnusedNullCheckInEquals", - "language": "java", - "name": "Unused Null Check In Equals", - "description": "After checking an object reference for null, you should invoke equals() on that object rather than passing it to another object's equals() method.", - "parentKey": null, - "repositoryKey": "pmd", - "severity": "MAJOR", - "status": "READY", - "createdAt": "2013-12-04T10:24:11.000Z", - "updatedAt": "2013-12-12T15:20:01.000Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule860.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule860.json deleted file mode 100644 index dc42767a299..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule860.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": 860, - "key": "Snippet", - "language": null, - "name": null, - "description": null, - "parentKey": null, - "repositoryKey": "squid", - "severity": "MAJOR", - "status": "REMOVED", - "cardinality": "MULTIPLE", - "createdAt": "2013-07-04T07:38:05.543Z", - "updatedAt": "2013-03-27T08:52:40.370Z" -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule944.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule944.json deleted file mode 100644 index a8a2d311d71..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileRuleLookupTest/shared/rule944.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": 944, - "key": "S1125", - "language": "java", - "name": "Boolean expressions should not be compared to true or false", - "description": "<p> Boolean expressions should not be compared against boolean literals, as their value can be directly used. </p> <p>The following code:</p> <pre> if (booleanVariable == true) { /* ... */ } // Non-Compliant if (booleanVariable != true) { /* ... */ } // Non-Compliant </pre> <p>should be refactored into:</p> <pre> if (booleanVariable) { /* ... */ } // Compliant if (!booleanVariable) { /* ... */ } // Compliant </pre>", - "parentKey": null, - "repositoryKey": "squid", - "severity": "MAJOR", - "status": "READY", - "cardinality": "SINGLE", - "createdAt": "2013-07-26T07:40:51.977Z", - "updatedAt": "2014-01-10T15:38:27.386Z" -} |