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
*/
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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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<Runnable> buildShuffleCallsToUnderTest() {
+ List<Runnable> 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
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;
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;
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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;
+++ /dev/null
-/*
- * 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.computation.monitoring;
-
-import java.util.concurrent.atomic.AtomicLong;
-import org.sonar.ce.monitoring.CEQueueStatus;
-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();
- }
-}
+++ /dev/null
-/*
- * 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.computation.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();
-}
+++ /dev/null
-/*
- * 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.computation.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();
- }
-}
+++ /dev/null
-/*
- * 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.computation.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();
-}
+++ /dev/null
-/*
- * 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.computation.monitoring;
-
-import org.picocontainer.Startable;
-import org.sonar.ce.monitoring.CEQueueStatus;
-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();
- }
-}
+++ /dev/null
-/*
- * 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.server.computation.monitoring;
-
-import javax.annotation.ParametersAreNonnullByDefault;
+++ /dev/null
-/*
- * 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 org.sonar.server.computation.monitoring.CEQueueStatusImpl;
-
-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<Runnable> buildShuffleCallsToUnderTest() {
- List<Runnable> 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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.computation.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();
-
- 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);
- }
-}
+++ /dev/null
-/*
- * 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.computation.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;
- }
- }
-}
+++ /dev/null
-/*
- * 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.computation.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.monitoring.CEQueueStatus;
-import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
-import org.sonar.ce.configuration.CeConfiguration;
-
-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;
- }
- }
-}