From e62b51e3812f640230c0d0dc191a54e8db76b949 Mon Sep 17 00:00:00 2001 From: Sébastien Lesaint Date: Fri, 31 Mar 2017 14:40:30 +0200 Subject: SONAR-9041 move computation.monitoring package to sonar-ce --- .../java/org/sonar/ce/CeConfigurationModule.java | 2 +- .../src/main/java/org/sonar/ce/CeQueueModule.java | 6 +- .../org/sonar/ce/monitoring/CEQueueStatus.java | 88 ++++++++++++ .../org/sonar/ce/monitoring/CEQueueStatusImpl.java | 91 ++++++++++++ .../org/sonar/ce/monitoring/CeDatabaseMBean.java | 43 ++++++ .../sonar/ce/monitoring/CeDatabaseMBeanImpl.java | 113 +++++++++++++++ .../java/org/sonar/ce/monitoring/CeTasksMBean.java | 55 ++++++++ .../org/sonar/ce/monitoring/CeTasksMBeanImpl.java | 92 ++++++++++++ .../java/org/sonar/ce/monitoring/package-info.java | 23 +++ .../CEQueueStatusImplConcurrentTest.java | 101 +++++++++++++ .../sonar/ce/monitoring/CEQueueStatusImplTest.java | 142 +++++++++++++++++++ .../ce/monitoring/CeDatabaseMBeanImplTest.java | 70 +++++++++ .../sonar/ce/monitoring/CeTasksMBeanImplTest.java | 156 +++++++++++++++++++++ .../sonar/ce/queue/InternalCeQueueImplTest.java | 4 +- 14 files changed, 980 insertions(+), 6 deletions(-) create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatusImpl.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBean.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBeanImpl.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/package-info.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplTest.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java (limited to 'server/sonar-ce') diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/CeConfigurationModule.java b/server/sonar-ce/src/main/java/org/sonar/ce/CeConfigurationModule.java index f89cf4efd39..cb61583ff06 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/CeConfigurationModule.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/CeConfigurationModule.java @@ -23,7 +23,7 @@ import org.sonar.ce.configuration.CeConfigurationImpl; import org.sonar.ce.log.CeLogging; import org.sonar.core.platform.Module; import org.sonar.process.systeminfo.ProcessStateSystemInfo; -import org.sonar.server.computation.monitoring.CeDatabaseMBeanImpl; +import org.sonar.ce.monitoring.CeDatabaseMBeanImpl; public class CeConfigurationModule extends Module { @Override diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java b/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java index 159e0d53687..d8f37cd5e11 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java @@ -19,11 +19,11 @@ */ package org.sonar.ce; -import org.sonar.core.platform.Module; -import org.sonar.server.computation.monitoring.CEQueueStatusImpl; -import org.sonar.server.computation.monitoring.CeTasksMBeanImpl; +import org.sonar.ce.monitoring.CEQueueStatusImpl; +import org.sonar.ce.monitoring.CeTasksMBeanImpl; import org.sonar.ce.queue.CeQueueInitializer; import org.sonar.ce.queue.InternalCeQueueImpl; +import org.sonar.core.platform.Module; public class CeQueueModule extends Module { @Override diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java new file mode 100644 index 00000000000..bc652ea9871 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java @@ -0,0 +1,88 @@ +/* + * 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.monitoring; + +public interface CEQueueStatus { + + /** + * Adds 1 to the count of batch reports under processing and removes 1 from the count of batch reports waiting for + * processing. + * + * @return the new count of batch reports under processing + * + * @see #getInProgressCount() + */ + long addInProgress(); + + /** + * Adds 1 to the count of batch reports which processing ended successfully and removes 1 from the count of batch + * reports under processing. Adds the specified time to the processing time counter. + * + * @param processingTime duration of processing in ms + * + * @return the new count of batch reports which processing ended successfully + * + * @see #getSuccessCount() + * @see #getInProgressCount() + * + * @throws IllegalArgumentException if processingTime is < 0 + */ + long addSuccess(long processingTime); + + /** + * Adds 1 to the count of batch reports which processing ended with an error and removes 1 from the count of batch + * reports under processing. Adds the specified time to the processing time counter. + * + * @param processingTime duration of processing in ms + * + * @return the new count of batch reports which processing ended with an error + * + * @see #getErrorCount() + * @see #getInProgressCount() + * + * @throws IllegalArgumentException if processingTime is < 0 + */ + long addError(long processingTime); + + /** + * 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 batch reports since startup, in milliseconds. + */ + long getProcessingTime(); +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatusImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatusImpl.java new file mode 100644 index 00000000000..305018d18da --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CEQueueStatusImpl.java @@ -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.ce.monitoring; + +import java.util.concurrent.atomic.AtomicLong; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.ce.CeQueueDto; + +import static com.google.common.base.Preconditions.checkArgument; + +public class CEQueueStatusImpl implements CEQueueStatus { + + private final DbClient dbClient; + private final AtomicLong inProgress = new AtomicLong(0); + private final AtomicLong error = new AtomicLong(0); + private final AtomicLong success = new AtomicLong(0); + private final AtomicLong processingTime = new AtomicLong(0); + + public CEQueueStatusImpl(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public long addInProgress() { + return inProgress.incrementAndGet(); + } + + @Override + public long addError(long processingTimeInMs) { + addProcessingTime(processingTimeInMs); + inProgress.decrementAndGet(); + return error.incrementAndGet(); + } + + @Override + public long addSuccess(long processingTimeInMs) { + addProcessingTime(processingTimeInMs); + inProgress.decrementAndGet(); + return success.incrementAndGet(); + } + + private void addProcessingTime(long ms) { + checkArgument(ms >= 0, "Processing time can not be < 0"); + processingTime.addAndGet(ms); + } + + @Override + public long getPendingCount() { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.ceQueueDao().countByStatus(dbSession, CeQueueDto.Status.PENDING); + } + } + + @Override + public long getInProgressCount() { + return inProgress.get(); + } + + @Override + public long getErrorCount() { + return error.get(); + } + + @Override + public long getSuccessCount() { + return success.get(); + } + + @Override + public long getProcessingTime() { + return processingTime.get(); + } +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java new file mode 100644 index 00000000000..4000e670c1b --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBean.java @@ -0,0 +1,43 @@ +/* + * 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.monitoring; + +public interface CeDatabaseMBean { + + String OBJECT_NAME = "SonarQube:name=ComputeEngineDatabaseConnection"; + + int getPoolActiveConnections(); + + int getPoolMaxActiveConnections(); + + int getPoolIdleConnections(); + + int getPoolMaxIdleConnections(); + + int getPoolMinIdleConnections(); + + int getPoolInitialSize(); + + long getPoolMaxWaitMillis(); + + boolean getPoolRemoveAbandoned(); + + int getPoolRemoveAbandonedTimeoutSeconds(); +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java new file mode 100644 index 00000000000..52aa2961051 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java @@ -0,0 +1,113 @@ +/* + * 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.monitoring; + +import org.apache.commons.dbcp.BasicDataSource; +import org.picocontainer.Startable; +import org.sonar.db.DbClient; +import org.sonar.process.Jmx; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +public class CeDatabaseMBeanImpl implements CeDatabaseMBean, Startable, SystemInfoSection { + private final DbClient dbClient; + + public CeDatabaseMBeanImpl(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public void start() { + Jmx.register(OBJECT_NAME, this); + } + + /** + * Unregister, if needed + */ + @Override + public void stop() { + Jmx.unregister(OBJECT_NAME); + } + + @Override + public int getPoolActiveConnections() { + return commonsDbcp().getNumActive(); + } + + @Override + public int getPoolMaxActiveConnections() { + return commonsDbcp().getMaxActive(); + } + + @Override + public int getPoolIdleConnections() { + return commonsDbcp().getNumIdle(); + } + + @Override + public int getPoolMaxIdleConnections() { + return commonsDbcp().getMaxIdle(); + } + + @Override + public int getPoolMinIdleConnections() { + return commonsDbcp().getMinIdle(); + } + + @Override + public int getPoolInitialSize() { + return commonsDbcp().getInitialSize(); + } + + @Override + public long getPoolMaxWaitMillis() { + return commonsDbcp().getMaxWait(); + } + + @Override + public boolean getPoolRemoveAbandoned() { + return commonsDbcp().getRemoveAbandoned(); + } + + @Override + public int getPoolRemoveAbandonedTimeoutSeconds() { + return commonsDbcp().getRemoveAbandonedTimeout(); + } + + private BasicDataSource commonsDbcp() { + return (BasicDataSource) dbClient.getDatabase().getDataSource(); + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder(); + builder.setName("Compute Engine Database Connection"); + builder.addAttributesBuilder().setKey("Pool Initial Size").setLongValue(getPoolInitialSize()).build(); + builder.addAttributesBuilder().setKey("Pool Active Connections").setLongValue(getPoolActiveConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Idle Connections").setLongValue(getPoolIdleConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Max Active Connections").setLongValue(getPoolMaxActiveConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Max Idle Connections").setLongValue(getPoolMaxIdleConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Min Idle Connections").setLongValue(getPoolMinIdleConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Max Wait (ms)").setLongValue(getPoolMaxWaitMillis()).build(); + builder.addAttributesBuilder().setKey("Pool Remove Abandoned").setBooleanValue(getPoolRemoveAbandoned()).build(); + builder.addAttributesBuilder().setKey("Pool Remove Abandoned Timeout (sec)").setLongValue(getPoolRemoveAbandonedTimeoutSeconds()).build(); + return builder.build(); + } +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBean.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBean.java new file mode 100644 index 00000000000..2e85a5d0c02 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBean.java @@ -0,0 +1,55 @@ +/* + * 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.monitoring; + +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-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBeanImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBeanImpl.java new file mode 100644 index 00000000000..9797b414f26 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBeanImpl.java @@ -0,0 +1,92 @@ +/* + * 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.monitoring; + +import org.picocontainer.Startable; +import org.sonar.process.Jmx; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; +import org.sonar.ce.configuration.CeConfiguration; + +public class CeTasksMBeanImpl implements CeTasksMBean, Startable, SystemInfoSection { + private final CEQueueStatus queueStatus; + private final CeConfiguration ceConfiguration; + + public CeTasksMBeanImpl(CEQueueStatus queueStatus, CeConfiguration ceConfiguration) { + this.queueStatus = queueStatus; + this.ceConfiguration = ceConfiguration; + } + + @Override + public void start() { + Jmx.register(OBJECT_NAME, this); + } + + /** + * Unregister, if needed + */ + @Override + public void stop() { + Jmx.unregister(OBJECT_NAME); + } + + @Override + public long getPendingCount() { + return queueStatus.getPendingCount(); + } + + @Override + public long getInProgressCount() { + return queueStatus.getInProgressCount(); + } + + @Override + public long getErrorCount() { + return queueStatus.getErrorCount(); + } + + @Override + public long getSuccessCount() { + return queueStatus.getSuccessCount(); + } + + @Override + public long getProcessingTime() { + return queueStatus.getProcessingTime(); + } + + @Override + public int getWorkerCount() { + return ceConfiguration.getWorkerCount(); + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder(); + builder.setName("Compute Engine Tasks"); + builder.addAttributesBuilder().setKey("Pending").setLongValue(getPendingCount()).build(); + builder.addAttributesBuilder().setKey("In Progress").setLongValue(getInProgressCount()).build(); + builder.addAttributesBuilder().setKey("Processed With Error").setLongValue(getErrorCount()).build(); + builder.addAttributesBuilder().setKey("Processed With Success").setLongValue(getSuccessCount()).build(); + builder.addAttributesBuilder().setKey("Processing Time (ms)").setLongValue(getProcessingTime()).build(); + builder.addAttributesBuilder().setKey("Worker Count").setLongValue(getWorkerCount()).build(); + return builder.build(); + } +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/package-info.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/package-info.java new file mode 100644 index 00000000000..029b7eeb436 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.ce.monitoring; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java new file mode 100644 index 00000000000..1c34a059861 --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java @@ -0,0 +1,101 @@ +/* + * 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.monitoring; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Test; +import org.sonar.db.DbClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class CEQueueStatusImplConcurrentTest { + private ExecutorService executorService = Executors.newFixedThreadPool(10, new ThreadFactory() { + private int cnt = 0; + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, CEQueueStatusImplConcurrentTest.class.getSimpleName() + cnt++); + } + }); + private CEQueueStatusImpl underTest = new CEQueueStatusImpl(mock(DbClient.class)); + + @After + public void tearDown() throws Exception { + executorService.shutdownNow(); + } + + @Test + public void test_concurrent_modifications_in_any_order() throws InterruptedException { + for (Runnable runnable : buildShuffleCallsToUnderTest()) { + executorService.submit(runnable); + } + + executorService.awaitTermination(1, TimeUnit.SECONDS); + + assertThat(underTest.getInProgressCount()).isEqualTo(1); + assertThat(underTest.getErrorCount()).isEqualTo(17); + assertThat(underTest.getSuccessCount()).isEqualTo(80); + assertThat(underTest.getProcessingTime()).isEqualTo(177); + } + + private List buildShuffleCallsToUnderTest() { + List res = new ArrayList<>(); + for (int i = 0; i < 98; i++) { + res.add(new AddInProgressRunnable()); + } + for (int i = 0; i < 80; i++) { + res.add(new AddSuccessRunnable()); + } + for (int i = 0; i < 17; i++) { + res.add(new AddErrorRunnable()); + } + Collections.shuffle(res); + return res; + } + + private class AddInProgressRunnable implements Runnable { + @Override + public void run() { + underTest.addInProgress(); + } + } + + private class AddErrorRunnable implements Runnable { + @Override + public void run() { + underTest.addError(1); + } + } + + private class AddSuccessRunnable implements Runnable { + @Override + public void run() { + underTest.addSuccess(2); + } + } +} diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplTest.java new file mode 100644 index 00000000000..c62195ab13b --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplTest.java @@ -0,0 +1,142 @@ +/* + * 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.monitoring; + +import java.util.Random; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.ce.CeQueueDto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class CEQueueStatusImplTest { + private static final int SOME_RANDOM_MAX = 96535; + private static final int SOME_PROCESSING_TIME = 8723; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS); + private CEQueueStatusImpl underTest = new CEQueueStatusImpl(dbClient); + + @Test + public void verify_just_created_instance_metrics() { + assertThat(underTest.getInProgressCount()).isEqualTo(0); + assertThat(underTest.getErrorCount()).isEqualTo(0); + assertThat(underTest.getSuccessCount()).isEqualTo(0); + assertThat(underTest.getProcessingTime()).isEqualTo(0); + } + + @Test + public void addInProgress_increases_InProgress() { + underTest.addInProgress(); + + assertThat(underTest.getInProgressCount()).isEqualTo(1); + assertThat(underTest.getErrorCount()).isEqualTo(0); + assertThat(underTest.getSuccessCount()).isEqualTo(0); + assertThat(underTest.getProcessingTime()).isEqualTo(0); + } + + @Test + public void addInProgress_any_number_of_call_change_by_1_per_call() { + int calls = new Random().nextInt(SOME_RANDOM_MAX); + for (int i = 0; i < calls; i++) { + underTest.addInProgress(); + } + + assertThat(underTest.getInProgressCount()).isEqualTo(calls); + assertThat(underTest.getProcessingTime()).isEqualTo(0); + } + + @Test + public void addError_throws_IAE_if_time_is_less_than_0() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Processing time can not be < 0"); + + underTest.addError(-1); + } + + @Test + public void addError_increases_Error_and_decreases_InProgress_by_1_without_check_on_InProgress() { + underTest.addError(SOME_PROCESSING_TIME); + + assertThat(underTest.getInProgressCount()).isEqualTo(-1); + assertThat(underTest.getErrorCount()).isEqualTo(1); + assertThat(underTest.getSuccessCount()).isEqualTo(0); + assertThat(underTest.getProcessingTime()).isEqualTo(SOME_PROCESSING_TIME); + } + + @Test + public void addError_any_number_of_call_change_by_1_per_call() { + int calls = new Random().nextInt(SOME_RANDOM_MAX); + for (int i = 0; i < calls; i++) { + underTest.addError(1); + } + + assertThat(underTest.getErrorCount()).isEqualTo(calls); + assertThat(underTest.getInProgressCount()).isEqualTo(-calls); + assertThat(underTest.getProcessingTime()).isEqualTo(calls); + } + + @Test + public void addSuccess_throws_IAE_if_time_is_less_than_0() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Processing time can not be < 0"); + + underTest.addSuccess(-1); + } + + @Test + public void addSuccess_increases_Error_and_decreases_InProgress_by_1_without_check_on_InProgress() { + underTest.addSuccess(SOME_PROCESSING_TIME); + + assertThat(underTest.getInProgressCount()).isEqualTo(-1); + assertThat(underTest.getErrorCount()).isEqualTo(0); + assertThat(underTest.getSuccessCount()).isEqualTo(1); + assertThat(underTest.getProcessingTime()).isEqualTo(SOME_PROCESSING_TIME); + } + + @Test + public void addSuccess_any_number_of_call_change_by_1_per_call() { + int calls = new Random().nextInt(SOME_RANDOM_MAX); + for (int i = 0; i < calls; i++) { + underTest.addSuccess(1); + } + + assertThat(underTest.getSuccessCount()).isEqualTo(calls); + assertThat(underTest.getInProgressCount()).isEqualTo(-calls); + assertThat(underTest.getProcessingTime()).isEqualTo(calls); + } + + @Test + public void count_Pending_from_database() { + when(dbClient.ceQueueDao().countByStatus(any(DbSession.class), eq(CeQueueDto.Status.PENDING))).thenReturn(42); + + assertThat(underTest.getPendingCount()).isEqualTo(42); + } +} diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java new file mode 100644 index 00000000000..60156412035 --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java @@ -0,0 +1,70 @@ +/* + * 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.monitoring; + +import java.lang.management.ManagementFactory; +import javax.annotation.CheckForNull; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CeDatabaseMBeanImplTest { + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + CeDatabaseMBeanImpl underTest = new CeDatabaseMBeanImpl(dbTester.getDbClient()); + + @Test + public void register_and_unregister() throws Exception { + assertThat(getMBean()).isNull(); + + underTest.start(); + assertThat(getMBean()).isNotNull(); + + underTest.stop(); + assertThat(getMBean()).isNull(); + } + + @Test + public void export_system_info() { + ProtobufSystemInfo.Section section = underTest.toProtobuf(); + assertThat(section.getName()).isEqualTo("Compute Engine Database Connection"); + assertThat(section.getAttributesCount()).isEqualTo(9); + assertThat(section.getAttributes(0).getKey()).isEqualTo("Pool Initial Size"); + assertThat(section.getAttributes(0).getLongValue()).isGreaterThanOrEqualTo(0); + } + + @CheckForNull + private ObjectInstance getMBean() throws Exception { + try { + return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeDatabaseMBean.OBJECT_NAME)); + } catch (InstanceNotFoundException e) { + return null; + } + } +} diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java new file mode 100644 index 00000000000..1ec6f932115 --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java @@ -0,0 +1,156 @@ +/* + * 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.monitoring; + +import java.lang.management.ManagementFactory; +import javax.annotation.CheckForNull; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import org.junit.Test; +import org.sonar.ce.configuration.CeConfiguration; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CeTasksMBeanImplTest { + private static final long PENDING_COUNT = 2; + private static final long IN_PROGRESS_COUNT = 5; + private static final long ERROR_COUNT = 10; + private static final long SUCCESS_COUNT = 13; + private static final long PROCESSING_TIME = 987; + private static final int WORKER_COUNT = 56; + + private CeTasksMBeanImpl underTest = new CeTasksMBeanImpl(new DumbCEQueueStatus(), new DumbCeConfiguration()); + + @Test + public void register_and_unregister() throws Exception { + assertThat(getMBean()).isNull(); + + underTest.start(); + assertThat(getMBean()).isNotNull(); + + underTest.stop(); + assertThat(getMBean()).isNull(); + } + + @Test + public void get_methods_delegate_to_the_CEQueueStatus_instance() { + assertThat(underTest.getPendingCount()).isEqualTo(PENDING_COUNT); + assertThat(underTest.getInProgressCount()).isEqualTo(IN_PROGRESS_COUNT); + assertThat(underTest.getErrorCount()).isEqualTo(ERROR_COUNT); + assertThat(underTest.getSuccessCount()).isEqualTo(SUCCESS_COUNT); + assertThat(underTest.getProcessingTime()).isEqualTo(PROCESSING_TIME); + } + + @Test + public void getWorkerCount_delegates_to_the_CEConfiguration_instance() { + assertThat(underTest.getWorkerCount()).isEqualTo(WORKER_COUNT); + } + + @Test + public void export_system_info() { + ProtobufSystemInfo.Section section = underTest.toProtobuf(); + assertThat(section.getName()).isEqualTo("Compute Engine Tasks"); + assertThat(section.getAttributesCount()).isEqualTo(6); + } + + /** + * Dumb implementation of CEQueueStatus which returns constant values for get methods and throws UnsupportedOperationException + * for other methods. + */ + private static class DumbCEQueueStatus implements CEQueueStatus { + + @Override + public long getPendingCount() { + return PENDING_COUNT; + } + + @Override + public long addInProgress() { + return methodNotImplemented(); + } + + @Override + public long getInProgressCount() { + return IN_PROGRESS_COUNT; + } + + @Override + public long addError(long processingTime) { + return methodNotImplemented(); + } + + @Override + public long getErrorCount() { + return ERROR_COUNT; + } + + @Override + public long addSuccess(long processingTime) { + return methodNotImplemented(); + } + + @Override + public long getSuccessCount() { + return SUCCESS_COUNT; + } + + @Override + public long getProcessingTime() { + return PROCESSING_TIME; + } + + private long methodNotImplemented() { + throw new UnsupportedOperationException("Not Implemented"); + } + } + + private static class DumbCeConfiguration implements CeConfiguration { + @Override + public int getWorkerCount() { + return WORKER_COUNT; + } + + @Override + public long getQueuePollingDelay() { + throw new UnsupportedOperationException("getQueuePollingDelay is not implemented"); + } + + @Override + public long getCancelWornOutsInitialDelay() { + throw new UnsupportedOperationException("getCancelWornOutsInitialDelay is not implemented"); + } + + @Override + public long getCancelWornOutsDelay() { + throw new UnsupportedOperationException("getCancelWornOutsDelay is not implemented"); + } + } + + @CheckForNull + private ObjectInstance getMBean() throws Exception { + try { + return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeTasksMBean.OBJECT_NAME)); + } catch (InstanceNotFoundException e) { + return null; + } + } +} diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java index c5a537880b0..2bf444730cb 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java @@ -33,6 +33,7 @@ import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; import org.sonar.api.utils.internal.TestSystem2; import org.sonar.ce.monitoring.CEQueueStatus; +import org.sonar.ce.monitoring.CEQueueStatusImpl; import org.sonar.core.util.UuidFactory; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DbSession; @@ -43,13 +44,12 @@ import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.computation.monitoring.CEQueueStatusImpl; import org.sonar.server.organization.DefaultOrganization; import org.sonar.server.organization.DefaultOrganizationProvider; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.startsWith; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -- cgit v1.2.3