diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2016-03-31 12:20:55 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2016-04-05 09:58:04 +0200 |
commit | 975158a5a726aa67c093f85779ac2c97efd03bb8 (patch) | |
tree | f2feb4851f4a0e2a6723e20d182413a01aeffade /server/sonar-process | |
parent | 87d559b07cdc6727dafe0c9e1286b30c8e7867ea (diff) | |
download | sonarqube-975158a5a726aa67c093f85779ac2c97efd03bb8.tar.gz sonarqube-975158a5a726aa67c093f85779ac2c97efd03bb8.zip |
SONAR-7436 replace JMX/RMI by HTTP
Diffstat (limited to 'server/sonar-process')
22 files changed, 415 insertions, 578 deletions
diff --git a/server/sonar-process/pom.xml b/server/sonar-process/pom.xml index 3bd9cfc33d7..ee7d279fc2f 100644 --- a/server/sonar-process/pom.xml +++ b/server/sonar-process/pom.xml @@ -29,12 +29,23 @@ <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> </dependency> - <dependency> <groupId>com.google.code.findbugs</groupId> <artifactId>jsr305</artifactId> <scope>provided</scope> </dependency> + <dependency> + <!-- only if org.sonar.process.systeminfo HTTP server is being used --> + <groupId>org.nanohttpd</groupId> + <artifactId>nanohttpd</artifactId> + <optional>true</optional> + </dependency> + <dependency> + <!-- only if org.sonar.process.systeminfo.protobuf classes are used --> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + <optional>true</optional> + </dependency> <dependency> <groupId>${project.groupId}</groupId> @@ -56,6 +67,11 @@ <artifactId>jetty-server</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>com.squareup.okhttp</groupId> + <artifactId>okhttp</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java b/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java index 9652aca6795..f5e0954f6ff 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java @@ -69,11 +69,11 @@ public class AllProcessesCommands implements AutoCloseable { private static final int RESTART_BYTE_OFFSET = 2; private static final int OPERATIONAL_BYTE_OFFSET = 3; private static final int PING_BYTE_OFFSET = 4; - private static final int JMX_URL_BYTE_OFFSET = PING_BYTE_OFFSET + 8; + private static final int SYSTEM_INFO_URL_BYTE_OFFSET = PING_BYTE_OFFSET + 8; - private static final int JMX_URL_SIZE_IN_BYTES = 500; + private static final int SYSTEM_INFO_URL_SIZE_IN_BYTES = 500; - private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8 + JMX_URL_SIZE_IN_BYTES; + private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8 + SYSTEM_INFO_URL_SIZE_IN_BYTES; // With this shared memory we can handle up to MAX_PROCESSES processes private static final int MAX_SHARED_MEMORY = BYTE_LENGTH_FOR_ONE_PROCESS * MAX_PROCESSES; @@ -148,17 +148,17 @@ public class AllProcessesCommands implements AutoCloseable { return readLong(processNumber, PING_BYTE_OFFSET); } - String getJmxUrl(int processNumber) { - byte[] urlBytes = readBytes(processNumber, JMX_URL_BYTE_OFFSET, JMX_URL_SIZE_IN_BYTES); + String getSystemInfoUrl(int processNumber) { + byte[] urlBytes = readBytes(processNumber, SYSTEM_INFO_URL_BYTE_OFFSET, SYSTEM_INFO_URL_SIZE_IN_BYTES); return new String(urlBytes, StandardCharsets.US_ASCII).trim(); } - void setJmxUrl(int processNumber, String jmxUrl) { - byte[] urlBytes = rightPad(jmxUrl, JMX_URL_SIZE_IN_BYTES).getBytes(StandardCharsets.US_ASCII); - if (urlBytes.length > JMX_URL_SIZE_IN_BYTES) { - throw new IllegalArgumentException(format("JMX URL is too long. Max is %d bytes. Got: %s", JMX_URL_SIZE_IN_BYTES, jmxUrl)); + void setSystemInfoUrl(int processNumber, String url) { + byte[] urlBytes = rightPad(url, SYSTEM_INFO_URL_SIZE_IN_BYTES).getBytes(StandardCharsets.US_ASCII); + if (urlBytes.length > SYSTEM_INFO_URL_SIZE_IN_BYTES) { + throw new IllegalArgumentException(format("System Info URL is too long. Max is %d bytes. Got: %s", SYSTEM_INFO_URL_SIZE_IN_BYTES, url)); } - writeBytes(processNumber, JMX_URL_BYTE_OFFSET, urlBytes); + writeBytes(processNumber, SYSTEM_INFO_URL_BYTE_OFFSET, urlBytes); } /** @@ -277,13 +277,13 @@ public class AllProcessesCommands implements AutoCloseable { } @Override - public void setJmxUrl(String s) { - AllProcessesCommands.this.setJmxUrl(processNumber, s); + public void setSystemInfoUrl(String s) { + AllProcessesCommands.this.setSystemInfoUrl(processNumber, s); } @Override - public String getJmxUrl() { - return AllProcessesCommands.this.getJmxUrl(processNumber); + public String getSystemInfoUrl() { + return AllProcessesCommands.this.getSystemInfoUrl(processNumber); } @Override diff --git a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java index d8c9975a4ba..dade6ab6265 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java @@ -83,13 +83,13 @@ public class DefaultProcessCommands implements ProcessCommands { } @Override - public void setJmxUrl(String s) { - delegate.setJmxUrl(s); + public void setSystemInfoUrl(String s) { + delegate.setSystemInfoUrl(s); } @Override - public String getJmxUrl() { - return delegate.getJmxUrl(); + public String getSystemInfoUrl() { + return delegate.getSystemInfoUrl(); } @Override diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java b/server/sonar-process/src/main/java/org/sonar/process/Jmx.java index 62375a32e83..76a7b03c639 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java +++ b/server/sonar-process/src/main/java/org/sonar/process/Jmx.java @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.process.jmx; +package org.sonar.process; import java.lang.management.ManagementFactory; import javax.management.InstanceAlreadyExistsException; diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java index 01ece9a7060..9c2f4a35a62 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java @@ -55,9 +55,9 @@ public interface ProcessCommands extends AutoCloseable { long getLastPing(); - void setJmxUrl(String s); + void setSystemInfoUrl(String s); - String getJmxUrl(); + String getSystemInfoUrl(); /** * To be executed by monitor process to ask for child process termination diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java index f77cc7c292a..2ca262205ce 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java @@ -22,7 +22,6 @@ package org.sonar.process; import java.io.File; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sun.misc.VMSupport; public class ProcessEntryPoint implements Stoppable { @@ -107,10 +106,6 @@ public class ProcessEntryPoint implements Stoppable { Thread.sleep(20L); } - String jmxUrl = guessJmxUrl(); - logger.debug("JMX URL is {}", jmxUrl); - commands.setJmxUrl(jmxUrl); - // notify monitor that process is ready commands.setUp(); @@ -125,15 +120,6 @@ public class ProcessEntryPoint implements Stoppable { } } - private static String guessJmxUrl() { - // this property is set by the agent management-agent.jar enabled by org.sonar.process.monitor.JavaProcessLauncher. - String jmxUrl = VMSupport.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); - if (jmxUrl == null) { - throw new IllegalStateException("Fail to load the JMX URL of JVM " + System.getProperty("java.vm.name")); - } - return jmxUrl; - } - boolean isStarted() { return lifecycle.getState() == Lifecycle.State.STARTED; } diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java deleted file mode 100644 index 354ce0db734..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -public interface CeDatabaseMBean { - - String OBJECT_NAME = "SonarQube:name=ComputeEngineDatabase"; - - int getPoolActiveConnections(); - - int getPoolMaxActiveConnections(); - - int getPoolIdleConnections(); - - int getPoolMaxIdleConnections(); - - int getPoolMinIdleConnections(); - - int getPoolInitialSize(); - - long getPoolMaxWaitMillis(); - - boolean getPoolRemoveAbandoned(); - - int getPoolRemoveAbandonedTimeoutSeconds(); -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java deleted file mode 100644 index 968dabc52b2..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -public interface CeTasksMBean { - - String OBJECT_NAME = "SonarQube:name=ComputeEngineTasks"; - - /** - * Count of batch reports waiting for processing since startup, including reports received before instance startup. - */ - long getPendingCount(); - - /** - * Count of batch reports under processing. - */ - long getInProgressCount(); - - /** - * Count of batch reports which processing ended with an error since instance startup. - */ - long getErrorCount(); - - /** - * Count of batch reports which processing ended successfully since instance startup. - */ - long getSuccessCount(); - - /** - * Time spent processing reports since startup, in milliseconds. - */ - long getProcessingTime(); - - /** - * Configured number of Workers. - */ - int getWorkerCount(); -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java deleted file mode 100644 index 4c2eaca5452..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; -import java.lang.management.MemoryUsage; -import java.lang.management.ThreadMXBean; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.annotation.CheckForNull; -import javax.management.JMX; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; - -import static java.lang.String.format; - -public class JmxConnection implements AutoCloseable { - - private static final long MEGABYTE = 1024L * 1024L; - private final JMXConnector jmxConnector; - - JmxConnection(JMXConnector jmxConnector) { - this.jmxConnector = jmxConnector; - } - - /** - * Get a MBean from a remote JMX server. - * @throws IllegalStateException if a valid - * connection to remote server cannot be created, for instance because the connection to has - * not yet been established (with {@link JMXConnector#connect()}), or it has been closed/broken. - */ - public <M> M getMBean(String mBeanName, Class<M> mBeanInterfaceClass) { - try { - MBeanServerConnection connection = jmxConnector.getMBeanServerConnection(); - if (mBeanName.startsWith("java.lang")) { - return ManagementFactory.newPlatformMXBeanProxy(connection, mBeanName, mBeanInterfaceClass); - } - return JMX.newMBeanProxy(connection, new ObjectName(mBeanName), mBeanInterfaceClass); - } catch (Exception e) { - throw new IllegalStateException(format("Fail to connect to MBean [%s]", mBeanName), e); - } - } - - public Map<String, Object> getSystemState() { - Map<String, Object> props = new LinkedHashMap<>(); - MemoryMXBean memory = getMBean(ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class); - MemoryUsage heap = memory.getHeapMemoryUsage(); - props.put("Heap Committed (MB)", toMegaBytes(heap.getCommitted())); - props.put("Heap Init (MB)", toMegaBytes(heap.getInit())); - props.put("Heap Max (MB)", toMegaBytes(heap.getMax())); - props.put("Heap Used (MB)", toMegaBytes(heap.getUsed())); - MemoryUsage nonHeap = memory.getNonHeapMemoryUsage(); - props.put("Non Heap Committed (MB)", toMegaBytes(nonHeap.getCommitted())); - props.put("Non Heap Init (MB)", toMegaBytes(nonHeap.getInit())); - props.put("Non Heap Max (MB)", toMegaBytes(nonHeap.getMax())); - props.put("Non Heap Used (MB)", toMegaBytes(nonHeap.getUsed())); - ThreadMXBean thread = getMBean(ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class); - props.put("Thread Count", thread.getThreadCount()); - return props; - } - - // visible for testing - @CheckForNull - static Long toMegaBytes(long bytes) { - if (bytes < 0L) { - return null; - } - return bytes / MEGABYTE; - } - - @Override - public void close() { - try { - jmxConnector.close(); - } catch (IOException e) { - throw new IllegalStateException("Can not close JMX connector", e); - } - } -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java deleted file mode 100644 index 29383cc211e..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -import java.io.File; -import javax.annotation.CheckForNull; -import javax.annotation.concurrent.Immutable; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; -import org.sonar.process.DefaultProcessCommands; -import org.sonar.process.ProcessEntryPoint; -import org.sonar.process.ProcessId; -import org.sonar.process.Props; - -/** - * Connects to JMX of other JVM processes - */ -@Immutable -public class JmxConnectionFactory { - private final File ipcSharedDir; - - public JmxConnectionFactory(File ipcSharedDir) { - this.ipcSharedDir = ipcSharedDir; - } - - public JmxConnectionFactory(Props props) { - this.ipcSharedDir = props.nonNullValueAsFile(ProcessEntryPoint.PROPERTY_SHARED_PATH); - } - - @CheckForNull - public JmxConnection create(ProcessId processId) { - try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(ipcSharedDir, processId.getIpcIndex())) { - if (commands.isUp()) { - String url = commands.getJmxUrl(); - JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(new JMXServiceURL(url), null); - jmxConnector.connect(); - return new JmxConnection(jmxConnector); - } - return null; - } catch (Exception e) { - throw new IllegalStateException("Can not connect to process " + processId, e); - } - } - - // visible for testing - File getIpcSharedDir() { - return ipcSharedDir; - } -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/ProcessStateSystemInfo.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/ProcessStateSystemInfo.java new file mode 100644 index 00000000000..1ca9297ee33 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/ProcessStateSystemInfo.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.systeminfo; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; +import java.lang.management.ThreadMXBean; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +public class ProcessStateSystemInfo implements SystemInfoSection { + private static final long MEGABYTE = 1024L * 1024L; + private final String name; + + public ProcessStateSystemInfo(String name) { + this.name = name; + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + return toProtobuf(ManagementFactory.getMemoryMXBean()); + } + + // Visible for testing + ProtobufSystemInfo.Section toProtobuf(MemoryMXBean memoryBean) { + ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder(); + builder.setName(name); + MemoryUsage heap = memoryBean.getHeapMemoryUsage(); + addAttributeInMb(builder, "Heap Committed (MB)", heap.getCommitted()); + addAttributeInMb(builder, "Heap Init (MB)", heap.getInit()); + addAttributeInMb(builder, "Heap Max (MB)", heap.getMax()); + addAttributeInMb(builder, "Heap Used (MB)", heap.getUsed()); + MemoryUsage nonHeap = memoryBean.getNonHeapMemoryUsage(); + addAttributeInMb(builder, "Non Heap Committed (MB)", nonHeap.getCommitted()); + addAttributeInMb(builder, "Non Heap Init (MB)", nonHeap.getInit()); + addAttributeInMb(builder, "Non Heap Max (MB)", nonHeap.getMax()); + addAttributeInMb(builder, "Non Heap Used (MB)", nonHeap.getUsed()); + ThreadMXBean thread = ManagementFactory.getThreadMXBean(); + builder.addAttributesBuilder().setKey("Thread Count").setLongValue(thread.getThreadCount()).build(); + return builder.build(); + } + + private void addAttributeInMb(ProtobufSystemInfo.Section.Builder builder, String key, long valueInBytes) { + if (valueInBytes >= 0L) { + builder.addAttributesBuilder().setKey(key).setLongValue(valueInBytes / MEGABYTE).build(); + } + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java new file mode 100644 index 00000000000..b8c08f3b90c --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java @@ -0,0 +1,104 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.systeminfo; + +import fi.iki.elonen.NanoHTTPD; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Properties; +import org.slf4j.LoggerFactory; +import org.sonar.process.DefaultProcessCommands; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static java.lang.Integer.parseInt; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; + +/** + * This HTTP server exports data required for display of System Info page (and the related web service). + * It listens on loopback address only, so it does not need to be secure (no HTTPS, no authentication). + */ +public class SystemInfoHttpServer { + + private static final String PROTOBUF_MIME_TYPE = "application/x-protobuf"; + + private final Properties processProps; + private final List<SystemInfoSection> sectionProviders; + private final SystemInfoNanoHttpd nanoHttpd; + + public SystemInfoHttpServer(Properties processProps, List<SystemInfoSection> sectionProviders) throws UnknownHostException { + this.processProps = processProps; + this.sectionProviders = sectionProviders; + InetAddress loopbackAddress = InetAddress.getByName(null); + this.nanoHttpd = new SystemInfoNanoHttpd(loopbackAddress.getHostAddress(), 0); + } + + // do not rename. This naming convention is required for picocontainer. + public void start() { + try { + nanoHttpd.start(); + registerHttpUrl(); + } catch (IOException e) { + throw new IllegalStateException("Can not start local HTTP server for System Info monitoring", e); + } + } + + private void registerHttpUrl() { + int processNumber = parseInt(processProps.getProperty(PROPERTY_PROCESS_INDEX)); + File shareDir = new File(processProps.getProperty(PROPERTY_SHARED_PATH)); + try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(shareDir, processNumber)) { + String url = getUrl(); + commands.setSystemInfoUrl(url); + LoggerFactory.getLogger(getClass()).debug("System Info HTTP server listening at {}", url); + } + } + + // do not rename. This naming convention is required for picocontainer. + public void stop() { + nanoHttpd.stop(); + } + + // visible for testing + String getUrl() { + return "http://" + nanoHttpd.getHostname() + ":" + nanoHttpd.getListeningPort(); + } + + private class SystemInfoNanoHttpd extends NanoHTTPD { + + SystemInfoNanoHttpd(String hostname, int port) { + super(hostname, port); + } + + @Override + public Response serve(IHTTPSession session) { + ProtobufSystemInfo.SystemInfo.Builder infoBuilder = ProtobufSystemInfo.SystemInfo.newBuilder(); + for (SystemInfoSection sectionProvider : sectionProviders) { + ProtobufSystemInfo.Section section = sectionProvider.toProtobuf(); + infoBuilder.addSections(section); + } + byte[] bytes = infoBuilder.build().toByteArray(); + return newFixedLengthResponse(Response.Status.OK, PROTOBUF_MIME_TYPE, new ByteArrayInputStream(bytes), bytes.length); + } + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoSection.java index 197dc35051c..c990cacb96b 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoSection.java @@ -17,22 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.process.jmx; +package org.sonar.process.systeminfo; -/** - * MBean registered in the Elasticsearch process - */ -public interface EsSettingsMBean { - - String OBJECT_NAME = "SonarQube:name=ElasticsearchSettings"; - - /** - * @return the enabled HTTP port, -1 if disabled - */ - int getHttpPort(); +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; - String getClusterName(); +public interface SystemInfoSection { - String getNodeName(); + ProtobufSystemInfo.Section toProtobuf(); } diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/package-info.java index bb4fb97207f..3ae1af74953 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/package-info.java @@ -18,6 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @ParametersAreNonnullByDefault -package org.sonar.process.jmx; +package org.sonar.process.systeminfo; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-process/src/main/protobuf/process_system_info.proto b/server/sonar-process/src/main/protobuf/process_system_info.proto new file mode 100644 index 00000000000..8780b677596 --- /dev/null +++ b/server/sonar-process/src/main/protobuf/process_system_info.proto @@ -0,0 +1,43 @@ +// SonarQube, open source software quality management tool. +// Copyright (C) 2008-2016 SonarSource +// mailto:contact AT sonarsource DOT com +// +// SonarQube is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// SonarQube is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +syntax = "proto3"; + +option java_package = "org.sonar.process.systeminfo.protobuf"; +option java_outer_classname = "ProtobufSystemInfo"; + +option optimize_for = SPEED; + +message SystemInfo { + repeated Section sections = 1; +} + +message Section { + string name = 1; + repeated Attribute attributes = 2; +} + +message Attribute { + string key = 1; + oneof value { + bool boolean_value = 2; + int64 long_value = 3; + double double_value = 4; + string string_value = 5; + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java index e834fce905f..1c26836fc1e 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java @@ -105,9 +105,9 @@ public class AllProcessesCommandsTest { assertThat(readByte(commands, offset + i)).isEqualTo(EMPTY); } - commands.setJmxUrl(PROCESS_NUMBER, "jmx:foo"); + commands.setSystemInfoUrl(PROCESS_NUMBER, "jmx:foo"); assertThat(readByte(commands, offset)).isNotEqualTo(EMPTY); - assertThat(commands.getJmxUrl(PROCESS_NUMBER)).isEqualTo("jmx:foo"); + assertThat(commands.getSystemInfoUrl(PROCESS_NUMBER)).isEqualTo("jmx:foo"); } @Test diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java b/server/sonar-process/src/test/java/org/sonar/process/JmxTest.java index 9b241accac3..7df06238d94 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/JmxTest.java @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.process.jmx; +package org.sonar.process; import java.lang.management.ManagementFactory; import javax.annotation.CheckForNull; @@ -27,6 +27,8 @@ import javax.management.ObjectName; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.process.jmx.Fake; +import org.sonar.process.jmx.FakeMBean; import static org.assertj.core.api.Assertions.assertThat; @@ -65,6 +67,14 @@ public class JmxTest { } @Test + public void register_fails_if_name_is_not_valid() { + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Can not register MBean [/]"); + + Jmx.register("/", new Fake()); + } + + @Test public void support_implementation_in_different_package_than_interface() throws Exception { assertThat(lookupMBean()).isNull(); diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java deleted file mode 100644 index 4709acb83d3..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -import java.io.File; -import java.util.Properties; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.process.DefaultProcessCommands; -import org.sonar.process.ProcessId; -import org.sonar.process.Props; - -import static org.assertj.core.api.Assertions.assertThat; - -public class JmxConnectionFactoryTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public JmxTestServer jmxServer = new JmxTestServer(); - - @Test - public void create_returns_null_if_process_is_down() throws Exception { - File ipcSharedDir = temp.newFolder(); - JmxConnectionFactory underTest = new JmxConnectionFactory(ipcSharedDir); - - JmxConnection connection = underTest.create(ProcessId.COMPUTE_ENGINE); - - assertThat(connection).isNull(); - } - - @Test - public void create_connection_if_process_is_up() throws Exception { - File ipcSharedDir = temp.newFolder(); - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, ProcessId.COMPUTE_ENGINE.getIpcIndex())) { - processCommands.setUp(); - processCommands.setJmxUrl(jmxServer.getAddress().toString()); - } - - JmxConnection connection = new JmxConnectionFactory(ipcSharedDir).create(ProcessId.COMPUTE_ENGINE); - assertThat(connection).isNotNull(); - } - - @Test - public void create_throws_ISE_if_fails_to_connect_to_process() throws Exception { - File ipcSharedDir = temp.newFolder(); - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, ProcessId.COMPUTE_ENGINE.getIpcIndex())) { - // process is up but does not have any JMX URL - processCommands.setUp(); - } - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Can not connect to process " + ProcessId.COMPUTE_ENGINE.toString()); - new JmxConnectionFactory(ipcSharedDir).create(ProcessId.COMPUTE_ENGINE); - } - - @Test - public void load_ipc_shared_dir_from_props() throws Exception { - File ipcSharedDir = temp.newFolder(); - Properties props = new Properties(); - props.setProperty("process.sharedDir", ipcSharedDir.getAbsolutePath()); - - JmxConnectionFactory underTest = new JmxConnectionFactory(new Props(props)); - - assertThat(underTest.getIpcSharedDir().getCanonicalPath()).isEqualTo(ipcSharedDir.getCanonicalPath()); - } - -} diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java deleted file mode 100644 index efb7f83701f..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.util.Map; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.assertj.core.api.Assertions.assertThat; - -public class JmxConnectionTest { - - private static final String CUSTOM_OBJECT_NAME = "Test:name=test"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public JmxTestServer jmxServer = new JmxTestServer(); - - JmxConnection underTest; - - @Before - public void setUp() throws Exception { - jmxServer.getMBeanServer().registerMBean(new Fake(), new ObjectName(CUSTOM_OBJECT_NAME)); - JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(jmxServer.getAddress(), null); - jmxConnector.connect(); - underTest = new JmxConnection(jmxConnector); - } - - @After - public void tearDown() throws Exception { - underTest.close(); - jmxServer.getMBeanServer().unregisterMBean(new ObjectName(CUSTOM_OBJECT_NAME)); - } - - @Test - public void toMegaBytes() { - assertThat(JmxConnection.toMegaBytes(-1)).isNull(); - assertThat(JmxConnection.toMegaBytes(0L)).isEqualTo(0L); - assertThat(JmxConnection.toMegaBytes(500L)).isEqualTo(0L); - assertThat(JmxConnection.toMegaBytes(500_000L)).isEqualTo(0L); - assertThat(JmxConnection.toMegaBytes(500_000_000L)).isEqualTo(476L); - } - - @Test - public void get_platform_mbean() throws Exception { - RuntimeMXBean runtimeMBean = underTest.getMBean(ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); - - assertThat(runtimeMBean).isNotNull(); - } - - @Test - public void get_custom_mbean() throws Exception { - FakeMBean mbean = underTest.getMBean(CUSTOM_OBJECT_NAME, FakeMBean.class); - - assertThat(mbean).isNotNull(); - } - - @Test - public void getMBean_fails_if_does_not_exist() throws Exception { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Fail to connect to MBean [unknown]"); - underTest.getMBean("unknown", FakeMBean.class); - } - - @Test - public void getSystemState() throws Exception { - Map<String, Object> state = underTest.getSystemState(); - assertThat(state).containsKey("Heap Max (MB)"); - assertThat((int) state.get("Thread Count")).isGreaterThan(0); - } -} diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java deleted file mode 100644 index 9ffe8413bef..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process.jmx; - -import com.google.common.base.Throwables; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.rmi.registry.LocateRegistry; -import java.util.HashMap; -import javax.management.MBeanServer; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; -import org.junit.rules.ExternalResource; -import org.sonar.process.NetworkUtils; - -public class JmxTestServer extends ExternalResource { - - private final int jmxPort = NetworkUtils.freePort(); - private JMXConnectorServer jmxServer; - - @Override - protected void before() throws Throwable { - LocateRegistry.createRegistry(jmxPort); - JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:rmi://localhost:" + jmxPort + "/jndi/rmi://localhost:" + jmxPort + "/jmxrmi"); - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - jmxServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, new HashMap<String, Object>(), mbeanServer); - jmxServer.start(); - - } - - @Override - protected void after() { - if (jmxServer != null) { - try { - jmxServer.stop(); - } catch (IOException e) { - throw Throwables.propagate(e); - } - } - } - - public int getPort() { - return jmxPort; - } - - public MBeanServer getMBeanServer() { - return jmxServer.getMBeanServer(); - } - - public JMXServiceURL getAddress() { - return jmxServer.getAddress(); - } -} diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.java new file mode 100644 index 00000000000..b1088a07584 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.java @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.systeminfo; + +import java.lang.management.MemoryMXBean; +import org.junit.Test; +import org.mockito.Mockito; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ProcessStateSystemInfoTest { + + public static final String PROCESS_NAME = "the process name"; + + @Test + public void toSystemInfoSection() { + ProcessStateSystemInfo underTest = new ProcessStateSystemInfo(PROCESS_NAME); + ProtobufSystemInfo.Section section = underTest.toProtobuf(); + + assertThat(section.getName()).isEqualTo(PROCESS_NAME); + assertThat(section.getAttributesCount()).isEqualTo(9); + assertThat(section.getAttributes(0).getKey()).isEqualTo("Heap Committed (MB)"); + assertThat(section.getAttributes(0).getLongValue()).isGreaterThan(1L); + assertThat(section.getAttributes(8).getKey()).isEqualTo("Thread Count"); + assertThat(section.getAttributes(8).getLongValue()).isGreaterThan(1L); + } + + @Test + public void should_hide_attributes_without_values() { + MemoryMXBean memoryBean = mock(MemoryMXBean.class, Mockito.RETURNS_DEEP_STUBS); + when(memoryBean.getHeapMemoryUsage().getCommitted()).thenReturn(-1L); + + ProcessStateSystemInfo underTest = new ProcessStateSystemInfo(PROCESS_NAME); + ProtobufSystemInfo.Section section = underTest.toProtobuf(memoryBean); + + assertThat(section.getAttributesList()).extracting("key").doesNotContain("Heap Committed (MB)"); + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java new file mode 100644 index 00000000000..31f7f48f08f --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.systeminfo; + +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import java.io.IOException; +import java.net.ConnectException; +import java.util.Arrays; +import java.util.Properties; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; + +public class SystemInfoHttpServerTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + SystemInfoSection stateProvider1 = new ProcessStateSystemInfo("state1"); + SystemInfoSection stateProvider2 = new ProcessStateSystemInfo("state2"); + SystemInfoHttpServer underTest; + + @Before + public void setUp() throws Exception { + Properties properties = new Properties(); + properties.setProperty(PROPERTY_PROCESS_INDEX, "1"); + properties.setProperty(PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath()); + underTest = new SystemInfoHttpServer(properties, Arrays.asList(stateProvider1, stateProvider2)); + } + + @After + public void tearDown() { + underTest.stop(); + } + + @Test + public void start_starts_http_server_and_publishes_URL_in_IPC() throws Exception { + underTest.start(); + Response response = call(underTest.getUrl()); + assertThat(response.code()).isEqualTo(200); + ProtobufSystemInfo.SystemInfo systemInfo = ProtobufSystemInfo.SystemInfo.parseFrom(response.body().bytes()); + assertThat(systemInfo.getSectionsCount()).isEqualTo(2); + assertThat(systemInfo.getSections(0).getName()).isEqualTo("state1"); + assertThat(systemInfo.getSections(1).getName()).isEqualTo("state2"); + } + + @Test + public void stop_stops_http_server() throws Exception { + underTest.start(); + underTest.stop(); + expectedException.expect(ConnectException.class); + call(underTest.getUrl()); + } + + private static Response call(String url) throws IOException { + Request request = new Request.Builder().get().url(url).build(); + return new OkHttpClient().newCall(request).execute(); + } +} |