From: Sébastien Lesaint Date: Thu, 29 Aug 2019 11:47:54 +0000 (+0200) Subject: use testFixtures instead of test configuration of server-common X-Git-Tag: 8.0~177 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4d38fa7629eca0d394f00c638f766027cf289cdd;p=sonarqube.git use testFixtures instead of test configuration of server-common --- diff --git a/server/sonar-ce-common/build.gradle b/server/sonar-ce-common/build.gradle index c10f7b688e0..800286bde41 100644 --- a/server/sonar-ce-common/build.gradle +++ b/server/sonar-ce-common/build.gradle @@ -51,6 +51,5 @@ dependencies { testCompile 'org.assertj:assertj-guava' testCompile 'org.hamcrest:hamcrest-all' testCompile project(':sonar-plugin-api-impl') - testCompile testFixtures(project(':server:sonar-db-dao')) - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) } diff --git a/server/sonar-ce-task-projectanalysis/build.gradle b/server/sonar-ce-task-projectanalysis/build.gradle index 47e0a9999dd..e9eca578474 100644 --- a/server/sonar-ce-task-projectanalysis/build.gradle +++ b/server/sonar-ce-task-projectanalysis/build.gradle @@ -50,17 +50,15 @@ dependencies { testCompile 'com.google.code.findbugs:jsr305' testCompile 'com.tngtech.java:junit-dataprovider' - testCompile 'junit:junit' testCompile 'org.apache.logging.log4j:log4j-api' testCompile 'org.apache.logging.log4j:log4j-core' testCompile 'org.assertj:assertj-core' testCompile 'org.assertj:assertj-guava' testCompile 'org.mockito:mockito-core' testCompile 'org.reflections:reflections' - testCompile testFixtures(project(':server:sonar-db-dao')) testCompile project(':sonar-testing-harness') testCompile project(path: ":server:sonar-ce-task", configuration: "tests") - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) } task testJar(type: Jar) { diff --git a/server/sonar-server-common/build.gradle b/server/sonar-server-common/build.gradle index 284828db542..5e027f81878 100644 --- a/server/sonar-server-common/build.gradle +++ b/server/sonar-server-common/build.gradle @@ -6,12 +6,6 @@ sonarqube { } } -configurations { - tests - - testCompile.extendsFrom tests -} - dependencies { // please keep the list grouped by configuration and ordered by name @@ -32,10 +26,6 @@ dependencies { compileOnly 'com.google.code.findbugs:jsr305' - // "tests" dependencies are pulled by other modules which depends on "tests" configuration, "testCompile" are not pulled - tests 'org.codelibs.elasticsearch.module:analysis-common' - tests 'org.elasticsearch:mocksocket' - testCompile 'ch.qos.logback:logback-core' testCompile 'com.google.code.findbugs:jsr305' testCompile 'com.squareup.okhttp3:mockwebserver' @@ -51,13 +41,12 @@ dependencies { testCompile project(path: ':sonar-plugin-api', configuration: 'shadow') testCompile project(':sonar-plugin-api-impl') testCompile project(':sonar-testing-harness') -} + + testFixturesApi 'junit:junit' + testFixturesApi testFixtures(project(':server:sonar-db-dao')) -task testJar(type: Jar) { - classifier = 'tests' - from sourceSets.test.output -} + testFixturesCompileOnly 'com.google.code.findbugs:jsr305' -artifacts { - tests testJar + testFixturesImplementation 'org.codelibs.elasticsearch.module:analysis-common' + testFixturesImplementation 'org.elasticsearch:mocksocket' } diff --git a/server/sonar-server-common/src/test/java/org/elasticsearch/transport/MockTcpTransport.java b/server/sonar-server-common/src/test/java/org/elasticsearch/transport/MockTcpTransport.java deleted file mode 100644 index b5d89ef054d..00000000000 --- a/server/sonar-server-common/src/test/java/org/elasticsearch/transport/MockTcpTransport.java +++ /dev/null @@ -1,495 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.elasticsearch.transport; - -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.elasticsearch.Version; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.cli.SuppressForbidden; -import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.concurrent.CompletableContext; -import org.elasticsearch.common.io.stream.BytesStreamOutput; -import org.elasticsearch.common.io.stream.InputStreamStreamInput; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.io.stream.ReleasableBytesStreamOutput; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.ByteSizeValue; -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.CancellableThreads; -import org.elasticsearch.common.util.PageCacheRecycler; -import org.elasticsearch.common.util.concurrent.AbstractRunnable; -import org.elasticsearch.common.util.concurrent.EsExecutors; -import org.elasticsearch.core.internal.io.IOUtils; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.mocksocket.MockServerSocket; -import org.elasticsearch.mocksocket.MockSocket; -import org.elasticsearch.threadpool.ThreadPool; - -/** - * This is a socket based blocking TcpTransport implementation that is used for tests - * that need real networking. This implementation is a test only implementation that implements - * the networking layer in the worst possible way since it blocks and uses a thread per request model. - */ -public class MockTcpTransport extends TcpTransport { - private static final Logger logger = LogManager.getLogger(MockTcpTransport.class); - - /** - * A pre-built light connection profile that shares a single connection across all - * types. - */ - static final ConnectionProfile LIGHT_PROFILE; - - private final Set openChannels = new HashSet<>(); - - static { - ConnectionProfile.Builder builder = new ConnectionProfile.Builder(); - builder.addConnections(1, - TransportRequestOptions.Type.BULK, - TransportRequestOptions.Type.PING, - TransportRequestOptions.Type.RECOVERY, - TransportRequestOptions.Type.REG, - TransportRequestOptions.Type.STATE); - LIGHT_PROFILE = builder.build(); - } - - private final ExecutorService executor; - - public MockTcpTransport(Settings settings, ThreadPool threadPool, BigArrays bigArrays, - CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, - NetworkService networkService) { - this(settings, threadPool, bigArrays, circuitBreakerService, namedWriteableRegistry, networkService, Version.CURRENT); - } - - public MockTcpTransport(Settings settings, ThreadPool threadPool, BigArrays bigArrays, - CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, - NetworkService networkService, Version mockVersion) { - super("mock-tcp-transport", settings, mockVersion, threadPool, PageCacheRecycler.NON_RECYCLING_INSTANCE, circuitBreakerService, - namedWriteableRegistry, networkService); - // we have our own crazy cached threadpool this one is not bounded at all... - // using the ES thread factory here is crucial for tests otherwise disruption tests won't block that thread - executor = Executors.newCachedThreadPool(EsExecutors.daemonThreadFactory(settings, Transports.TEST_MOCK_TRANSPORT_THREAD_PREFIX)); - } - - @Override - protected MockChannel bind(final String name, InetSocketAddress address) throws IOException { - MockServerSocket socket = new MockServerSocket(); - socket.setReuseAddress(TransportSettings.TCP_REUSE_ADDRESS.get(settings)); - ByteSizeValue tcpReceiveBufferSize = TransportSettings.TCP_RECEIVE_BUFFER_SIZE.get(settings); - if (tcpReceiveBufferSize.getBytes() > 0) { - socket.setReceiveBufferSize(tcpReceiveBufferSize.bytesAsInt()); - } - socket.bind(address); - MockChannel serverMockChannel = new MockChannel(socket, name); - CountDownLatch started = new CountDownLatch(1); - executor.execute(new AbstractRunnable() { - @Override - public void onFailure(Exception e) { - onException(serverMockChannel, e); - } - - @Override - protected void doRun() throws Exception { - started.countDown(); - serverMockChannel.accept(executor); - } - }); - try { - started.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return serverMockChannel; - } - - private void readMessage(MockChannel mockChannel, StreamInput input) throws IOException { - Socket socket = mockChannel.activeChannel; - byte[] minimalHeader = new byte[TcpHeader.MARKER_BYTES_SIZE + TcpHeader.MESSAGE_LENGTH_SIZE]; - try { - input.readFully(minimalHeader); - } catch (EOFException eof) { - throw new IOException("Connection reset by peer"); - } - - // Read message length will throw stream corrupted exception if the marker bytes incorrect - int msgSize = TcpTransport.readMessageLength(new BytesArray(minimalHeader)); - if (msgSize == -1) { - socket.getOutputStream().flush(); - } else { - final byte[] buffer = new byte[msgSize]; - input.readFully(buffer); - int expectedSize = TcpHeader.MARKER_BYTES_SIZE + TcpHeader.MESSAGE_LENGTH_SIZE + msgSize; - try (BytesStreamOutput output = new ReleasableBytesStreamOutput(expectedSize, bigArrays)) { - output.write(minimalHeader); - output.write(buffer); - consumeNetworkReads(mockChannel, output.bytes()); - } - } - } - - @Override - @SuppressForbidden(reason = "real socket for mocking remote connections") - protected MockChannel initiateChannel(DiscoveryNode node) throws IOException { - InetSocketAddress address = node.getAddress().address(); - final MockSocket socket = new MockSocket(); - final MockChannel channel = new MockChannel(socket, address, false, "none"); - - boolean success = false; - try { - configureSocket(socket); - success = true; - } finally { - if (success == false) { - IOUtils.close(socket); - } - } - - executor.submit(() -> { - try { - socket.connect(address); - socket.setSoLinger(false, 0); - channel.connectFuture.complete(null); - channel.loopRead(executor); - } catch (Exception ex) { - channel.connectFuture.completeExceptionally(ex); - } - }); - - return channel; - } - - @Override - protected ConnectionProfile maybeOverrideConnectionProfile(ConnectionProfile connectionProfile) { - ConnectionProfile.Builder builder = new ConnectionProfile.Builder(); - Set allTypesWithConnection = new HashSet<>(); - Set allTypesWithoutConnection = new HashSet<>(); - for (ConnectionProfile.ConnectionTypeHandle handle : connectionProfile.getHandles()) { - Set types = handle.getTypes(); - if (handle.length > 0) { - allTypesWithConnection.addAll(types); - } else { - allTypesWithoutConnection.addAll(types); - } - } - // make sure we maintain at least the types that are supported by this profile even if we only use a single channel for them. - builder.addConnections(1, allTypesWithConnection.toArray(new TransportRequestOptions.Type[0])); - if (allTypesWithoutConnection.isEmpty() == false) { - builder.addConnections(0, allTypesWithoutConnection.toArray(new TransportRequestOptions.Type[0])); - } - builder.setHandshakeTimeout(connectionProfile.getHandshakeTimeout()); - builder.setConnectTimeout(connectionProfile.getConnectTimeout()); - builder.setPingInterval(connectionProfile.getPingInterval()); - builder.setCompressionEnabled(connectionProfile.getCompressionEnabled()); - return builder.build(); - } - - private void configureSocket(Socket socket) throws SocketException { - socket.setTcpNoDelay(TransportSettings.TCP_NO_DELAY.get(settings)); - ByteSizeValue tcpSendBufferSize = TransportSettings.TCP_SEND_BUFFER_SIZE.get(settings); - if (tcpSendBufferSize.getBytes() > 0) { - socket.setSendBufferSize(tcpSendBufferSize.bytesAsInt()); - } - ByteSizeValue tcpReceiveBufferSize = TransportSettings.TCP_RECEIVE_BUFFER_SIZE.get(settings); - if (tcpReceiveBufferSize.getBytes() > 0) { - socket.setReceiveBufferSize(tcpReceiveBufferSize.bytesAsInt()); - } - socket.setReuseAddress(TransportSettings.TCP_REUSE_ADDRESS.get(settings)); - } - - public final class MockChannel implements Closeable, TcpChannel, TcpServerChannel { - private final AtomicBoolean isOpen = new AtomicBoolean(true); - private final InetSocketAddress localAddress; - private final ServerSocket serverSocket; - private final Set workerChannels = Collections.newSetFromMap(new ConcurrentHashMap<>()); - private final Socket activeChannel; - private final boolean isServer; - private final String profile; - private final CancellableThreads cancellableThreads = new CancellableThreads(); - private final CompletableContext closeFuture = new CompletableContext<>(); - private final CompletableContext connectFuture = new CompletableContext<>(); - private final ChannelStats stats = new ChannelStats(); - - /** - * Constructs a new MockChannel instance intended for handling the actual incoming / outgoing traffic. - * - * @param socket The client socket. Mut not be null. - * @param localAddress Address associated with the corresponding local server socket. Must not be null. - * @param profile The associated profile name. - */ - MockChannel(Socket socket, InetSocketAddress localAddress, boolean isServer, String profile) { - this.localAddress = localAddress; - this.activeChannel = socket; - this.isServer = isServer; - this.serverSocket = null; - this.profile = profile; - synchronized (openChannels) { - openChannels.add(this); - } - } - - /** - * Constructs a new MockChannel instance intended for accepting requests. - * - * @param serverSocket The associated server socket. Must not be null. - * @param profile The associated profile name. - */ - MockChannel(ServerSocket serverSocket, String profile) { - this.localAddress = (InetSocketAddress) serverSocket.getLocalSocketAddress(); - this.serverSocket = serverSocket; - this.profile = profile; - this.isServer = false; - this.activeChannel = null; - synchronized (openChannels) { - openChannels.add(this); - } - } - - public void accept(Executor executor) throws IOException { - while (isOpen.get()) { - Socket incomingSocket = serverSocket.accept(); - MockChannel incomingChannel = null; - try { - configureSocket(incomingSocket); - synchronized (this) { - if (isOpen.get()) { - InetSocketAddress localAddress = new InetSocketAddress(incomingSocket.getLocalAddress(), - incomingSocket.getPort()); - incomingChannel = new MockChannel(incomingSocket, localAddress, true, profile); - MockChannel finalIncomingChannel = incomingChannel; - incomingChannel.addCloseListener(new ActionListener() { - @Override - public void onResponse(Void aVoid) { - workerChannels.remove(finalIncomingChannel); - } - - @Override - public void onFailure(Exception e) { - workerChannels.remove(finalIncomingChannel); - } - }); - serverAcceptedChannel(incomingChannel); - //establish a happens-before edge between closing and accepting a new connection - workerChannels.add(incomingChannel); - - // this spawns a new thread immediately, so OK under lock - incomingChannel.loopRead(executor); - // the channel is properly registered and will be cleared by the close code. - incomingSocket = null; - incomingChannel = null; - } - } - } finally { - // ensure we don't leak sockets and channels in the failure case. Note that we null both - // if there are no exceptions so this becomes a no op. - IOUtils.closeWhileHandlingException(incomingSocket, incomingChannel); - } - } - } - - void loopRead(Executor executor) { - executor.execute(new AbstractRunnable() { - @Override - public void onFailure(Exception e) { - if (isOpen.get()) { - try { - onException(MockChannel.this, e); - } catch (Exception ex) { - logger.warn("failed on handling exception", ex); - IOUtils.closeWhileHandlingException(MockChannel.this); // pure paranoia - } - } - } - - @Override - protected void doRun() throws Exception { - StreamInput input = new InputStreamStreamInput(new BufferedInputStream(activeChannel.getInputStream())); - // There is a (slim) chance that we get interrupted right after a loop iteration, so check explicitly - while (isOpen.get() && !Thread.currentThread().isInterrupted()) { - cancellableThreads.executeIO(() -> readMessage(MockChannel.this, input)); - } - } - }); - } - - synchronized void close0() throws IOException { - // establish a happens-before edge between closing and accepting a new connection - // we have to sync this entire block to ensure that our openChannels checks work correctly. - // The close block below will close all worker channels but if one of the worker channels runs into an exception - // for instance due to a disconnect the handling of this exception might be executed concurrently. - // now if we are in-turn concurrently call close we might not wait for the actual close to happen and that will, down the road - // make the assertion trip that not all channels are closed. - if (isOpen.compareAndSet(true, false)) { - final boolean removedChannel; - synchronized (openChannels) { - removedChannel = openChannels.remove(this); - } - IOUtils.close(serverSocket, activeChannel, () -> IOUtils.close(workerChannels), - () -> cancellableThreads.cancel("channel closed")); - assert removedChannel: "Channel was not removed or removed twice?"; - } - } - - @Override - public String toString() { - return "MockChannel{" + - "profile='" + profile + '\'' + - ", isOpen=" + isOpen + - ", localAddress=" + localAddress + - ", isServerSocket=" + (serverSocket != null) + - '}'; - } - - @Override - public void close() { - try { - close0(); - closeFuture.complete(null); - } catch (IOException e) { - closeFuture.completeExceptionally(e); - } - } - - @Override - public String getProfile() { - return profile; - } - - @Override - public boolean isServerChannel() { - return isServer; - } - - @Override - public void addCloseListener(ActionListener listener) { - closeFuture.addListener(ActionListener.toBiConsumer(listener)); - } - - @Override - public void addConnectListener(ActionListener listener) { - connectFuture.addListener(ActionListener.toBiConsumer(listener)); - } - - @Override - public ChannelStats getChannelStats() { - return stats; - } - - @Override - public boolean isOpen() { - return isOpen.get(); - } - - @Override - public InetSocketAddress getLocalAddress() { - return localAddress; - } - - @Override - public InetSocketAddress getRemoteAddress() { - return (InetSocketAddress) activeChannel.getRemoteSocketAddress(); - } - - @Override - public void sendMessage(BytesReference reference, ActionListener listener) { - try { - synchronized (this) { - OutputStream outputStream = new BufferedOutputStream(activeChannel.getOutputStream()); - reference.writeTo(outputStream); - outputStream.flush(); - } - listener.onResponse(null); - } catch (IOException e) { - listener.onFailure(e); - onException(this, e); - } - } - } - - - @Override - protected void doStart() { - boolean success = false; - try { - if (NetworkService.NETWORK_SERVER.get(settings)) { - // loop through all profiles and start them up, special handling for default one - for (ProfileSettings profileSettings : profileSettings) { - bindServer(profileSettings); - } - } - super.doStart(); - success = true; - } finally { - if (success == false) { - doStop(); - } - } - } - - @Override - protected void stopInternal() { - ThreadPool.terminate(executor, 10, TimeUnit.SECONDS); - synchronized (openChannels) { - assert openChannels.isEmpty() : "there are still open channels: " + openChannels; - } - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/EsTester.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/EsTester.java deleted file mode 100644 index 9d69c0413f3..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/EsTester.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.es; - -import com.google.common.base.Throwables; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.commons.lang.reflect.ConstructorUtils; -import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; -import org.elasticsearch.action.bulk.BulkRequestBuilder; -import org.elasticsearch.action.bulk.BulkResponse; -import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.support.master.AcknowledgedResponse; -import org.elasticsearch.analysis.common.CommonAnalysisPlugin; -import org.elasticsearch.cluster.health.ClusterHealthStatus; -import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings; -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.network.NetworkModule; -import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.PageCacheRecycler; -import org.elasticsearch.discovery.DiscoveryModule; -import org.elasticsearch.env.Environment; -import org.elasticsearch.env.NodeEnvironment; -import org.elasticsearch.index.IndexNotFoundException; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.TermQueryBuilder; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.indices.recovery.RecoverySettings; -import org.elasticsearch.join.ParentJoinPlugin; -import org.elasticsearch.node.InternalSettingsPreparer; -import org.elasticsearch.node.Node; -import org.elasticsearch.plugins.NetworkPlugin; -import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.MockTcpTransport; -import org.elasticsearch.transport.Transport; -import org.junit.rules.ExternalResource; -import org.sonar.server.component.index.ComponentIndexDefinition; -import org.sonar.server.es.IndexDefinition.IndexDefinitionContext; -import org.sonar.server.es.IndexType.IndexRelationType; -import org.sonar.server.es.newindex.BuiltIndex; -import org.sonar.server.es.newindex.NewIndex; -import org.sonar.server.issue.index.IssueIndexDefinition; -import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition; -import org.sonar.server.rule.index.RuleIndexDefinition; -import org.sonar.server.user.index.UserIndexDefinition; -import org.sonar.server.view.index.ViewIndexDefinition; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Lists.newArrayList; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; -import static org.sonar.server.es.Index.ALL_INDICES; -import static org.sonar.server.es.IndexType.FIELD_INDEX_TYPE; -import static org.sonar.server.es.newindex.DefaultIndexSettings.REFRESH_IMMEDIATE; - -public class EsTester extends ExternalResource { - - static { - System.setProperty("log4j.shutdownHookEnabled", "false"); - // we can not shutdown logging when tests are running or the next test that runs within the - // same JVM will try to initialize logging after a security manager has been installed and - // this will fail - System.setProperty("es.log4j.shutdownEnabled", "false"); - System.setProperty("log4j2.disable.jmx", "true"); - System.setProperty("log4j.skipJansi", "true"); // jython has this crazy shaded Jansi version that log4j2 tries to load - - if (!Strings.hasLength(System.getProperty("tests.es.logger.level"))) { - System.setProperty("tests.es.logger.level", "WARN"); - } - } - - private static final Node SHARED_NODE = createNode(); - private static final AtomicBoolean CORE_INDICES_CREATED = new AtomicBoolean(false); - private static final Set CORE_INDICES_NAMES = new HashSet<>(); - - private final boolean isCustom; - - private EsTester(boolean isCustom) { - this.isCustom = isCustom; - } - - /** - * New instance which contains the core indices (rules, issues, ...). - */ - public static EsTester create() { - if (!CORE_INDICES_CREATED.get()) { - List createdIndices = createIndices( - ComponentIndexDefinition.createForTest(), - IssueIndexDefinition.createForTest(), - ProjectMeasuresIndexDefinition.createForTest(), - RuleIndexDefinition.createForTest(), - UserIndexDefinition.createForTest(), - ViewIndexDefinition.createForTest()); - - CORE_INDICES_CREATED.set(true); - createdIndices.stream().map(t -> t.getMainType().getIndex().getName()).forEach(CORE_INDICES_NAMES::add); - } - return new EsTester(false); - } - - /** - * New instance which contains the specified indices. Note that - * core indices may exist. - */ - public static EsTester createCustom(IndexDefinition... definitions) { - createIndices(definitions); - return new EsTester(true); - } - - @Override - protected void after() { - if (isCustom) { - // delete non-core indices - String[] existingIndices = SHARED_NODE.client().admin().indices().prepareGetIndex().get().getIndices(); - Stream.of(existingIndices) - .filter(i -> !CORE_INDICES_NAMES.contains(i)) - .forEach(EsTester::deleteIndexIfExists); - } - BulkIndexer.delete(client(), IndexType.main(ALL_INDICES, "dummy"), client().prepareSearch(ALL_INDICES).setQuery(matchAllQuery())); - } - - public EsClient client() { - return new EsClient(SHARED_NODE.client()); - } - - public void putDocuments(IndexType indexType, BaseDoc... docs) { - try { - BulkRequestBuilder bulk = SHARED_NODE.client().prepareBulk() - .setRefreshPolicy(REFRESH_IMMEDIATE); - for (BaseDoc doc : docs) { - bulk.add(doc.toIndexRequest()); - } - BulkResponse bulkResponse = bulk.get(); - if (bulkResponse.hasFailures()) { - throw new IllegalStateException(bulkResponse.buildFailureMessage()); - } - } catch (Exception e) { - throw Throwables.propagate(e); - } - } - - public void putDocuments(IndexType indexType, Map... docs) { - try { - BulkRequestBuilder bulk = SHARED_NODE.client().prepareBulk() - .setRefreshPolicy(REFRESH_IMMEDIATE); - for (Map doc : docs) { - IndexType.IndexMainType mainType = indexType.getMainType(); - bulk.add(new IndexRequest(mainType.getIndex().getName(), mainType.getType()) - .source(doc)); - } - BulkResponse bulkResponse = bulk.get(); - if (bulkResponse.hasFailures()) { - throw new IllegalStateException(bulkResponse.buildFailureMessage()); - } - } catch (Exception e) { - throw Throwables.propagate(e); - } - } - - public long countDocuments(Index index) { - return client().prepareSearch(index) - .setQuery(matchAllQuery()) - .setSize(0).get().getHits().getTotalHits(); - } - - public long countDocuments(IndexType indexType) { - return client().prepareSearch(indexType.getMainType()) - .setQuery(getDocumentsQuery(indexType)) - .setSize(0).get().getHits().getTotalHits(); - } - - /** - * Get all the indexed documents (no paginated results). Results are converted to BaseDoc objects. - * Results are not sorted. - */ - public List getDocuments(IndexType indexType, final Class docClass) { - List hits = getDocuments(indexType); - return new ArrayList<>(Collections2.transform(hits, input -> { - try { - return (E) ConstructorUtils.invokeConstructor(docClass, input.getSourceAsMap()); - } catch (Exception e) { - throw Throwables.propagate(e); - } - })); - } - - /** - * Get all the indexed documents (no paginated results) in the specified index, whatever their type. Results are not sorted. - */ - public List getDocuments(Index index) { - SearchRequestBuilder req = SHARED_NODE.client() - .prepareSearch(index.getName()) - .setQuery(matchAllQuery()); - return getDocuments(req); - } - - /** - * Get all the indexed documents (no paginated results) of the specified type. Results are not sorted. - */ - public List getDocuments(IndexType indexType) { - IndexType.IndexMainType mainType = indexType.getMainType(); - SearchRequestBuilder req = SHARED_NODE.client() - .prepareSearch(mainType.getIndex().getName()) - .setQuery(getDocumentsQuery(indexType)); - return getDocuments(req); - } - - private List getDocuments(SearchRequestBuilder req) { - EsUtils.optimizeScrollRequest(req); - req.setScroll(new TimeValue(60000)) - .setSize(100); - - SearchResponse response = req.get(); - List result = newArrayList(); - while (true) { - Iterables.addAll(result, response.getHits()); - response = SHARED_NODE.client().prepareSearchScroll(response.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet(); - // Break condition: No hits are returned - if (response.getHits().getHits().length == 0) { - break; - } - } - return result; - } - - private QueryBuilder getDocumentsQuery(IndexType indexType) { - if (!indexType.getMainType().getIndex().acceptsRelations()) { - return matchAllQuery(); - } - - if (indexType instanceof IndexRelationType) { - return new TermQueryBuilder(FIELD_INDEX_TYPE, ((IndexRelationType) indexType).getName()); - } - if (indexType instanceof IndexType.IndexMainType) { - return new TermQueryBuilder(FIELD_INDEX_TYPE, ((IndexType.IndexMainType) indexType).getType()); - } - throw new IllegalArgumentException("Unsupported IndexType " + indexType.getClass()); - } - - /** - * Get a list of a specific field from all indexed documents. - */ - public List getDocumentFieldValues(IndexType indexType, final String fieldNameToReturn) { - return getDocuments(indexType) - .stream() - .map(input -> (T) input.getSourceAsMap().get(fieldNameToReturn)) - .collect(Collectors.toList()); - } - - public List getIds(IndexType indexType) { - return getDocuments(indexType).stream().map(SearchHit::getId).collect(Collectors.toList()); - } - - public void lockWrites(IndexType index) { - setIndexSettings(index.getMainType().getIndex().getName(), ImmutableMap.of("index.blocks.write", "true")); - } - - public void unlockWrites(IndexType index) { - setIndexSettings(index.getMainType().getIndex().getName(), ImmutableMap.of("index.blocks.write", "false")); - } - - private void setIndexSettings(String index, Map settings) { - AcknowledgedResponse response = SHARED_NODE.client().admin().indices() - .prepareUpdateSettings(index) - .setSettings(settings) - .get(); - checkState(response.isAcknowledged()); - } - - private static void deleteIndexIfExists(String name) { - try { - AcknowledgedResponse response = SHARED_NODE.client().admin().indices().prepareDelete(name).get(); - checkState(response.isAcknowledged(), "Fail to drop the index " + name); - } catch (IndexNotFoundException e) { - // ignore - } - } - - private static List createIndices(IndexDefinition... definitions) { - IndexDefinitionContext context = new IndexDefinitionContext(); - Stream.of(definitions).forEach(d -> d.define(context)); - - List result = new ArrayList<>(); - for (NewIndex newIndex : context.getIndices().values()) { - BuiltIndex index = newIndex.build(); - - String indexName = index.getMainType().getIndex().getName(); - deleteIndexIfExists(indexName); - - // create index - Settings.Builder settings = Settings.builder(); - settings.put(index.getSettings()); - CreateIndexResponse indexResponse = SHARED_NODE.client().admin().indices() - .prepareCreate(indexName) - .setSettings(settings) - .get(); - if (!indexResponse.isAcknowledged()) { - throw new IllegalStateException("Failed to create index " + indexName); - } - SHARED_NODE.client().admin().cluster().prepareHealth(indexName).setWaitForStatus(ClusterHealthStatus.YELLOW).get(); - - // create types - String typeName = index.getMainType().getType(); - AcknowledgedResponse mappingResponse = SHARED_NODE.client().admin().indices().preparePutMapping(indexName) - .setType(typeName) - .setSource(index.getAttributes()) - .get(); - if (!mappingResponse.isAcknowledged()) { - throw new IllegalStateException("Failed to create type " + typeName); - } - SHARED_NODE.client().admin().cluster().prepareHealth(indexName).setWaitForStatus(ClusterHealthStatus.YELLOW).get(); - result.add(index); - } - return result; - } - - private static Node createNode() { - try { - Path tempDir = Files.createTempDirectory("EsTester"); - tempDir.toFile().deleteOnExit(); - Settings settings = Settings.builder() - .put(Environment.PATH_HOME_SETTING.getKey(), tempDir) - .put("node.name", "EsTester") - .put(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey(), Integer.MAX_VALUE) - .put("logger.level", "INFO") - .put("action.auto_create_index", false) - // Default the watermarks to absurdly low to prevent the tests - // from failing on nodes without enough disk space - .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING.getKey(), "1b") - .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK_SETTING.getKey(), "1b") - .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_DISK_FLOOD_STAGE_WATERMARK_SETTING.getKey(), "1b") - // always reduce this - it can make tests really slow - .put(RecoverySettings.INDICES_RECOVERY_RETRY_DELAY_STATE_SYNC_SETTING.getKey(), TimeValue.timeValueMillis(20)) - .put(NetworkModule.TRANSPORT_TYPE_KEY, "local") - .put(NetworkModule.HTTP_ENABLED.getKey(), false) - .put(DiscoveryModule.DISCOVERY_TYPE_SETTING.getKey(), "single-node") - .build(); - Node node = new Node(InternalSettingsPreparer.prepareEnvironment(settings, null), - ImmutableList.of( - CommonAnalysisPlugin.class, - // mock local transport plugin - MockTcpTransportPlugin.class, - // install ParentJoin plugin required to create field of type "join" - ParentJoinPlugin.class), - true) { - @Override - protected void registerDerivedNodeNameWithLogger(String nodeName) { - // nothing to do - } - }; - return node.start(); - } catch (Exception e) { - throw new IllegalStateException("Fail to start embedded Elasticsearch", e); - } - } - - public static final class MockTcpTransportPlugin extends Plugin implements NetworkPlugin { - @Override - public Map> getTransports(Settings settings, ThreadPool threadPool, PageCacheRecycler pageCacheRecycler, - CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) { - return Collections.singletonMap( - "local", - () -> new MockTcpTransport(settings, threadPool, BigArrays.NON_RECYCLING_INSTANCE, circuitBreakerService, namedWriteableRegistry, networkService)); - } - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/FakeDoc.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/FakeDoc.java deleted file mode 100644 index d199ed9323a..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/FakeDoc.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.es; - -import com.google.common.collect.Maps; - -import static org.sonar.server.es.newindex.FakeIndexDefinition.INT_FIELD; -import static org.sonar.server.es.newindex.FakeIndexDefinition.TYPE_FAKE; - -public class FakeDoc extends BaseDoc { - public FakeDoc() { - super(TYPE_FAKE, Maps.newHashMap()); - } - - @Override - public String getId() { - return null; - } - - public int getInt() { - return getField(INT_FIELD); - } - - public FakeDoc setInt(int i) { - setField(INT_FIELD, i); - return this; - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/TestProjectIndexers.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/TestProjectIndexers.java deleted file mode 100644 index fb858911533..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/TestProjectIndexers.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.es; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ListMultimap; -import java.util.Collection; -import org.sonar.db.DbSession; - -public class TestProjectIndexers implements ProjectIndexers { - - private final ListMultimap calls = ArrayListMultimap.create(); - - @Override - public void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { - dbSession.commit(); - projectUuids.forEach(projectUuid -> calls.put(projectUuid, cause)); - - } - - public boolean hasBeenCalled(String projectUuid, ProjectIndexer.Cause expectedCause) { - return calls.get(projectUuid).contains(expectedCause); - } - - public boolean hasBeenCalled(String projectUuid) { - return calls.containsKey(projectUuid); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/newindex/FakeIndexDefinition.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/newindex/FakeIndexDefinition.java deleted file mode 100644 index d6dfd760540..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/newindex/FakeIndexDefinition.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.es.newindex; - -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.server.es.FakeDoc; -import org.sonar.server.es.Index; -import org.sonar.server.es.IndexDefinition; -import org.sonar.server.es.IndexType; -import org.sonar.server.es.IndexType.IndexMainType; - -import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder; - -public class FakeIndexDefinition implements IndexDefinition { - - public static final String INDEX = "fakes"; - public static final String TYPE = "fake"; - public static final Index DESCRIPTOR = Index.simple(INDEX); - public static final IndexMainType TYPE_FAKE = IndexType.main(DESCRIPTOR, TYPE); - public static final String INT_FIELD = "intField"; - - private int replicas = 0; - - public FakeIndexDefinition setReplicas(int replicas) { - this.replicas = replicas; - return this; - } - - @Override - public void define(IndexDefinitionContext context) { - NewIndex index = context.create(DESCRIPTOR, newBuilder(new MapSettings().asConfig()).build()); - index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, replicas); - index.getSettings().put("index.refresh_interval", "-1"); - index.createTypeMapping(TYPE_FAKE) - .createIntegerField(INT_FIELD); - } - - public static FakeDoc newDoc(int value) { - return new FakeDoc().setInt(value); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java deleted file mode 100644 index 60ddbdbde5b..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.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.es.textsearch; - -import org.junit.rules.ExternalResource; - -public class ComponentTextSearchFeatureRule extends ExternalResource { - - private ComponentTextSearchFeature[] features; - - @Override - protected void before() { - features = ComponentTextSearchFeatureRepertoire.values(); - } - - public ComponentTextSearchFeature[] get() { - return features; - } - - public void set(ComponentTextSearchFeature... features) { - this.features = features; - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueDocTesting.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueDocTesting.java deleted file mode 100644 index c63f12e950c..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueDocTesting.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.issue; - -import com.google.common.collect.Maps; -import java.util.Date; -import org.sonar.api.resources.Scopes; -import org.sonar.api.rule.Severity; -import org.sonar.api.rules.RuleType; -import org.sonar.core.util.Uuids; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.issue.index.IssueDoc; - -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.apache.commons.lang.math.RandomUtils.nextInt; -import static org.sonar.api.issue.Issue.STATUS_OPEN; - -public class IssueDocTesting { - - public static IssueDoc newDoc(ComponentDto componentDto) { - return newDoc(Uuids.createFast(), componentDto); - } - - public static IssueDoc newDoc(String key, ComponentDto componentDto) { - String mainBranchProjectUuid = componentDto.getMainBranchProjectUuid(); - return newDoc() - .setKey(key) - .setBranchUuid(componentDto.projectUuid()) - .setComponentUuid(componentDto.uuid()) - .setModuleUuid(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.moduleUuid() : componentDto.uuid()) - .setModuleUuidPath(componentDto.moduleUuidPath()) - .setProjectUuid(mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid) - .setOrganizationUuid(componentDto.getOrganizationUuid()) - // File path make no sens on modules and projects - .setFilePath(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.path() : null) - .setIsMainBranch(mainBranchProjectUuid == null); - } - - public static IssueDoc newDoc() { - IssueDoc doc = new IssueDoc(Maps.newHashMap()); - doc.setKey(Uuids.createFast()); - doc.setRuleId(nextInt(1000)); - doc.setType(RuleType.CODE_SMELL); - doc.setAssigneeUuid("assignee_uuid_" + randomAlphabetic(26)); - doc.setAuthorLogin("author_" + randomAlphabetic(5)); - doc.setLanguage("language_" + randomAlphabetic(5)); - doc.setComponentUuid(Uuids.createFast()); - doc.setFilePath("filePath_" + randomAlphabetic(5)); - doc.setDirectoryPath("directory_" + randomAlphabetic(5)); - doc.setModuleUuid(Uuids.createFast()); - doc.setModuleUuidPath(Uuids.createFast()); - doc.setProjectUuid(Uuids.createFast()); - doc.setLine(nextInt(1_000) + 1); - doc.setStatus(STATUS_OPEN); - doc.setResolution(null); - doc.setSeverity(Severity.ALL.get(nextInt(Severity.ALL.size()))); - doc.setEffort((long) nextInt(10)); - doc.setFuncCreationDate(new Date(System.currentTimeMillis() - 2_000)); - doc.setFuncUpdateDate(new Date(System.currentTimeMillis() - 1_000)); - doc.setFuncCloseDate(null); - return doc; - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/IssuesChangesNotificationBuilderTesting.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/IssuesChangesNotificationBuilderTesting.java deleted file mode 100644 index 43f5cbfd5a2..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/IssuesChangesNotificationBuilderTesting.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this 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.notification; - -import java.util.Random; -import org.sonar.api.rule.RuleKey; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.rule.RuleDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.AnalysisChange; -import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.ChangedIssue; -import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.Project; -import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.Rule; -import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.User; -import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.UserChange; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; - -public class IssuesChangesNotificationBuilderTesting { - - public static Rule ruleOf(RuleDto rule) { - return new Rule(rule.getKey(), rule.getName()); - } - - public static Rule ruleOf(RuleDefinitionDto rule) { - return new Rule(rule.getKey(), rule.getName()); - } - - public static User userOf(UserDto changeAuthor) { - return new User(changeAuthor.getUuid(), changeAuthor.getLogin(), changeAuthor.getName()); - } - - public static Project projectBranchOf(DbTester db, ComponentDto branch) { - BranchDto branchDto = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()).get(); - checkArgument(!branchDto.isMain(), "should be a branch"); - return new Project.Builder(branch.uuid()) - .setKey(branch.getKey()) - .setProjectName(branch.name()) - .setBranchName(branchDto.getKey()) - .build(); - } - - public static Project projectOf(ComponentDto project) { - return new Project.Builder(project.uuid()) - .setKey(project.getKey()) - .setProjectName(project.name()) - .build(); - } - - static ChangedIssue newChangedIssue(String key, Project project, Rule rule) { - return new ChangedIssue.Builder(key) - .setNewStatus(randomAlphabetic(19)) - .setProject(project) - .setRule(rule) - .build(); - } - - static ChangedIssue newChangedIssue(String key, String status, Project project, String ruleName) { - return newChangedIssue(key, status, project, newRule(ruleName)); - } - - static ChangedIssue newChangedIssue(String key, String status, Project project, Rule rule) { - return new ChangedIssue.Builder(key) - .setNewStatus(status) - .setProject(project) - .setRule(rule) - .build(); - } - - static Rule newRule(String ruleName) { - return new Rule(RuleKey.of(randomAlphabetic(6), randomAlphabetic(7)), ruleName); - } - - static Project newProject(String uuid) { - return new Project.Builder(uuid).setProjectName(uuid + "_name").setKey(uuid + "_key").build(); - } - - static Project newBranch(String uuid, String branchName) { - return new Project.Builder(uuid).setProjectName(uuid + "_name").setKey(uuid + "_key").setBranchName(branchName).build(); - } - - static UserChange newUserChange() { - return new UserChange(new Random().nextLong(), new User(randomAlphabetic(4), randomAlphabetic(5), randomAlphabetic(6))); - } - - static AnalysisChange newAnalysisChange() { - return new AnalysisChange(new Random().nextLong()); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/l18n/I18nRule.java b/server/sonar-server-common/src/test/java/org/sonar/server/l18n/I18nRule.java deleted file mode 100644 index f81a2f09b45..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/l18n/I18nRule.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.l18n; - -import java.text.MessageFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; -import org.sonar.core.i18n.I18n; - -public class I18nRule implements TestRule, I18n { - private final Map messages = new HashMap<>(); - - public I18nRule put(String key, String value) { - messages.put(key, value); - return this; - } - - @Override - public Statement apply(final Statement statement, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - statement.evaluate(); - } finally { - messages.clear(); - } - } - }; - } - - public void setProjectPermissions() { - put("projects_role.admin", "Administer"); - put("projects_role.admin.desc", "Ability to access project settings and perform administration tasks. " + - "(Users will also need \"Browse\" permission)"); - put("projects_role.issueadmin", "Administer Issues"); - put("projects_role.issueadmin.desc", "Grants the permission to perform advanced editing on issues: marking an issue " + - "False Positive / Won't Fix or changing an Issue's severity. (Users will also need \"Browse\" permission)"); - put("projects_role.securityhotspotadmin", "Administer Security Hotspots"); - put("projects_role.securityhotspotadmin.desc", "Detect a Vulnerability from a \"Security Hotspot\". Reject, clear, accept, reopen a \"Security Hotspot\" (users also need \"Browse\" permissions)."); - put("projects_role.applicationcreator", "Create Applications"); - put("projects_role.applicationcreator.desc", "Allow to create applications for non system administrator."); - put("projects_role.portfoliocreator", "Create Portfolios"); - put("projects_role.portfoliocreator.desc", "Allow to create portfolios for non system administrator."); - put("projects_role.user", "Browse"); - put("projects_role.user.desc", "Ability to access a project, browse its measures, and create/edit issues for it."); - put("projects_role.codeviewer", "See Source Code"); - put("projects_role.codeviewer.desc", "Ability to view the project's source code. (Users will also need \"Browse\" permission)"); - put("projects_role.scan", "Execute Analysis"); - put("projects_role.scan.desc", - "Ability to execute analyses, and to get all settings required to perform the analysis, even the secured ones like the scm account password, the jira account password, and so on."); - } - - @Override - public String message(Locale locale, String key, @Nullable String defaultValue, Object... parameters) { - String messageInMap = messages.get(key); - String message = messageInMap != null ? messageInMap : defaultValue; - return formatMessage(message, parameters); - } - - @CheckForNull - private static String formatMessage(@Nullable String message, Object... parameters) { - if (message == null || parameters.length == 0) { - return message; - } - return MessageFormat.format(message.replaceAll("'", "''"), parameters); - } - - @Override - public String age(Locale locale, long durationInMillis) { - throw new UnsupportedOperationException(); - } - - @Override - public String age(Locale locale, Date fromDate, Date toDate) { - throw new UnsupportedOperationException(); - } - - @Override - public String ageFromNow(Locale locale, Date date) { - throw new UnsupportedOperationException(); - } - - @Override - public String formatDateTime(Locale locale, Date date) { - throw new UnsupportedOperationException(); - } - - @Override - public String formatDate(Locale locale, Date date) { - throw new UnsupportedOperationException(); - } - - @Override - public String formatDouble(Locale locale, Double value) { - return String.valueOf(value); - } - - @Override - public String formatInteger(Locale locale, Integer value) { - return String.valueOf(value); - } - -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/organization/TestDefaultOrganizationProvider.java b/server/sonar-server-common/src/test/java/org/sonar/server/organization/TestDefaultOrganizationProvider.java deleted file mode 100644 index a5b52317a37..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/organization/TestDefaultOrganizationProvider.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.organization; - -import java.util.Date; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; - -public class TestDefaultOrganizationProvider implements DefaultOrganizationProvider { - - private final DefaultOrganizationProvider delegate; - - private TestDefaultOrganizationProvider(DefaultOrganizationProvider delegate) { - this.delegate = delegate; - } - - public static TestDefaultOrganizationProvider from(DbTester dbTester) { - return new TestDefaultOrganizationProvider(new DbTesterDefaultOrganizationProvider(dbTester)); - } - - public static TestDefaultOrganizationProvider fromUuid(String uuid) { - long createdAt = new Date().getTime(); - return new TestDefaultOrganizationProvider( - new ImmutableDefaultOrganizationProvider( - DefaultOrganization.newBuilder() - .setUuid(uuid) - .setKey("key_" + uuid) - .setName("name_" + uuid) - .setCreatedAt(createdAt) - .setUpdatedAt(createdAt) - .build())); - } - - @Override - public DefaultOrganization get() { - return delegate.get(); - } - - private static final class ImmutableDefaultOrganizationProvider implements DefaultOrganizationProvider { - private final DefaultOrganization defaultOrganization; - - private ImmutableDefaultOrganizationProvider(DefaultOrganization defaultOrganization) { - this.defaultOrganization = defaultOrganization; - } - - @Override - public DefaultOrganization get() { - return defaultOrganization; - } - } - - private static final class DbTesterDefaultOrganizationProvider implements DefaultOrganizationProvider { - private final DbTester dbTester; - private DefaultOrganization defaultOrganization = null; - - private DbTesterDefaultOrganizationProvider(DbTester dbTester) { - this.dbTester = dbTester; - } - - @Override - public DefaultOrganization get() { - if (defaultOrganization == null) { - defaultOrganization = toDefaultOrganization(dbTester.getDefaultOrganization()); - } - return defaultOrganization; - } - - private static DefaultOrganization toDefaultOrganization(OrganizationDto organizationDto) { - return DefaultOrganization.newBuilder() - .setUuid(organizationDto.getUuid()) - .setKey(organizationDto.getKey()) - .setName(organizationDto.getName()) - .setCreatedAt(organizationDto.getCreatedAt()) - .setUpdatedAt(organizationDto.getUpdatedAt()) - .build(); - } - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/organization/TestOrganizationFlags.java b/server/sonar-server-common/src/test/java/org/sonar/server/organization/TestOrganizationFlags.java deleted file mode 100644 index f5a6d71cd33..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/organization/TestOrganizationFlags.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.organization; - -import java.util.concurrent.atomic.AtomicBoolean; -import org.sonar.db.DbSession; - -import static org.sonar.server.organization.OrganizationFlagsImpl.FAILURE_MESSAGE_DISABLED; -import static org.sonar.server.organization.OrganizationFlagsImpl.FAILURE_MESSAGE_ENABLED; - -public class TestOrganizationFlags implements OrganizationFlags { - - private final AtomicBoolean enabled = new AtomicBoolean(false); - - private TestOrganizationFlags() { - } - - @Override - public boolean isEnabled(DbSession dbSession) { - return enabled.get(); - } - - public TestOrganizationFlags setEnabled(boolean b) { - this.enabled.set(b); - return this; - } - - @Override - public void enable(DbSession dbSession) { - setEnabled(true); - } - - @Override - public void checkEnabled(DbSession dbSession) { - if (!isEnabled(dbSession)) { - throw new IllegalStateException(FAILURE_MESSAGE_DISABLED); - } - } - - @Override - public void checkDisabled(DbSession dbSession) { - if (isEnabled(dbSession)) { - throw new IllegalStateException(FAILURE_MESSAGE_ENABLED); - } - } - - /** - * By default Organization support is disabled - */ - public static TestOrganizationFlags standalone() { - return new TestOrganizationFlags(); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/SystemInfoTesting.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/SystemInfoTesting.java deleted file mode 100644 index a438af791b9..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/SystemInfoTesting.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.monitoring; - -import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.process.systeminfo.SystemInfoUtils.attribute; - -public class SystemInfoTesting { - - private SystemInfoTesting() { - // do not instantiate - } - - public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, String expectedValue) { - ProtobufSystemInfo.Attribute value = attribute(section, key); - assertThat(value).as(key).isNotNull(); - assertThat(value.getStringValue()).isEqualTo(expectedValue); - } - - public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, boolean expectedValue) { - ProtobufSystemInfo.Attribute value = attribute(section, key); - assertThat(value).as(key).isNotNull(); - assertThat(value.getBooleanValue()).isEqualTo(expectedValue); - } - - public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, long expectedValue) { - ProtobufSystemInfo.Attribute value = attribute(section, key); - assertThat(value).as(key).isNotNull(); - assertThat(value.getLongValue()).isEqualTo(expectedValue); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java deleted file mode 100644 index 534c0f5df46..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.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.platform.monitoring.cluster; - -import org.sonar.process.systeminfo.Global; -import org.sonar.process.systeminfo.SystemInfoSection; -import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - -class TestGlobalSystemInfoSection implements SystemInfoSection, Global { - private final String name; - - TestGlobalSystemInfoSection(String name) { - this.name = name; - } - - @Override - public ProtobufSystemInfo.Section toProtobuf() { - return ProtobufSystemInfo.Section.newBuilder().setName(name).build(); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java deleted file mode 100644 index 0ae8b3aec57..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.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.platform.monitoring.cluster; - -import org.sonar.process.systeminfo.SystemInfoSection; -import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - -class TestSystemInfoSection implements SystemInfoSection { - private final String name; - - TestSystemInfoSection(String name) { - this.name = name; - } - - @Override - public ProtobufSystemInfo.Section toProtobuf() { - return ProtobufSystemInfo.Section.newBuilder().setName(name).build(); - } -} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/source/index/FileSourceTesting.java b/server/sonar-server-common/src/test/java/org/sonar/server/source/index/FileSourceTesting.java deleted file mode 100644 index 86624383dc4..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/source/index/FileSourceTesting.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.source.index; - -import java.util.Arrays; -import org.sonar.db.protobuf.DbFileSources; - -public class FileSourceTesting { - - private FileSourceTesting() { - // only static stuff - } - - /** - * Generate predefined fake data. Result is mutable. - */ - public static DbFileSources.Data.Builder newFakeData(int numberOfLines) { - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - for (int i = 1; i <= numberOfLines; i++) { - dataBuilder.addLinesBuilder() - .setLine(i) - .setScmRevision("REVISION_" + i) - .setScmAuthor("AUTHOR_" + i) - .setScmDate(1_500_000_000_00L + i) - .setSource("SOURCE_" + i) - .setLineHits(i) - .setConditions(i + 1) - .setCoveredConditions(i + 2) - .setHighlighting("HIGHLIGHTING_" + i) - .setSymbols("SYMBOLS_" + i) - .addAllDuplication(Arrays.asList(i)) - .setIsNewLine(true) - .build(); - } - return dataBuilder; - } - -} diff --git a/server/sonar-server-common/src/testFixtures/java/org/elasticsearch/transport/MockTcpTransport.java b/server/sonar-server-common/src/testFixtures/java/org/elasticsearch/transport/MockTcpTransport.java new file mode 100644 index 00000000000..b5d89ef054d --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/elasticsearch/transport/MockTcpTransport.java @@ -0,0 +1,495 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.elasticsearch.transport; + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.EOFException; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.Version; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.cli.SuppressForbidden; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.concurrent.CompletableContext; +import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.io.stream.InputStreamStreamInput; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.ReleasableBytesStreamOutput; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.network.NetworkService; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.CancellableThreads; +import org.elasticsearch.common.util.PageCacheRecycler; +import org.elasticsearch.common.util.concurrent.AbstractRunnable; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.core.internal.io.IOUtils; +import org.elasticsearch.indices.breaker.CircuitBreakerService; +import org.elasticsearch.mocksocket.MockServerSocket; +import org.elasticsearch.mocksocket.MockSocket; +import org.elasticsearch.threadpool.ThreadPool; + +/** + * This is a socket based blocking TcpTransport implementation that is used for tests + * that need real networking. This implementation is a test only implementation that implements + * the networking layer in the worst possible way since it blocks and uses a thread per request model. + */ +public class MockTcpTransport extends TcpTransport { + private static final Logger logger = LogManager.getLogger(MockTcpTransport.class); + + /** + * A pre-built light connection profile that shares a single connection across all + * types. + */ + static final ConnectionProfile LIGHT_PROFILE; + + private final Set openChannels = new HashSet<>(); + + static { + ConnectionProfile.Builder builder = new ConnectionProfile.Builder(); + builder.addConnections(1, + TransportRequestOptions.Type.BULK, + TransportRequestOptions.Type.PING, + TransportRequestOptions.Type.RECOVERY, + TransportRequestOptions.Type.REG, + TransportRequestOptions.Type.STATE); + LIGHT_PROFILE = builder.build(); + } + + private final ExecutorService executor; + + public MockTcpTransport(Settings settings, ThreadPool threadPool, BigArrays bigArrays, + CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, + NetworkService networkService) { + this(settings, threadPool, bigArrays, circuitBreakerService, namedWriteableRegistry, networkService, Version.CURRENT); + } + + public MockTcpTransport(Settings settings, ThreadPool threadPool, BigArrays bigArrays, + CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, + NetworkService networkService, Version mockVersion) { + super("mock-tcp-transport", settings, mockVersion, threadPool, PageCacheRecycler.NON_RECYCLING_INSTANCE, circuitBreakerService, + namedWriteableRegistry, networkService); + // we have our own crazy cached threadpool this one is not bounded at all... + // using the ES thread factory here is crucial for tests otherwise disruption tests won't block that thread + executor = Executors.newCachedThreadPool(EsExecutors.daemonThreadFactory(settings, Transports.TEST_MOCK_TRANSPORT_THREAD_PREFIX)); + } + + @Override + protected MockChannel bind(final String name, InetSocketAddress address) throws IOException { + MockServerSocket socket = new MockServerSocket(); + socket.setReuseAddress(TransportSettings.TCP_REUSE_ADDRESS.get(settings)); + ByteSizeValue tcpReceiveBufferSize = TransportSettings.TCP_RECEIVE_BUFFER_SIZE.get(settings); + if (tcpReceiveBufferSize.getBytes() > 0) { + socket.setReceiveBufferSize(tcpReceiveBufferSize.bytesAsInt()); + } + socket.bind(address); + MockChannel serverMockChannel = new MockChannel(socket, name); + CountDownLatch started = new CountDownLatch(1); + executor.execute(new AbstractRunnable() { + @Override + public void onFailure(Exception e) { + onException(serverMockChannel, e); + } + + @Override + protected void doRun() throws Exception { + started.countDown(); + serverMockChannel.accept(executor); + } + }); + try { + started.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return serverMockChannel; + } + + private void readMessage(MockChannel mockChannel, StreamInput input) throws IOException { + Socket socket = mockChannel.activeChannel; + byte[] minimalHeader = new byte[TcpHeader.MARKER_BYTES_SIZE + TcpHeader.MESSAGE_LENGTH_SIZE]; + try { + input.readFully(minimalHeader); + } catch (EOFException eof) { + throw new IOException("Connection reset by peer"); + } + + // Read message length will throw stream corrupted exception if the marker bytes incorrect + int msgSize = TcpTransport.readMessageLength(new BytesArray(minimalHeader)); + if (msgSize == -1) { + socket.getOutputStream().flush(); + } else { + final byte[] buffer = new byte[msgSize]; + input.readFully(buffer); + int expectedSize = TcpHeader.MARKER_BYTES_SIZE + TcpHeader.MESSAGE_LENGTH_SIZE + msgSize; + try (BytesStreamOutput output = new ReleasableBytesStreamOutput(expectedSize, bigArrays)) { + output.write(minimalHeader); + output.write(buffer); + consumeNetworkReads(mockChannel, output.bytes()); + } + } + } + + @Override + @SuppressForbidden(reason = "real socket for mocking remote connections") + protected MockChannel initiateChannel(DiscoveryNode node) throws IOException { + InetSocketAddress address = node.getAddress().address(); + final MockSocket socket = new MockSocket(); + final MockChannel channel = new MockChannel(socket, address, false, "none"); + + boolean success = false; + try { + configureSocket(socket); + success = true; + } finally { + if (success == false) { + IOUtils.close(socket); + } + } + + executor.submit(() -> { + try { + socket.connect(address); + socket.setSoLinger(false, 0); + channel.connectFuture.complete(null); + channel.loopRead(executor); + } catch (Exception ex) { + channel.connectFuture.completeExceptionally(ex); + } + }); + + return channel; + } + + @Override + protected ConnectionProfile maybeOverrideConnectionProfile(ConnectionProfile connectionProfile) { + ConnectionProfile.Builder builder = new ConnectionProfile.Builder(); + Set allTypesWithConnection = new HashSet<>(); + Set allTypesWithoutConnection = new HashSet<>(); + for (ConnectionProfile.ConnectionTypeHandle handle : connectionProfile.getHandles()) { + Set types = handle.getTypes(); + if (handle.length > 0) { + allTypesWithConnection.addAll(types); + } else { + allTypesWithoutConnection.addAll(types); + } + } + // make sure we maintain at least the types that are supported by this profile even if we only use a single channel for them. + builder.addConnections(1, allTypesWithConnection.toArray(new TransportRequestOptions.Type[0])); + if (allTypesWithoutConnection.isEmpty() == false) { + builder.addConnections(0, allTypesWithoutConnection.toArray(new TransportRequestOptions.Type[0])); + } + builder.setHandshakeTimeout(connectionProfile.getHandshakeTimeout()); + builder.setConnectTimeout(connectionProfile.getConnectTimeout()); + builder.setPingInterval(connectionProfile.getPingInterval()); + builder.setCompressionEnabled(connectionProfile.getCompressionEnabled()); + return builder.build(); + } + + private void configureSocket(Socket socket) throws SocketException { + socket.setTcpNoDelay(TransportSettings.TCP_NO_DELAY.get(settings)); + ByteSizeValue tcpSendBufferSize = TransportSettings.TCP_SEND_BUFFER_SIZE.get(settings); + if (tcpSendBufferSize.getBytes() > 0) { + socket.setSendBufferSize(tcpSendBufferSize.bytesAsInt()); + } + ByteSizeValue tcpReceiveBufferSize = TransportSettings.TCP_RECEIVE_BUFFER_SIZE.get(settings); + if (tcpReceiveBufferSize.getBytes() > 0) { + socket.setReceiveBufferSize(tcpReceiveBufferSize.bytesAsInt()); + } + socket.setReuseAddress(TransportSettings.TCP_REUSE_ADDRESS.get(settings)); + } + + public final class MockChannel implements Closeable, TcpChannel, TcpServerChannel { + private final AtomicBoolean isOpen = new AtomicBoolean(true); + private final InetSocketAddress localAddress; + private final ServerSocket serverSocket; + private final Set workerChannels = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Socket activeChannel; + private final boolean isServer; + private final String profile; + private final CancellableThreads cancellableThreads = new CancellableThreads(); + private final CompletableContext closeFuture = new CompletableContext<>(); + private final CompletableContext connectFuture = new CompletableContext<>(); + private final ChannelStats stats = new ChannelStats(); + + /** + * Constructs a new MockChannel instance intended for handling the actual incoming / outgoing traffic. + * + * @param socket The client socket. Mut not be null. + * @param localAddress Address associated with the corresponding local server socket. Must not be null. + * @param profile The associated profile name. + */ + MockChannel(Socket socket, InetSocketAddress localAddress, boolean isServer, String profile) { + this.localAddress = localAddress; + this.activeChannel = socket; + this.isServer = isServer; + this.serverSocket = null; + this.profile = profile; + synchronized (openChannels) { + openChannels.add(this); + } + } + + /** + * Constructs a new MockChannel instance intended for accepting requests. + * + * @param serverSocket The associated server socket. Must not be null. + * @param profile The associated profile name. + */ + MockChannel(ServerSocket serverSocket, String profile) { + this.localAddress = (InetSocketAddress) serverSocket.getLocalSocketAddress(); + this.serverSocket = serverSocket; + this.profile = profile; + this.isServer = false; + this.activeChannel = null; + synchronized (openChannels) { + openChannels.add(this); + } + } + + public void accept(Executor executor) throws IOException { + while (isOpen.get()) { + Socket incomingSocket = serverSocket.accept(); + MockChannel incomingChannel = null; + try { + configureSocket(incomingSocket); + synchronized (this) { + if (isOpen.get()) { + InetSocketAddress localAddress = new InetSocketAddress(incomingSocket.getLocalAddress(), + incomingSocket.getPort()); + incomingChannel = new MockChannel(incomingSocket, localAddress, true, profile); + MockChannel finalIncomingChannel = incomingChannel; + incomingChannel.addCloseListener(new ActionListener() { + @Override + public void onResponse(Void aVoid) { + workerChannels.remove(finalIncomingChannel); + } + + @Override + public void onFailure(Exception e) { + workerChannels.remove(finalIncomingChannel); + } + }); + serverAcceptedChannel(incomingChannel); + //establish a happens-before edge between closing and accepting a new connection + workerChannels.add(incomingChannel); + + // this spawns a new thread immediately, so OK under lock + incomingChannel.loopRead(executor); + // the channel is properly registered and will be cleared by the close code. + incomingSocket = null; + incomingChannel = null; + } + } + } finally { + // ensure we don't leak sockets and channels in the failure case. Note that we null both + // if there are no exceptions so this becomes a no op. + IOUtils.closeWhileHandlingException(incomingSocket, incomingChannel); + } + } + } + + void loopRead(Executor executor) { + executor.execute(new AbstractRunnable() { + @Override + public void onFailure(Exception e) { + if (isOpen.get()) { + try { + onException(MockChannel.this, e); + } catch (Exception ex) { + logger.warn("failed on handling exception", ex); + IOUtils.closeWhileHandlingException(MockChannel.this); // pure paranoia + } + } + } + + @Override + protected void doRun() throws Exception { + StreamInput input = new InputStreamStreamInput(new BufferedInputStream(activeChannel.getInputStream())); + // There is a (slim) chance that we get interrupted right after a loop iteration, so check explicitly + while (isOpen.get() && !Thread.currentThread().isInterrupted()) { + cancellableThreads.executeIO(() -> readMessage(MockChannel.this, input)); + } + } + }); + } + + synchronized void close0() throws IOException { + // establish a happens-before edge between closing and accepting a new connection + // we have to sync this entire block to ensure that our openChannels checks work correctly. + // The close block below will close all worker channels but if one of the worker channels runs into an exception + // for instance due to a disconnect the handling of this exception might be executed concurrently. + // now if we are in-turn concurrently call close we might not wait for the actual close to happen and that will, down the road + // make the assertion trip that not all channels are closed. + if (isOpen.compareAndSet(true, false)) { + final boolean removedChannel; + synchronized (openChannels) { + removedChannel = openChannels.remove(this); + } + IOUtils.close(serverSocket, activeChannel, () -> IOUtils.close(workerChannels), + () -> cancellableThreads.cancel("channel closed")); + assert removedChannel: "Channel was not removed or removed twice?"; + } + } + + @Override + public String toString() { + return "MockChannel{" + + "profile='" + profile + '\'' + + ", isOpen=" + isOpen + + ", localAddress=" + localAddress + + ", isServerSocket=" + (serverSocket != null) + + '}'; + } + + @Override + public void close() { + try { + close0(); + closeFuture.complete(null); + } catch (IOException e) { + closeFuture.completeExceptionally(e); + } + } + + @Override + public String getProfile() { + return profile; + } + + @Override + public boolean isServerChannel() { + return isServer; + } + + @Override + public void addCloseListener(ActionListener listener) { + closeFuture.addListener(ActionListener.toBiConsumer(listener)); + } + + @Override + public void addConnectListener(ActionListener listener) { + connectFuture.addListener(ActionListener.toBiConsumer(listener)); + } + + @Override + public ChannelStats getChannelStats() { + return stats; + } + + @Override + public boolean isOpen() { + return isOpen.get(); + } + + @Override + public InetSocketAddress getLocalAddress() { + return localAddress; + } + + @Override + public InetSocketAddress getRemoteAddress() { + return (InetSocketAddress) activeChannel.getRemoteSocketAddress(); + } + + @Override + public void sendMessage(BytesReference reference, ActionListener listener) { + try { + synchronized (this) { + OutputStream outputStream = new BufferedOutputStream(activeChannel.getOutputStream()); + reference.writeTo(outputStream); + outputStream.flush(); + } + listener.onResponse(null); + } catch (IOException e) { + listener.onFailure(e); + onException(this, e); + } + } + } + + + @Override + protected void doStart() { + boolean success = false; + try { + if (NetworkService.NETWORK_SERVER.get(settings)) { + // loop through all profiles and start them up, special handling for default one + for (ProfileSettings profileSettings : profileSettings) { + bindServer(profileSettings); + } + } + super.doStart(); + success = true; + } finally { + if (success == false) { + doStop(); + } + } + } + + @Override + protected void stopInternal() { + ThreadPool.terminate(executor, 10, TimeUnit.SECONDS); + synchronized (openChannels) { + assert openChannels.isEmpty() : "there are still open channels: " + openChannels; + } + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/EsTester.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/EsTester.java new file mode 100644 index 00000000000..9d69c0413f3 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/EsTester.java @@ -0,0 +1,404 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.es; + +import com.google.common.base.Throwables; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang.reflect.ConstructorUtils; +import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.action.bulk.BulkRequestBuilder; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.search.SearchRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.analysis.common.CommonAnalysisPlugin; +import org.elasticsearch.cluster.health.ClusterHealthStatus; +import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.network.NetworkModule; +import org.elasticsearch.common.network.NetworkService; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.PageCacheRecycler; +import org.elasticsearch.discovery.DiscoveryModule; +import org.elasticsearch.env.Environment; +import org.elasticsearch.env.NodeEnvironment; +import org.elasticsearch.index.IndexNotFoundException; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.indices.breaker.CircuitBreakerService; +import org.elasticsearch.indices.recovery.RecoverySettings; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.node.InternalSettingsPreparer; +import org.elasticsearch.node.Node; +import org.elasticsearch.plugins.NetworkPlugin; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.MockTcpTransport; +import org.elasticsearch.transport.Transport; +import org.junit.rules.ExternalResource; +import org.sonar.server.component.index.ComponentIndexDefinition; +import org.sonar.server.es.IndexDefinition.IndexDefinitionContext; +import org.sonar.server.es.IndexType.IndexRelationType; +import org.sonar.server.es.newindex.BuiltIndex; +import org.sonar.server.es.newindex.NewIndex; +import org.sonar.server.issue.index.IssueIndexDefinition; +import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition; +import org.sonar.server.rule.index.RuleIndexDefinition; +import org.sonar.server.user.index.UserIndexDefinition; +import org.sonar.server.view.index.ViewIndexDefinition; + +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Lists.newArrayList; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.sonar.server.es.Index.ALL_INDICES; +import static org.sonar.server.es.IndexType.FIELD_INDEX_TYPE; +import static org.sonar.server.es.newindex.DefaultIndexSettings.REFRESH_IMMEDIATE; + +public class EsTester extends ExternalResource { + + static { + System.setProperty("log4j.shutdownHookEnabled", "false"); + // we can not shutdown logging when tests are running or the next test that runs within the + // same JVM will try to initialize logging after a security manager has been installed and + // this will fail + System.setProperty("es.log4j.shutdownEnabled", "false"); + System.setProperty("log4j2.disable.jmx", "true"); + System.setProperty("log4j.skipJansi", "true"); // jython has this crazy shaded Jansi version that log4j2 tries to load + + if (!Strings.hasLength(System.getProperty("tests.es.logger.level"))) { + System.setProperty("tests.es.logger.level", "WARN"); + } + } + + private static final Node SHARED_NODE = createNode(); + private static final AtomicBoolean CORE_INDICES_CREATED = new AtomicBoolean(false); + private static final Set CORE_INDICES_NAMES = new HashSet<>(); + + private final boolean isCustom; + + private EsTester(boolean isCustom) { + this.isCustom = isCustom; + } + + /** + * New instance which contains the core indices (rules, issues, ...). + */ + public static EsTester create() { + if (!CORE_INDICES_CREATED.get()) { + List createdIndices = createIndices( + ComponentIndexDefinition.createForTest(), + IssueIndexDefinition.createForTest(), + ProjectMeasuresIndexDefinition.createForTest(), + RuleIndexDefinition.createForTest(), + UserIndexDefinition.createForTest(), + ViewIndexDefinition.createForTest()); + + CORE_INDICES_CREATED.set(true); + createdIndices.stream().map(t -> t.getMainType().getIndex().getName()).forEach(CORE_INDICES_NAMES::add); + } + return new EsTester(false); + } + + /** + * New instance which contains the specified indices. Note that + * core indices may exist. + */ + public static EsTester createCustom(IndexDefinition... definitions) { + createIndices(definitions); + return new EsTester(true); + } + + @Override + protected void after() { + if (isCustom) { + // delete non-core indices + String[] existingIndices = SHARED_NODE.client().admin().indices().prepareGetIndex().get().getIndices(); + Stream.of(existingIndices) + .filter(i -> !CORE_INDICES_NAMES.contains(i)) + .forEach(EsTester::deleteIndexIfExists); + } + BulkIndexer.delete(client(), IndexType.main(ALL_INDICES, "dummy"), client().prepareSearch(ALL_INDICES).setQuery(matchAllQuery())); + } + + public EsClient client() { + return new EsClient(SHARED_NODE.client()); + } + + public void putDocuments(IndexType indexType, BaseDoc... docs) { + try { + BulkRequestBuilder bulk = SHARED_NODE.client().prepareBulk() + .setRefreshPolicy(REFRESH_IMMEDIATE); + for (BaseDoc doc : docs) { + bulk.add(doc.toIndexRequest()); + } + BulkResponse bulkResponse = bulk.get(); + if (bulkResponse.hasFailures()) { + throw new IllegalStateException(bulkResponse.buildFailureMessage()); + } + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + public void putDocuments(IndexType indexType, Map... docs) { + try { + BulkRequestBuilder bulk = SHARED_NODE.client().prepareBulk() + .setRefreshPolicy(REFRESH_IMMEDIATE); + for (Map doc : docs) { + IndexType.IndexMainType mainType = indexType.getMainType(); + bulk.add(new IndexRequest(mainType.getIndex().getName(), mainType.getType()) + .source(doc)); + } + BulkResponse bulkResponse = bulk.get(); + if (bulkResponse.hasFailures()) { + throw new IllegalStateException(bulkResponse.buildFailureMessage()); + } + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + public long countDocuments(Index index) { + return client().prepareSearch(index) + .setQuery(matchAllQuery()) + .setSize(0).get().getHits().getTotalHits(); + } + + public long countDocuments(IndexType indexType) { + return client().prepareSearch(indexType.getMainType()) + .setQuery(getDocumentsQuery(indexType)) + .setSize(0).get().getHits().getTotalHits(); + } + + /** + * Get all the indexed documents (no paginated results). Results are converted to BaseDoc objects. + * Results are not sorted. + */ + public List getDocuments(IndexType indexType, final Class docClass) { + List hits = getDocuments(indexType); + return new ArrayList<>(Collections2.transform(hits, input -> { + try { + return (E) ConstructorUtils.invokeConstructor(docClass, input.getSourceAsMap()); + } catch (Exception e) { + throw Throwables.propagate(e); + } + })); + } + + /** + * Get all the indexed documents (no paginated results) in the specified index, whatever their type. Results are not sorted. + */ + public List getDocuments(Index index) { + SearchRequestBuilder req = SHARED_NODE.client() + .prepareSearch(index.getName()) + .setQuery(matchAllQuery()); + return getDocuments(req); + } + + /** + * Get all the indexed documents (no paginated results) of the specified type. Results are not sorted. + */ + public List getDocuments(IndexType indexType) { + IndexType.IndexMainType mainType = indexType.getMainType(); + SearchRequestBuilder req = SHARED_NODE.client() + .prepareSearch(mainType.getIndex().getName()) + .setQuery(getDocumentsQuery(indexType)); + return getDocuments(req); + } + + private List getDocuments(SearchRequestBuilder req) { + EsUtils.optimizeScrollRequest(req); + req.setScroll(new TimeValue(60000)) + .setSize(100); + + SearchResponse response = req.get(); + List result = newArrayList(); + while (true) { + Iterables.addAll(result, response.getHits()); + response = SHARED_NODE.client().prepareSearchScroll(response.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet(); + // Break condition: No hits are returned + if (response.getHits().getHits().length == 0) { + break; + } + } + return result; + } + + private QueryBuilder getDocumentsQuery(IndexType indexType) { + if (!indexType.getMainType().getIndex().acceptsRelations()) { + return matchAllQuery(); + } + + if (indexType instanceof IndexRelationType) { + return new TermQueryBuilder(FIELD_INDEX_TYPE, ((IndexRelationType) indexType).getName()); + } + if (indexType instanceof IndexType.IndexMainType) { + return new TermQueryBuilder(FIELD_INDEX_TYPE, ((IndexType.IndexMainType) indexType).getType()); + } + throw new IllegalArgumentException("Unsupported IndexType " + indexType.getClass()); + } + + /** + * Get a list of a specific field from all indexed documents. + */ + public List getDocumentFieldValues(IndexType indexType, final String fieldNameToReturn) { + return getDocuments(indexType) + .stream() + .map(input -> (T) input.getSourceAsMap().get(fieldNameToReturn)) + .collect(Collectors.toList()); + } + + public List getIds(IndexType indexType) { + return getDocuments(indexType).stream().map(SearchHit::getId).collect(Collectors.toList()); + } + + public void lockWrites(IndexType index) { + setIndexSettings(index.getMainType().getIndex().getName(), ImmutableMap.of("index.blocks.write", "true")); + } + + public void unlockWrites(IndexType index) { + setIndexSettings(index.getMainType().getIndex().getName(), ImmutableMap.of("index.blocks.write", "false")); + } + + private void setIndexSettings(String index, Map settings) { + AcknowledgedResponse response = SHARED_NODE.client().admin().indices() + .prepareUpdateSettings(index) + .setSettings(settings) + .get(); + checkState(response.isAcknowledged()); + } + + private static void deleteIndexIfExists(String name) { + try { + AcknowledgedResponse response = SHARED_NODE.client().admin().indices().prepareDelete(name).get(); + checkState(response.isAcknowledged(), "Fail to drop the index " + name); + } catch (IndexNotFoundException e) { + // ignore + } + } + + private static List createIndices(IndexDefinition... definitions) { + IndexDefinitionContext context = new IndexDefinitionContext(); + Stream.of(definitions).forEach(d -> d.define(context)); + + List result = new ArrayList<>(); + for (NewIndex newIndex : context.getIndices().values()) { + BuiltIndex index = newIndex.build(); + + String indexName = index.getMainType().getIndex().getName(); + deleteIndexIfExists(indexName); + + // create index + Settings.Builder settings = Settings.builder(); + settings.put(index.getSettings()); + CreateIndexResponse indexResponse = SHARED_NODE.client().admin().indices() + .prepareCreate(indexName) + .setSettings(settings) + .get(); + if (!indexResponse.isAcknowledged()) { + throw new IllegalStateException("Failed to create index " + indexName); + } + SHARED_NODE.client().admin().cluster().prepareHealth(indexName).setWaitForStatus(ClusterHealthStatus.YELLOW).get(); + + // create types + String typeName = index.getMainType().getType(); + AcknowledgedResponse mappingResponse = SHARED_NODE.client().admin().indices().preparePutMapping(indexName) + .setType(typeName) + .setSource(index.getAttributes()) + .get(); + if (!mappingResponse.isAcknowledged()) { + throw new IllegalStateException("Failed to create type " + typeName); + } + SHARED_NODE.client().admin().cluster().prepareHealth(indexName).setWaitForStatus(ClusterHealthStatus.YELLOW).get(); + result.add(index); + } + return result; + } + + private static Node createNode() { + try { + Path tempDir = Files.createTempDirectory("EsTester"); + tempDir.toFile().deleteOnExit(); + Settings settings = Settings.builder() + .put(Environment.PATH_HOME_SETTING.getKey(), tempDir) + .put("node.name", "EsTester") + .put(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey(), Integer.MAX_VALUE) + .put("logger.level", "INFO") + .put("action.auto_create_index", false) + // Default the watermarks to absurdly low to prevent the tests + // from failing on nodes without enough disk space + .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING.getKey(), "1b") + .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK_SETTING.getKey(), "1b") + .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_DISK_FLOOD_STAGE_WATERMARK_SETTING.getKey(), "1b") + // always reduce this - it can make tests really slow + .put(RecoverySettings.INDICES_RECOVERY_RETRY_DELAY_STATE_SYNC_SETTING.getKey(), TimeValue.timeValueMillis(20)) + .put(NetworkModule.TRANSPORT_TYPE_KEY, "local") + .put(NetworkModule.HTTP_ENABLED.getKey(), false) + .put(DiscoveryModule.DISCOVERY_TYPE_SETTING.getKey(), "single-node") + .build(); + Node node = new Node(InternalSettingsPreparer.prepareEnvironment(settings, null), + ImmutableList.of( + CommonAnalysisPlugin.class, + // mock local transport plugin + MockTcpTransportPlugin.class, + // install ParentJoin plugin required to create field of type "join" + ParentJoinPlugin.class), + true) { + @Override + protected void registerDerivedNodeNameWithLogger(String nodeName) { + // nothing to do + } + }; + return node.start(); + } catch (Exception e) { + throw new IllegalStateException("Fail to start embedded Elasticsearch", e); + } + } + + public static final class MockTcpTransportPlugin extends Plugin implements NetworkPlugin { + @Override + public Map> getTransports(Settings settings, ThreadPool threadPool, PageCacheRecycler pageCacheRecycler, + CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) { + return Collections.singletonMap( + "local", + () -> new MockTcpTransport(settings, threadPool, BigArrays.NON_RECYCLING_INSTANCE, circuitBreakerService, namedWriteableRegistry, networkService)); + } + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/FakeDoc.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/FakeDoc.java new file mode 100644 index 00000000000..d199ed9323a --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/FakeDoc.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.es; + +import com.google.common.collect.Maps; + +import static org.sonar.server.es.newindex.FakeIndexDefinition.INT_FIELD; +import static org.sonar.server.es.newindex.FakeIndexDefinition.TYPE_FAKE; + +public class FakeDoc extends BaseDoc { + public FakeDoc() { + super(TYPE_FAKE, Maps.newHashMap()); + } + + @Override + public String getId() { + return null; + } + + public int getInt() { + return getField(INT_FIELD); + } + + public FakeDoc setInt(int i) { + setField(INT_FIELD, i); + return this; + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java new file mode 100644 index 00000000000..fb858911533 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/TestProjectIndexers.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.es; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import java.util.Collection; +import org.sonar.db.DbSession; + +public class TestProjectIndexers implements ProjectIndexers { + + private final ListMultimap calls = ArrayListMultimap.create(); + + @Override + public void commitAndIndexByProjectUuids(DbSession dbSession, Collection projectUuids, ProjectIndexer.Cause cause) { + dbSession.commit(); + projectUuids.forEach(projectUuid -> calls.put(projectUuid, cause)); + + } + + public boolean hasBeenCalled(String projectUuid, ProjectIndexer.Cause expectedCause) { + return calls.get(projectUuid).contains(expectedCause); + } + + public boolean hasBeenCalled(String projectUuid) { + return calls.containsKey(projectUuid); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/newindex/FakeIndexDefinition.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/newindex/FakeIndexDefinition.java new file mode 100644 index 00000000000..d6dfd760540 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/newindex/FakeIndexDefinition.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.es.newindex; + +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.server.es.FakeDoc; +import org.sonar.server.es.Index; +import org.sonar.server.es.IndexDefinition; +import org.sonar.server.es.IndexType; +import org.sonar.server.es.IndexType.IndexMainType; + +import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder; + +public class FakeIndexDefinition implements IndexDefinition { + + public static final String INDEX = "fakes"; + public static final String TYPE = "fake"; + public static final Index DESCRIPTOR = Index.simple(INDEX); + public static final IndexMainType TYPE_FAKE = IndexType.main(DESCRIPTOR, TYPE); + public static final String INT_FIELD = "intField"; + + private int replicas = 0; + + public FakeIndexDefinition setReplicas(int replicas) { + this.replicas = replicas; + return this; + } + + @Override + public void define(IndexDefinitionContext context) { + NewIndex index = context.create(DESCRIPTOR, newBuilder(new MapSettings().asConfig()).build()); + index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, replicas); + index.getSettings().put("index.refresh_interval", "-1"); + index.createTypeMapping(TYPE_FAKE) + .createIntegerField(INT_FIELD); + } + + public static FakeDoc newDoc(int value) { + return new FakeDoc().setInt(value); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java new file mode 100644 index 00000000000..60ddbdbde5b --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.es.textsearch; + +import org.junit.rules.ExternalResource; + +public class ComponentTextSearchFeatureRule extends ExternalResource { + + private ComponentTextSearchFeature[] features; + + @Override + protected void before() { + features = ComponentTextSearchFeatureRepertoire.values(); + } + + public ComponentTextSearchFeature[] get() { + return features; + } + + public void set(ComponentTextSearchFeature... features) { + this.features = features; + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/issue/IssueDocTesting.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/issue/IssueDocTesting.java new file mode 100644 index 00000000000..c63f12e950c --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/issue/IssueDocTesting.java @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this 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.Maps; +import java.util.Date; +import org.sonar.api.resources.Scopes; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.RuleType; +import org.sonar.core.util.Uuids; +import org.sonar.db.component.ComponentDto; +import org.sonar.server.issue.index.IssueDoc; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; +import static org.apache.commons.lang.math.RandomUtils.nextInt; +import static org.sonar.api.issue.Issue.STATUS_OPEN; + +public class IssueDocTesting { + + public static IssueDoc newDoc(ComponentDto componentDto) { + return newDoc(Uuids.createFast(), componentDto); + } + + public static IssueDoc newDoc(String key, ComponentDto componentDto) { + String mainBranchProjectUuid = componentDto.getMainBranchProjectUuid(); + return newDoc() + .setKey(key) + .setBranchUuid(componentDto.projectUuid()) + .setComponentUuid(componentDto.uuid()) + .setModuleUuid(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.moduleUuid() : componentDto.uuid()) + .setModuleUuidPath(componentDto.moduleUuidPath()) + .setProjectUuid(mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid) + .setOrganizationUuid(componentDto.getOrganizationUuid()) + // File path make no sens on modules and projects + .setFilePath(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.path() : null) + .setIsMainBranch(mainBranchProjectUuid == null); + } + + public static IssueDoc newDoc() { + IssueDoc doc = new IssueDoc(Maps.newHashMap()); + doc.setKey(Uuids.createFast()); + doc.setRuleId(nextInt(1000)); + doc.setType(RuleType.CODE_SMELL); + doc.setAssigneeUuid("assignee_uuid_" + randomAlphabetic(26)); + doc.setAuthorLogin("author_" + randomAlphabetic(5)); + doc.setLanguage("language_" + randomAlphabetic(5)); + doc.setComponentUuid(Uuids.createFast()); + doc.setFilePath("filePath_" + randomAlphabetic(5)); + doc.setDirectoryPath("directory_" + randomAlphabetic(5)); + doc.setModuleUuid(Uuids.createFast()); + doc.setModuleUuidPath(Uuids.createFast()); + doc.setProjectUuid(Uuids.createFast()); + doc.setLine(nextInt(1_000) + 1); + doc.setStatus(STATUS_OPEN); + doc.setResolution(null); + doc.setSeverity(Severity.ALL.get(nextInt(Severity.ALL.size()))); + doc.setEffort((long) nextInt(10)); + doc.setFuncCreationDate(new Date(System.currentTimeMillis() - 2_000)); + doc.setFuncUpdateDate(new Date(System.currentTimeMillis() - 1_000)); + doc.setFuncCloseDate(null); + return doc; + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/issue/notification/IssuesChangesNotificationBuilderTesting.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/issue/notification/IssuesChangesNotificationBuilderTesting.java new file mode 100644 index 00000000000..43f5cbfd5a2 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/issue/notification/IssuesChangesNotificationBuilderTesting.java @@ -0,0 +1,110 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this 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.notification; + +import java.util.Random; +import org.sonar.api.rule.RuleKey; +import org.sonar.db.DbTester; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.rule.RuleDto; +import org.sonar.db.user.UserDto; +import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.AnalysisChange; +import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.ChangedIssue; +import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.Project; +import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.Rule; +import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.User; +import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.UserChange; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; + +public class IssuesChangesNotificationBuilderTesting { + + public static Rule ruleOf(RuleDto rule) { + return new Rule(rule.getKey(), rule.getName()); + } + + public static Rule ruleOf(RuleDefinitionDto rule) { + return new Rule(rule.getKey(), rule.getName()); + } + + public static User userOf(UserDto changeAuthor) { + return new User(changeAuthor.getUuid(), changeAuthor.getLogin(), changeAuthor.getName()); + } + + public static Project projectBranchOf(DbTester db, ComponentDto branch) { + BranchDto branchDto = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()).get(); + checkArgument(!branchDto.isMain(), "should be a branch"); + return new Project.Builder(branch.uuid()) + .setKey(branch.getKey()) + .setProjectName(branch.name()) + .setBranchName(branchDto.getKey()) + .build(); + } + + public static Project projectOf(ComponentDto project) { + return new Project.Builder(project.uuid()) + .setKey(project.getKey()) + .setProjectName(project.name()) + .build(); + } + + static ChangedIssue newChangedIssue(String key, Project project, Rule rule) { + return new ChangedIssue.Builder(key) + .setNewStatus(randomAlphabetic(19)) + .setProject(project) + .setRule(rule) + .build(); + } + + static ChangedIssue newChangedIssue(String key, String status, Project project, String ruleName) { + return newChangedIssue(key, status, project, newRule(ruleName)); + } + + static ChangedIssue newChangedIssue(String key, String status, Project project, Rule rule) { + return new ChangedIssue.Builder(key) + .setNewStatus(status) + .setProject(project) + .setRule(rule) + .build(); + } + + static Rule newRule(String ruleName) { + return new Rule(RuleKey.of(randomAlphabetic(6), randomAlphabetic(7)), ruleName); + } + + static Project newProject(String uuid) { + return new Project.Builder(uuid).setProjectName(uuid + "_name").setKey(uuid + "_key").build(); + } + + static Project newBranch(String uuid, String branchName) { + return new Project.Builder(uuid).setProjectName(uuid + "_name").setKey(uuid + "_key").setBranchName(branchName).build(); + } + + static UserChange newUserChange() { + return new UserChange(new Random().nextLong(), new User(randomAlphabetic(4), randomAlphabetic(5), randomAlphabetic(6))); + } + + static AnalysisChange newAnalysisChange() { + return new AnalysisChange(new Random().nextLong()); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/l18n/I18nRule.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/l18n/I18nRule.java new file mode 100644 index 00000000000..f81a2f09b45 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/l18n/I18nRule.java @@ -0,0 +1,128 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.l18n; + +import java.text.MessageFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.sonar.core.i18n.I18n; + +public class I18nRule implements TestRule, I18n { + private final Map messages = new HashMap<>(); + + public I18nRule put(String key, String value) { + messages.put(key, value); + return this; + } + + @Override + public Statement apply(final Statement statement, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + statement.evaluate(); + } finally { + messages.clear(); + } + } + }; + } + + public void setProjectPermissions() { + put("projects_role.admin", "Administer"); + put("projects_role.admin.desc", "Ability to access project settings and perform administration tasks. " + + "(Users will also need \"Browse\" permission)"); + put("projects_role.issueadmin", "Administer Issues"); + put("projects_role.issueadmin.desc", "Grants the permission to perform advanced editing on issues: marking an issue " + + "False Positive / Won't Fix or changing an Issue's severity. (Users will also need \"Browse\" permission)"); + put("projects_role.securityhotspotadmin", "Administer Security Hotspots"); + put("projects_role.securityhotspotadmin.desc", "Detect a Vulnerability from a \"Security Hotspot\". Reject, clear, accept, reopen a \"Security Hotspot\" (users also need \"Browse\" permissions)."); + put("projects_role.applicationcreator", "Create Applications"); + put("projects_role.applicationcreator.desc", "Allow to create applications for non system administrator."); + put("projects_role.portfoliocreator", "Create Portfolios"); + put("projects_role.portfoliocreator.desc", "Allow to create portfolios for non system administrator."); + put("projects_role.user", "Browse"); + put("projects_role.user.desc", "Ability to access a project, browse its measures, and create/edit issues for it."); + put("projects_role.codeviewer", "See Source Code"); + put("projects_role.codeviewer.desc", "Ability to view the project's source code. (Users will also need \"Browse\" permission)"); + put("projects_role.scan", "Execute Analysis"); + put("projects_role.scan.desc", + "Ability to execute analyses, and to get all settings required to perform the analysis, even the secured ones like the scm account password, the jira account password, and so on."); + } + + @Override + public String message(Locale locale, String key, @Nullable String defaultValue, Object... parameters) { + String messageInMap = messages.get(key); + String message = messageInMap != null ? messageInMap : defaultValue; + return formatMessage(message, parameters); + } + + @CheckForNull + private static String formatMessage(@Nullable String message, Object... parameters) { + if (message == null || parameters.length == 0) { + return message; + } + return MessageFormat.format(message.replaceAll("'", "''"), parameters); + } + + @Override + public String age(Locale locale, long durationInMillis) { + throw new UnsupportedOperationException(); + } + + @Override + public String age(Locale locale, Date fromDate, Date toDate) { + throw new UnsupportedOperationException(); + } + + @Override + public String ageFromNow(Locale locale, Date date) { + throw new UnsupportedOperationException(); + } + + @Override + public String formatDateTime(Locale locale, Date date) { + throw new UnsupportedOperationException(); + } + + @Override + public String formatDate(Locale locale, Date date) { + throw new UnsupportedOperationException(); + } + + @Override + public String formatDouble(Locale locale, Double value) { + return String.valueOf(value); + } + + @Override + public String formatInteger(Locale locale, Integer value) { + return String.valueOf(value); + } + +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/organization/TestDefaultOrganizationProvider.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/organization/TestDefaultOrganizationProvider.java new file mode 100644 index 00000000000..a5b52317a37 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/organization/TestDefaultOrganizationProvider.java @@ -0,0 +1,95 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.organization; + +import java.util.Date; +import org.sonar.db.DbTester; +import org.sonar.db.organization.OrganizationDto; + +public class TestDefaultOrganizationProvider implements DefaultOrganizationProvider { + + private final DefaultOrganizationProvider delegate; + + private TestDefaultOrganizationProvider(DefaultOrganizationProvider delegate) { + this.delegate = delegate; + } + + public static TestDefaultOrganizationProvider from(DbTester dbTester) { + return new TestDefaultOrganizationProvider(new DbTesterDefaultOrganizationProvider(dbTester)); + } + + public static TestDefaultOrganizationProvider fromUuid(String uuid) { + long createdAt = new Date().getTime(); + return new TestDefaultOrganizationProvider( + new ImmutableDefaultOrganizationProvider( + DefaultOrganization.newBuilder() + .setUuid(uuid) + .setKey("key_" + uuid) + .setName("name_" + uuid) + .setCreatedAt(createdAt) + .setUpdatedAt(createdAt) + .build())); + } + + @Override + public DefaultOrganization get() { + return delegate.get(); + } + + private static final class ImmutableDefaultOrganizationProvider implements DefaultOrganizationProvider { + private final DefaultOrganization defaultOrganization; + + private ImmutableDefaultOrganizationProvider(DefaultOrganization defaultOrganization) { + this.defaultOrganization = defaultOrganization; + } + + @Override + public DefaultOrganization get() { + return defaultOrganization; + } + } + + private static final class DbTesterDefaultOrganizationProvider implements DefaultOrganizationProvider { + private final DbTester dbTester; + private DefaultOrganization defaultOrganization = null; + + private DbTesterDefaultOrganizationProvider(DbTester dbTester) { + this.dbTester = dbTester; + } + + @Override + public DefaultOrganization get() { + if (defaultOrganization == null) { + defaultOrganization = toDefaultOrganization(dbTester.getDefaultOrganization()); + } + return defaultOrganization; + } + + private static DefaultOrganization toDefaultOrganization(OrganizationDto organizationDto) { + return DefaultOrganization.newBuilder() + .setUuid(organizationDto.getUuid()) + .setKey(organizationDto.getKey()) + .setName(organizationDto.getName()) + .setCreatedAt(organizationDto.getCreatedAt()) + .setUpdatedAt(organizationDto.getUpdatedAt()) + .build(); + } + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/organization/TestOrganizationFlags.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/organization/TestOrganizationFlags.java new file mode 100644 index 00000000000..f5a6d71cd33 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/organization/TestOrganizationFlags.java @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.organization; + +import java.util.concurrent.atomic.AtomicBoolean; +import org.sonar.db.DbSession; + +import static org.sonar.server.organization.OrganizationFlagsImpl.FAILURE_MESSAGE_DISABLED; +import static org.sonar.server.organization.OrganizationFlagsImpl.FAILURE_MESSAGE_ENABLED; + +public class TestOrganizationFlags implements OrganizationFlags { + + private final AtomicBoolean enabled = new AtomicBoolean(false); + + private TestOrganizationFlags() { + } + + @Override + public boolean isEnabled(DbSession dbSession) { + return enabled.get(); + } + + public TestOrganizationFlags setEnabled(boolean b) { + this.enabled.set(b); + return this; + } + + @Override + public void enable(DbSession dbSession) { + setEnabled(true); + } + + @Override + public void checkEnabled(DbSession dbSession) { + if (!isEnabled(dbSession)) { + throw new IllegalStateException(FAILURE_MESSAGE_DISABLED); + } + } + + @Override + public void checkDisabled(DbSession dbSession) { + if (isEnabled(dbSession)) { + throw new IllegalStateException(FAILURE_MESSAGE_ENABLED); + } + } + + /** + * By default Organization support is disabled + */ + public static TestOrganizationFlags standalone() { + return new TestOrganizationFlags(); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/SystemInfoTesting.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/SystemInfoTesting.java new file mode 100644 index 00000000000..a438af791b9 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/SystemInfoTesting.java @@ -0,0 +1,50 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this 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.monitoring; + +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.process.systeminfo.SystemInfoUtils.attribute; + +public class SystemInfoTesting { + + private SystemInfoTesting() { + // do not instantiate + } + + public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, String expectedValue) { + ProtobufSystemInfo.Attribute value = attribute(section, key); + assertThat(value).as(key).isNotNull(); + assertThat(value.getStringValue()).isEqualTo(expectedValue); + } + + public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, boolean expectedValue) { + ProtobufSystemInfo.Attribute value = attribute(section, key); + assertThat(value).as(key).isNotNull(); + assertThat(value.getBooleanValue()).isEqualTo(expectedValue); + } + + public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, long expectedValue) { + ProtobufSystemInfo.Attribute value = attribute(section, key); + assertThat(value).as(key).isNotNull(); + assertThat(value.getLongValue()).isEqualTo(expectedValue); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java new file mode 100644 index 00000000000..534c0f5df46 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this 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.monitoring.cluster; + +import org.sonar.process.systeminfo.Global; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +class TestGlobalSystemInfoSection implements SystemInfoSection, Global { + private final String name; + + TestGlobalSystemInfoSection(String name) { + this.name = name; + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + return ProtobufSystemInfo.Section.newBuilder().setName(name).build(); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java new file mode 100644 index 00000000000..0ae8b3aec57 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this 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.monitoring.cluster; + +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +class TestSystemInfoSection implements SystemInfoSection { + private final String name; + + TestSystemInfoSection(String name) { + this.name = name; + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + return ProtobufSystemInfo.Section.newBuilder().setName(name).build(); + } +} diff --git a/server/sonar-server-common/src/testFixtures/java/org/sonar/server/source/index/FileSourceTesting.java b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/source/index/FileSourceTesting.java new file mode 100644 index 00000000000..86624383dc4 --- /dev/null +++ b/server/sonar-server-common/src/testFixtures/java/org/sonar/server/source/index/FileSourceTesting.java @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this 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.index; + +import java.util.Arrays; +import org.sonar.db.protobuf.DbFileSources; + +public class FileSourceTesting { + + private FileSourceTesting() { + // only static stuff + } + + /** + * Generate predefined fake data. Result is mutable. + */ + public static DbFileSources.Data.Builder newFakeData(int numberOfLines) { + DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); + for (int i = 1; i <= numberOfLines; i++) { + dataBuilder.addLinesBuilder() + .setLine(i) + .setScmRevision("REVISION_" + i) + .setScmAuthor("AUTHOR_" + i) + .setScmDate(1_500_000_000_00L + i) + .setSource("SOURCE_" + i) + .setLineHits(i) + .setConditions(i + 1) + .setCoveredConditions(i + 2) + .setHighlighting("HIGHLIGHTING_" + i) + .setSymbols("SYMBOLS_" + i) + .addAllDuplication(Arrays.asList(i)) + .setIsNewLine(true) + .build(); + } + return dataBuilder; + } + +} diff --git a/server/sonar-webserver-api/build.gradle b/server/sonar-webserver-api/build.gradle index 93b373805f7..561fd3957d5 100644 --- a/server/sonar-webserver-api/build.gradle +++ b/server/sonar-webserver-api/build.gradle @@ -35,7 +35,6 @@ dependencies { testCompile 'com.tngtech.java:junit-dataprovider' testCompile 'javax.servlet:javax.servlet-api' testCompile 'org.mockito:mockito-core' - testCompile testFixtures(project(':server:sonar-db-dao')) - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) testCompile project(':sonar-testing-harness') } diff --git a/server/sonar-webserver-auth/build.gradle b/server/sonar-webserver-auth/build.gradle index cba572bb3ba..2882242d7fc 100644 --- a/server/sonar-webserver-auth/build.gradle +++ b/server/sonar-webserver-auth/build.gradle @@ -35,8 +35,7 @@ dependencies { testCompile 'org.apache.logging.log4j:log4j-core' testCompile 'org.assertj:assertj-guava' testCompile 'org.mockito:mockito-core' - testCompile testFixtures(project(':server:sonar-db-dao')) - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) testCompile project(':sonar-testing-harness') runtime 'io.jsonwebtoken:jjwt-jackson' diff --git a/server/sonar-webserver-core/build.gradle b/server/sonar-webserver-core/build.gradle index 46fd497fa9f..824739f42c7 100644 --- a/server/sonar-webserver-core/build.gradle +++ b/server/sonar-webserver-core/build.gradle @@ -61,7 +61,6 @@ dependencies { testCompile 'com.h2database:h2' testCompile 'com.squareup.okhttp3:mockwebserver' testCompile 'com.tngtech.java:junit-dataprovider' - testCompile 'junit:junit' testCompile 'org.apache.logging.log4j:log4j-api' testCompile 'org.apache.logging.log4j:log4j-core' testCompile 'org.assertj:assertj-core' @@ -71,8 +70,7 @@ dependencies { testCompile 'org.hamcrest:hamcrest-all' testCompile 'org.mockito:mockito-core' testCompile 'org.subethamail:subethasmtp' - testCompile testFixtures(project(':server:sonar-db-dao')) - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) testCompile project(path: ":server:sonar-webserver-auth", configuration: "tests") testCompile project(path: ":server:sonar-webserver-es", configuration: "tests") testCompile testFixtures(project(':server:sonar-webserver-ws')) diff --git a/server/sonar-webserver-es/build.gradle b/server/sonar-webserver-es/build.gradle index cea503301be..d69e85e01aa 100644 --- a/server/sonar-webserver-es/build.gradle +++ b/server/sonar-webserver-es/build.gradle @@ -27,9 +27,8 @@ dependencies { testCompile 'com.google.code.findbugs:jsr305' testCompile 'com.tngtech.java:junit-dataprovider' testCompile 'org.mockito:mockito-core' - testCompile testFixtures(project(':server:sonar-db-dao')) testCompile project(path: ":server:sonar-webserver-auth", configuration: "tests") - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) testCompile project(':sonar-testing-harness') } diff --git a/server/sonar-webserver-webapi/build.gradle b/server/sonar-webserver-webapi/build.gradle index 2d3a2c1772f..d9501e61847 100644 --- a/server/sonar-webserver-webapi/build.gradle +++ b/server/sonar-webserver-webapi/build.gradle @@ -33,8 +33,7 @@ dependencies { testCompile 'com.squareup.okhttp3:mockwebserver' testCompile 'javax.servlet:javax.servlet-api' testCompile 'org.mockito:mockito-core' - testCompile testFixtures(project(':server:sonar-db-dao')) - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) testCompile project(path: ":server:sonar-webserver-auth", configuration: "tests") testCompile project(path: ":server:sonar-webserver-es", configuration: "tests") testCompile testFixtures(project(':server:sonar-webserver-ws')) diff --git a/server/sonar-webserver/build.gradle b/server/sonar-webserver/build.gradle index cd4e3185417..758f76bca3c 100644 --- a/server/sonar-webserver/build.gradle +++ b/server/sonar-webserver/build.gradle @@ -26,8 +26,7 @@ dependencies { testCompile 'org.mockito:mockito-core' testCompile 'org.eclipse.jetty:jetty-server' testCompile 'org.eclipse.jetty:jetty-servlet' - testCompile testFixtures(project(':server:sonar-db-dao')) - testCompile project(path: ":server:sonar-server-common", configuration: "tests") + testCompile testFixtures(project(':server:sonar-server-common')) testCompile project(path: ":server:sonar-webserver-auth", configuration: "tests") testCompile project(path: ":server:sonar-webserver-es", configuration: "tests") testCompile project(':sonar-testing-harness')