]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9802 add unit tests
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Thu, 21 Sep 2017 10:45:38 +0000 (12:45 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 26 Sep 2017 21:49:38 +0000 (23:49 +0200)
14 files changed:
server/sonar-ce/src/test/java/org/sonar/ce/container/HazelcastTestHelper.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoader.java
server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImpl.java
server/sonar-server/src/main/java/org/sonar/server/platform/ws/BaseInfoWsAction.java
server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoaderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSectionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/LoggingSectionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSectionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProviderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java [new file with mode: 0644]

diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/HazelcastTestHelper.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/HazelcastTestHelper.java
deleted file mode 100644 (file)
index 07cb6f5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.ce.container;
-
-import com.hazelcast.config.Config;
-import com.hazelcast.config.JoinConfig;
-import com.hazelcast.config.NetworkConfig;
-import com.hazelcast.core.Hazelcast;
-import com.hazelcast.core.HazelcastInstance;
-import java.net.InetAddress;
-
-/**
- * TODO move outside main sources
- */
-public class HazelcastTestHelper {
-  private HazelcastTestHelper() {
-    // prevents instantiation
-  }
-
-  public static HazelcastInstance createHazelcastCluster(String hostname, int port) {
-    Config hzConfig = new Config();
-    hzConfig.getGroupConfig().setName("sonarqube");
-
-    // Configure the network instance
-    NetworkConfig netConfig = hzConfig.getNetworkConfig();
-    netConfig
-      .setPort(port)
-      .setReuseAddress(true);
-
-    netConfig.getInterfaces()
-      .setEnabled(true)
-      .addInterface(InetAddress.getLoopbackAddress().getHostAddress());
-
-    // Only allowing TCP/IP configuration
-    JoinConfig joinConfig = netConfig.getJoin();
-    joinConfig.getAwsConfig().setEnabled(false);
-    joinConfig.getMulticastConfig().setEnabled(false);
-    joinConfig.getTcpIpConfig().setEnabled(true);
-
-    // Tweak HazelCast configuration
-    hzConfig
-      // Increase the number of tries
-      .setProperty("hazelcast.tcp.join.port.try.count", "10")
-      // Don't bind on all interfaces
-      .setProperty("hazelcast.socket.bind.any", "false")
-      // Don't phone home
-      .setProperty("hazelcast.phone.home.enabled", "false")
-      // Use slf4j for logging
-      .setProperty("hazelcast.logging.type", "slf4j");
-
-    // Trying to resolve the hostname
-    hzConfig.getMemberAttributeConfig().setStringAttribute("HOSTNAME", hostname);
-
-    // We are not using the partition group of Hazelcast, so disabling it
-    hzConfig.getPartitionGroupConfig().setEnabled(false);
-    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(hzConfig);
-    return hzInstance;
-  }
-}
index f3ffd959865a2fa1a9c7feb7c5b66c4c6234db7b..0999e401431841e606bb3b99d952cf103467354f 100644 (file)
@@ -23,5 +23,5 @@ import java.util.Collection;
 
 public interface AppNodesInfoLoader {
 
-  Collection<NodeInfo> load();
+  Collection<NodeInfo> load() throws InterruptedException;
 }
index bb545a764eb7eeacb1de98bf6f6049e636144b78..565178f40a81278102db867bc36f8f588cb7876a 100644 (file)
@@ -29,39 +29,35 @@ import org.sonar.api.server.ServerSide;
 import org.sonar.process.ProcessId;
 import org.sonar.process.cluster.hz.DistributedAnswer;
 import org.sonar.process.cluster.hz.HazelcastMember;
+import org.sonar.process.cluster.hz.HazelcastMemberSelectors;
 import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
 
 import static org.sonar.process.cluster.hz.HazelcastMember.Attribute.NODE_NAME;
-import static org.sonar.process.cluster.hz.HazelcastMember.Attribute.PROCESS_KEY;
 
 @ServerSide
 public class AppNodesInfoLoaderImpl implements AppNodesInfoLoader {
 
+  /**
+   * Timeout to get information from all nodes
+   */
+  private static final long DISTRIBUTED_TIMEOUT_MS = 15_000L;
+
   private final HazelcastMember hzMember;
 
   public AppNodesInfoLoaderImpl(HazelcastMember hzMember) {
     this.hzMember = hzMember;
   }
 
-  public Collection<NodeInfo> load() {
-    try {
-      Map<String, NodeInfo> nodesByName = new HashMap<>();
-      DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer = hzMember.call(ProcessInfoProvider::provide, new CeWebMemberSelector(), 15_000L);
-      for (Member member : distributedAnswer.getMembers()) {
-        String nodeName = member.getStringAttribute(NODE_NAME.getKey());
-        NodeInfo nodeInfo = nodesByName.get(nodeName);
-        if (nodeInfo == null) {
-          nodeInfo = new NodeInfo(nodeName);
-          nodesByName.put(nodeName, nodeInfo);
-        }
-        completeNodeInfo(distributedAnswer, member, nodeInfo);
-      }
-      return nodesByName.values();
-
-    } catch (InterruptedException e) {
-      Thread.currentThread().interrupt();
-      throw new IllegalStateException(e);
+  public Collection<NodeInfo> load() throws InterruptedException {
+    Map<String, NodeInfo> nodesByName = new HashMap<>();
+    MemberSelector memberSelector = HazelcastMemberSelectors.selectorForProcessIds(ProcessId.WEB_SERVER, ProcessId.COMPUTE_ENGINE);
+    DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer = hzMember.call(ProcessInfoProvider::provide, memberSelector, DISTRIBUTED_TIMEOUT_MS);
+    for (Member member : distributedAnswer.getMembers()) {
+      String nodeName = member.getStringAttribute(NODE_NAME.getKey());
+      NodeInfo nodeInfo = nodesByName.computeIfAbsent(nodeName, NodeInfo::new);
+      completeNodeInfo(distributedAnswer, member, nodeInfo);
     }
+    return nodesByName.values();
   }
 
   private static void completeNodeInfo(DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer, Member member, NodeInfo nodeInfo) {
@@ -75,12 +71,4 @@ public class AppNodesInfoLoaderImpl implements AppNodesInfoLoader {
       nodeAnswer.get().getSectionsList().forEach(nodeInfo::addSection);
     }
   }
-
-  private static class CeWebMemberSelector implements MemberSelector {
-    @Override
-    public boolean select(Member member) {
-      String processKey = member.getStringAttribute(PROCESS_KEY.getKey());
-      return processKey.equals(ProcessId.WEB_SERVER.getKey()) || processKey.equals(ProcessId.COMPUTE_ENGINE.getKey());
-    }
-  }
 }
index 1af23c72a53ea0f67f9c0c2d200d213b1ef51406..4f2607a96cc4bdcd314273a502e6a90d5b47e881 100644 (file)
@@ -61,12 +61,12 @@ public abstract class BaseInfoWsAction implements SystemWsAction {
   }
 
   @Override
-  public void handle(Request request, Response response) {
+  public void handle(Request request, Response response) throws InterruptedException {
     userSession.checkIsSystemAdministrator();
     doHandle(request, response);
   }
 
-  protected abstract void doHandle(Request request, Response response);
+  protected abstract void doHandle(Request request, Response response) throws InterruptedException;
 
   protected void writeSections(Collection<ProtobufSystemInfo.Section> sections, JsonWriter json) {
     SystemInfoUtils
index f0208f2a84d49edc820d1158263c3c1b0bc2d5b5..35c4386502674c7a3f9fcbeeb793bf4ae9b9330b 100644 (file)
@@ -50,7 +50,7 @@ public class ClusterInfoAction extends BaseInfoWsAction {
   }
 
   @Override
-  protected void doHandle(Request request, Response response) {
+  protected void doHandle(Request request, Response response) throws InterruptedException {
     ClusterHealth clusterHealth = healthChecker.checkCluster();
     try (JsonWriter json = response.newJsonWriter()) {
       json.beginObject();
@@ -69,7 +69,8 @@ public class ClusterInfoAction extends BaseInfoWsAction {
     writeSections(globalInfoLoader.load(), json);
   }
 
-  private void writeApplicationNodes(JsonWriter json, ClusterHealth clusterHealth) {
+  private void writeApplicationNodes(JsonWriter json, ClusterHealth clusterHealth)
+    throws InterruptedException {
     json.name("Application Nodes").beginArray();
 
     Collection<NodeInfo> appNodes = appNodesInfoLoader.load();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImplTest.java
new file mode 100644 (file)
index 0000000..806e671
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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 com.hazelcast.core.Member;
+import com.hazelcast.core.MemberSelector;
+import java.io.IOException;
+import java.util.Collection;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+import org.sonar.process.cluster.hz.DistributedAnswer;
+import org.sonar.process.cluster.hz.DistributedCall;
+import org.sonar.process.cluster.hz.HazelcastMember;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.SystemInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+
+public class AppNodesInfoLoaderImplTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private HazelcastMember hzMember = mock(HazelcastMember.class);
+  private AppNodesInfoLoaderImpl underTest = new AppNodesInfoLoaderImpl(hzMember);
+
+  @Test
+  public void load_info_from_all_nodes() throws Exception {
+    DistributedAnswer<SystemInfo> answer = new DistributedAnswer<>();
+    answer.setAnswer(newMember("foo"), SystemInfo.newBuilder().addSections(Section.newBuilder().build()).build());
+    answer.setTimedOut(newMember("bar"));
+    answer.setFailed(newMember("baz"), new IOException("BOOM"));
+    when(hzMember.call(any(DistributedCall.class), any(MemberSelector.class), anyLong())).thenReturn(answer);
+
+    Collection<NodeInfo> nodes = underTest.load();
+
+    assertThat(nodes).hasSize(3);
+
+    NodeInfo successfulNodeInfo = findNode(nodes, "foo");
+    assertThat(successfulNodeInfo.getName()).isEqualTo("foo");
+    assertThat(successfulNodeInfo.getErrorMessage()).isEmpty();
+    assertThat(successfulNodeInfo.getSections()).hasSize(1);
+
+    NodeInfo timedOutNodeInfo = findNode(nodes, "bar");
+    assertThat(timedOutNodeInfo.getName()).isEqualTo("bar");
+    assertThat(timedOutNodeInfo.getErrorMessage()).hasValue("Failed to retrieve information on time");
+    assertThat(timedOutNodeInfo.getSections()).isEmpty();
+
+    NodeInfo failedNodeInfo = findNode(nodes, "baz");
+    assertThat(failedNodeInfo.getName()).isEqualTo("baz");
+    assertThat(failedNodeInfo.getErrorMessage()).hasValue("Failed to retrieve information: BOOM");
+    assertThat(failedNodeInfo.getSections()).isEmpty();
+  }
+
+  private NodeInfo findNode(Collection<NodeInfo> nodes, String name) {
+    return nodes.stream()
+      .filter(n -> n.getName().equals(name))
+      .findFirst()
+      .orElseThrow(IllegalStateException::new);
+  }
+
+  private Member newMember(String name) {
+    Member member = mock(Member.class, Mockito.RETURNS_DEEP_STUBS);
+    when(member.getStringAttribute(HazelcastMember.Attribute.NODE_NAME.getKey())).thenReturn(name);
+    return member;
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoaderTest.java
new file mode 100644 (file)
index 0000000..df950be
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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 java.util.List;
+import org.junit.Test;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class GlobalInfoLoaderTest {
+
+  @Test
+  public void call_only_SystemInfoSection_that_inherit_Global() {
+    // two globals and one standard
+    SystemInfoSection[] sections = new SystemInfoSection[] {
+      new TestGlobalSystemInfoSection("foo"), new TestSystemInfoSection("bar"), new TestGlobalSystemInfoSection("baz")};
+
+    GlobalInfoLoader underTest = new GlobalInfoLoader(sections);
+    List<ProtobufSystemInfo.Section> loadedInfo = underTest.load();
+
+    assertThat(loadedInfo).extracting(ProtobufSystemInfo.Section::getName)
+      .containsExactlyInAnyOrder("foo", "baz");
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSectionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSectionTest.java
new file mode 100644 (file)
index 0000000..5d663f5
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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 java.util.Optional;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.security.SecurityRealm;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.authentication.IdentityProviderRepositoryRule;
+import org.sonar.server.authentication.TestIdentityProvider;
+import org.sonar.server.platform.ServerId;
+import org.sonar.server.platform.ServerIdLoader;
+import org.sonar.server.user.SecurityRealmFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+
+public class GlobalSystemSectionTest {
+
+  private static final String SERVER_ID_PROPERTY = "Server ID";
+  private static final String SERVER_ID_VALIDATED_PROPERTY = "Server ID validated";
+
+  @Rule
+  public IdentityProviderRepositoryRule identityProviderRepository = new IdentityProviderRepositoryRule();
+
+  private MapSettings settings = new MapSettings();
+  private ServerIdLoader serverIdLoader = mock(ServerIdLoader.class);
+  private SecurityRealmFactory securityRealmFactory = mock(SecurityRealmFactory.class);
+
+  private GlobalSystemSection underTest = new GlobalSystemSection(settings.asConfig(),
+    serverIdLoader, securityRealmFactory, identityProviderRepository);
+
+  @Before
+  public void setUp() throws Exception {
+    when(serverIdLoader.getRaw()).thenReturn(Optional.empty());
+    when(serverIdLoader.get()).thenReturn(Optional.empty());
+  }
+
+  @Test
+  public void name_is_not_empty() {
+    assertThat(underTest.toProtobuf().getName()).isEqualTo("System");
+  }
+
+  @Test
+  public void attributes_contain_information_about_valid_server_id() {
+    when(serverIdLoader.get()).thenReturn(Optional.of(new ServerId("ABC", true)));
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThatAttributeIs(protobuf, SERVER_ID_PROPERTY, "ABC");
+    assertThatAttributeIs(protobuf, SERVER_ID_VALIDATED_PROPERTY, true);
+  }
+
+  @Test
+  public void attributes_contain_information_about_non_valid_server_id() {
+    when(serverIdLoader.get()).thenReturn(Optional.of(new ServerId("ABC", false)));
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThatAttributeIs(protobuf, SERVER_ID_PROPERTY, "ABC");
+    assertThatAttributeIs(protobuf, SERVER_ID_VALIDATED_PROPERTY, false);
+  }
+
+  @Test
+  public void attributes_do_not_contain_information_about_server_id_if_absent() {
+    when(serverIdLoader.get()).thenReturn(Optional.empty());
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThat(attribute(protobuf, SERVER_ID_PROPERTY)).isNull();
+    assertThat(attribute(protobuf, SERVER_ID_VALIDATED_PROPERTY)).isNull();
+  }
+
+  @Test
+  public void get_realm() throws Exception {
+    SecurityRealm realm = mock(SecurityRealm.class);
+    when(realm.getName()).thenReturn("LDAP");
+    when(securityRealmFactory.getRealm()).thenReturn(realm);
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThatAttributeIs(protobuf, "External User Authentication", "LDAP");
+  }
+
+  @Test
+  public void no_realm() throws Exception {
+    when(securityRealmFactory.getRealm()).thenReturn(null);
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThat(attribute(protobuf, "External User Authentication")).isNull();
+  }
+
+  @Test
+  public void get_enabled_identity_providers() throws Exception {
+    identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+      .setKey("github")
+      .setName("GitHub")
+      .setEnabled(true));
+    identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+      .setKey("bitbucket")
+      .setName("Bitbucket")
+      .setEnabled(true));
+    identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+      .setKey("disabled")
+      .setName("Disabled")
+      .setEnabled(false));
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThatAttributeIs(protobuf, "Accepted external identity providers", "Bitbucket, GitHub");
+  }
+
+  @Test
+  public void get_enabled_identity_providers_allowing_users_to_signup() throws Exception {
+    identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+      .setKey("github")
+      .setName("GitHub")
+      .setEnabled(true)
+      .setAllowsUsersToSignUp(true));
+    identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+      .setKey("bitbucket")
+      .setName("Bitbucket")
+      .setEnabled(true)
+      .setAllowsUsersToSignUp(false));
+    identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+      .setKey("disabled")
+      .setName("Disabled")
+      .setEnabled(false)
+      .setAllowsUsersToSignUp(true));
+
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThatAttributeIs(protobuf, "External identity providers whose users are allowed to sign themselves up", "GitHub");
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/LoggingSectionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/LoggingSectionTest.java
new file mode 100644 (file)
index 0000000..91a704b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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 java.io.File;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.platform.ServerLogging;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class LoggingSectionTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  private SonarRuntime runtime = mock(SonarRuntime.class);
+  private ServerLogging logging = mock(ServerLogging.class);
+  private File logDir;
+  private LoggingSection underTest = new LoggingSection(runtime, logging);
+
+  @Before
+  public void setUp() throws Exception {
+    logDir = temp.newFolder();
+    when(logging.getLogsDir()).thenReturn(logDir);
+    when(logging.getRootLoggerLevel()).thenReturn(LoggerLevel.DEBUG);
+  }
+
+  @Test
+  public void return_logging_attributes_of_compute_engine() {
+    when(runtime.getSonarQubeSide()).thenReturn(SonarQubeSide.COMPUTE_ENGINE);
+
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+    assertThat(section.getName()).isEqualTo("Compute Engine Logging");
+    assertThatAttributeIs(section, "Logs Dir", logDir.getAbsolutePath());
+    assertThatAttributeIs(section, "Logs Level", "DEBUG");
+  }
+
+  @Test
+  public void return_logging_attributes_of_web_server() {
+    when(runtime.getSonarQubeSide()).thenReturn(SonarQubeSide.SERVER);
+
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+    assertThat(section.getName()).isEqualTo("Web Logging");
+    assertThatAttributeIs(section, "Logs Dir", logDir.getAbsolutePath());
+    assertThatAttributeIs(section, "Logs Level", "DEBUG");
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSectionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSectionTest.java
new file mode 100644 (file)
index 0000000..8dd1ab5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.platform.Server;
+import org.sonar.process.ProcessProperties;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.platform.monitoring.OfficialDistribution;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+
+public class NodeSystemSectionTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private MapSettings settings = new MapSettings();
+  private Server server = mock(Server.class, RETURNS_DEEP_STUBS);
+  private OfficialDistribution officialDistrib = mock(OfficialDistribution.class);
+  private NodeSystemSection underTest = new NodeSystemSection(settings.asConfig(), server, officialDistrib);
+
+  @Test
+  public void test_section_name() {
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+    assertThat(section.getName()).isEqualTo("System");
+  }
+
+  @Test
+  public void return_server_version() {
+    when(server.getVersion()).thenReturn("6.6");
+
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+    assertThatAttributeIs(section, "Version", "6.6");
+  }
+
+  @Test
+  public void return_official_distribution_flag() {
+    when(officialDistrib.check()).thenReturn(true);
+
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+    assertThatAttributeIs(section, "Official Distribution", true);
+  }
+
+  @Test
+  public void return_nb_of_processors() {
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+    assertThat(attribute(section, "Processors").getLongValue()).isGreaterThan(0);
+  }
+
+  @Test
+  public void return_dir_paths() {
+    settings.setProperty(ProcessProperties.PATH_HOME, "/home");
+    settings.setProperty(ProcessProperties.PATH_DATA, "/data");
+    settings.setProperty(ProcessProperties.PATH_TEMP, "/temp");
+    settings.setProperty(ProcessProperties.PATH_LOGS, "/logs");
+    settings.setProperty(ProcessProperties.PATH_WEB, "/web");
+
+    ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+    assertThatAttributeIs(section, "Home Dir", "/home");
+    assertThatAttributeIs(section, "Data Dir", "/data");
+    assertThatAttributeIs(section, "Temp Dir", "/temp");
+
+    // logs dir is part of LoggingSection
+    assertThat(attribute(section, "Logs Dir")).isNull();
+
+    // for internal usage
+    assertThat(attribute(section, "Web Dir")).isNull();
+
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProviderTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProviderTest.java
new file mode 100644 (file)
index 0000000..afc2ebc
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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 java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProcessInfoProviderTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Test
+  public void set_self_as_statically_shared_instance() {
+    ProcessInfoProvider underTest = new ProcessInfoProvider(new SystemInfoSection[0]);
+
+    underTest.start();
+    assertThat(ProcessInfoProvider.provide()).isNotNull();
+
+    underTest.stop();
+
+    expectedException.expect(NullPointerException.class);
+    ProcessInfoProvider.provide();
+  }
+
+  @Test
+  public void remove_global_sections_from_results() {
+    ProcessInfoProvider underTest = new ProcessInfoProvider(new SystemInfoSection[]{
+      new TestGlobalSystemInfoSection("foo"),
+      new TestSystemInfoSection("bar")});
+
+    underTest.start();
+    List<ProtobufSystemInfo.Section> sections = ProcessInfoProvider.provide().getSectionsList();
+    assertThat(sections).extracting(ProtobufSystemInfo.Section::getName).containsExactly("bar");
+
+    underTest.stop();
+  }
+
+  @Test
+  public void merge_sections() {
+    ProcessInfoProvider underTest = new ProcessInfoProvider(new SystemInfoSection[]{
+      new TestSystemInfoSection("foo"),
+      new TestSystemInfoSection("bar")});
+
+    underTest.start();
+    List<ProtobufSystemInfo.Section> sections = ProcessInfoProvider.provide().getSectionsList();
+    assertThat(sections).extracting(ProtobufSystemInfo.Section::getName)
+      .containsExactlyInAnyOrder("foo", "bar");
+
+    underTest.stop();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImplTest.java
new file mode 100644 (file)
index 0000000..ebb96e3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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 java.util.Collection;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.es.FakeIndexDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SearchNodesInfoLoaderImplTest {
+
+  @Rule
+  public EsTester es = new EsTester(new FakeIndexDefinition());
+
+  private SearchNodesInfoLoaderImpl underTest = new SearchNodesInfoLoaderImpl(es.client());
+
+  @Test
+  public void return_info_from_elasticsearch_api() {
+    Collection<NodeInfo> nodes = underTest.load();
+
+    assertThat(nodes).hasSize(1);
+    NodeInfo node = nodes.iterator().next();
+    assertThat(node.getName()).isNotEmpty();
+    assertThat(node.getSections()).hasSize(1);
+    ProtobufSystemInfo.Section stateSection = node.getSections().get(0);
+
+    assertThat(stateSection.getAttributesList())
+      .extracting(ProtobufSystemInfo.Attribute::getKey)
+      .contains(
+        "Disk Available", "Store Size",
+        "JVM Heap Usage", "JVM Heap Used", "JVM Heap Max", "JVM Non Heap Used",
+        "JVM Threads",
+        "Field Data Memory", "Field Data Circuit Breaker Limit", "Field Data Circuit Breaker Estimation",
+        "Request Circuit Breaker Limit", "Request Circuit Breaker Estimation",
+        "Query Cache Memory", "Request Cache Memory");
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/TestGlobalSystemInfoSection.java
new file mode 100644 (file)
index 0000000..1584360
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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/src/test/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/TestSystemInfoSection.java
new file mode 100644 (file)
index 0000000..a682f43
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this 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();
+  }
+}